diff options
Diffstat (limited to 'sys/contrib/ngatm/netnatm')
61 files changed, 43486 insertions, 0 deletions
diff --git a/sys/contrib/ngatm/netnatm/addr.h b/sys/contrib/ngatm/netnatm/addr.h new file mode 100644 index 000000000000..c1ba20eb1c3d --- /dev/null +++ b/sys/contrib/ngatm/netnatm/addr.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/addr.h,v 1.3 2004/07/08 08:21:45 brandt Exp $ + */ +#ifndef _NETNATM_ADDR_H_ +#define _NETNATM_ADDR_H_ + +int uni_str2nsap(u_char *, const char *); +void uni_nsap2str(char *, const u_char *, int); + +void uni_prefix2str(char *, const u_char *, u_int, int); + +int uni_e1642nsap(u_char *, const char *); +int uni_nsap2e164(char *, const u_char *, int); + +#endif diff --git a/sys/contrib/ngatm/netnatm/api/atmapi.h b/sys/contrib/ngatm/netnatm/api/atmapi.h new file mode 100644 index 000000000000..887f548598ed --- /dev/null +++ b/sys/contrib/ngatm/netnatm/api/atmapi.h @@ -0,0 +1,291 @@ +/* + * 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 AUTHORS + * 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 AUTHORS 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/atmapi.h,v 1.1 2004/07/08 08:21:48 brandt Exp $ + * + * ATM API as defined per af-saa-0108 + */ +#ifndef _NETNATM_API_ATMAPI_H_ +#define _NETNATM_API_ATMAPI_H_ + +#include <sys/types.h> + +/* size of an endpointlen including trailing \0 */ +#define ATM_EPNAMSIZ 65 + +enum atmstate { + ATM_A0, /* non existent */ + ATM_A1, /* initial */ + ATM_A2, /* outgoing call preparation */ + ATM_A3, /* outgoing call requested */ + ATM_A4, /* incoming call preparation */ + ATM_A5, /* wait incoming call */ + ATM_A6, /* incoming call present */ + ATM_A7, /* incoming call requested */ + ATM_A8, /* p2p data transfer */ + ATM_A9, /* p2mp root data transfer */ + ATM_A10, /* p2mp leaf data transfer */ + ATM_A11, /* terminated */ +}; + +enum atmop { + ATMOP_RESP, /* 0 */ + ATMOP_ABORT_CONNECTION, + ATMOP_ACCEPT_INCOMING_CALL, + ATMOP_ADD_PARTY, + ATMOP_ADD_PARTY_REJECT, + ATMOP_ADD_PARTY_SUCCESS, /* 5 */ + ATMOP_ARRIVAL_OF_INCOMING_CALL, + ATMOP_CALL_RELEASE, + ATMOP_CONNECT_OUTGOING_CALL, + ATMOP_DROP_PARTY, + ATMOP_GET_LOCAL_PORT_INFO, /* 10 */ + ATMOP_P2MP_CALL_ACTIVE, + ATMOP_P2P_CALL_ACTIVE, + ATMOP_PREPARE_INCOMING_CALL, + ATMOP_PREPARE_OUTGOING_CALL, + ATMOP_QUERY_CONNECTION_ATTRIBUTES, /* 15 */ + ATMOP_REJECT_INCOMING_CALL, + ATMOP_SET_CONNECTION_ATTRIBUTES, + ATMOP_WAIT_ON_INCOMING_CALL, + ATMOP_SET_CONNECTION_ATTRIBUTES_X, + ATMOP_QUERY_CONNECTION_ATTRIBUTES_X, /* 20 */ + ATMOP_QUERY_STATE, +}; + +#define ATM_DEFINE_ERRORS \ + DEF(ATMERR_OK, 0, "OK") \ + DEF(ATMERR_SYS, -1, "syscall error") \ + DEF(ATMERR_BAD_OP, -2, "bad operation") \ + DEF(ATMERR_BAD_ARGS, -3, "bad arguments for operation") \ + DEF(ATMERR_BAD_STATE, -4, "operation in bad state") \ + DEF(ATMERR_BAD_ATTR, -5, "unknown attribute") \ + DEF(ATMERR_BAD_VALUE, -6, "bad attribute value") \ + DEF(ATMERR_BUSY, -7, "busy") \ + DEF(ATMERR_RDONLY, -8, "read-only attribute") \ + DEF(ATMERR_BAD_SAP, -9, "bad SAP") \ + DEF(ATMERR_OVERLAP, -10,"overlaping SAP") \ + DEF(ATMERR_BAD_ENDPOINT, -11,"bad ATM endpoint") \ + DEF(ATMERR_PREVIOUSLY_ABORTED,-12,"previously aborted") \ + DEF(ATMERR_NO_CALL, -13,"no incoming call") \ + DEF(ATMERR_BAD_LEAF_IDENT, -14,"bad leaf identifier") \ + DEF(ATMERR_BAD_PORT, -15,"unknown port") \ + DEF(ATMERR_BAD_SIGNAL, -29-UNIAPI_ERROR_BAD_SIGNAL, "bad signal")\ + DEF(ATMERR_BADCU, -29-UNIAPI_ERROR_BADCU, "bad coordinator state")\ + DEF(ATMERR_BAD_CALLSTATE, -29-UNIAPI_ERROR_BAD_CALLSTATE, "bad call state")\ + DEF(ATMERR_BAD_EPSTATE, -29-UNIAPI_ERROR_BAD_EPSTATE, "bad party state")\ + DEF(ATMERR_BAD_UNIARG, -29-UNIAPI_ERROR_BAD_ARG, "bad uni argument")\ + DEF(ATMERR_BAD_CALL, -29-UNIAPI_ERROR_BAD_CALL, "unknown call")\ + DEF(ATMERR_BAD_PARTY, -29-UNIAPI_ERROR_BAD_PARTY, "unknown party")\ + DEF(ATMERR_BAD_CTYPE, -29-UNIAPI_ERROR_BAD_CTYPE, "wrong call type")\ + DEF(ATMERR_BAD_IE, -29-UNIAPI_ERROR_BAD_IE, "bad information element")\ + DEF(ATMERR_EPREF_INUSE, -29-UNIAPI_ERROR_EPREF_INUSE, "endpoint reference in use")\ + DEF(ATMERR_MISSING_IE, -29-UNIAPI_ERROR_MISSING_IE, "missing information element")\ + DEF(ATMERR_ENCODING, -29-UNIAPI_ERROR_ENCODING, "encoding error")\ + DEF(ATMERR_NOMEM, -29-UNIAPI_ERROR_NOMEM, "no memory")\ + DEF(ATMERR_UNIBUSY, -29-UNIAPI_ERROR_BUSY, "uni process busy") + +#define ATM_MKUNIERR(E) (-29 - (E)) + +enum atm_error { +#define DEF(NAME,VAL,STR) NAME = (VAL), +ATM_DEFINE_ERRORS +#undef DEF +}; + +enum atm_attribute { + ATM_ATTR_NONE = 0, + ATM_ATTR_BLLI_SELECTOR, + ATM_ATTR_BLLI, + ATM_ATTR_BEARER, + ATM_ATTR_TRAFFIC, + ATM_ATTR_QOS, + ATM_ATTR_EXQOS, + ATM_ATTR_CALLED, + ATM_ATTR_CALLEDSUB, + ATM_ATTR_CALLING, + ATM_ATTR_CALLINGSUB, + ATM_ATTR_AAL, + ATM_ATTR_EPREF, + ATM_ATTR_CONNED, + ATM_ATTR_CONNEDSUB, + ATM_ATTR_EETD, + ATM_ATTR_ABRSETUP, + ATM_ATTR_ABRADD, + ATM_ATTR_CONNID, + ATM_ATTR_MDCR, +}; + +struct atm_resp { + int32_t resp; + uint32_t data; /* type of attached data */ +}; +enum { + ATMRESP_NONE, /* no data */ + ATMRESP_ATTRS, /* attribute(s) */ + ATMRESP_PORTS, /* port info */ + ATMRESP_STATE, /* endpoint state */ + ATMRESP_EXSTAT, /* extended status */ +}; + +struct atm_abort_connection { + struct uni_ie_cause cause; +}; + +struct atm_query_connection_attributes { + uint32_t attr; +}; +struct atm_set_connection_attributes { + uint32_t attr; +}; +struct atm_query_connection_attributes_x { + uint32_t count; +#if defined(__GNUC__) && __GNUC__ < 3 + uint32_t attr[0]; +#else + uint32_t attr[]; +#endif +}; +struct atm_set_connection_attributes_x { + uint32_t count; +#if defined(__GNUC__) && __GNUC__ < 3 + uint32_t attr[0]; +#else + uint32_t attr[]; +#endif +}; +struct atm_prepare_incoming_call { + struct uni_sap sap; + uint32_t queue_size; +}; +struct atm_connect_outgoing_call { + struct uni_ie_called called; +}; +struct atm_call_release { + struct uni_ie_cause cause[2]; +}; +struct atm_p2p_call_active { + struct uni_ie_connid connid; +}; +struct atm_p2mp_call_active { + struct uni_ie_connid connid; +}; +struct atm_accept_incoming_call { + char newep[ATM_EPNAMSIZ]; +}; +struct atm_reject_incoming_call { + struct uni_ie_cause cause; +}; +struct atm_add_party { + uint16_t leaf_ident; + struct uni_ie_called called; +}; +struct atm_add_party_success { + uint16_t leaf_ident; +}; +struct atm_add_party_reject { + uint16_t leaf_ident; + struct uni_ie_cause cause; +}; +struct atm_drop_party { + uint16_t leaf_ident; + struct uni_ie_cause cause; +}; + +/* + * Get local port info. If port is 0, information on all ports is returned, + * otherwise only on the named port. + * The response consists of a header with two counters, a list of ports + * (struct atm_port_info) and a list of addresses (struct uni_addr). + * The port to which an address belongs is implicit in the num_addrs field + * of the port. + */ +struct atm_get_local_port_info { + uint32_t port; +}; + +struct atm_port_list { + uint32_t num_ports; /* number of ports */ + uint32_t num_addrs; /* total number of addresses */ +}; + +struct atm_port_info { + uint32_t port; + uint32_t pcr; + uint32_t max_vpi_bits; + uint32_t max_vci_bits; + uint32_t max_svpc_vpi; + uint32_t max_svcc_vpi; + uint32_t min_svcc_vci; + u_char esi[6]; + uint32_t num_addrs; /* number of addresses on this port */ +}; + +/* + * Endpoint state info + */ +struct atm_epstate { + char name[ATM_EPNAMSIZ]; + uint8_t state; +}; + +/* + * Extended status information. + */ +struct atm_exstatus { + uint32_t neps; /* endpoints */ + uint32_t nports; /* ports */ + uint32_t nconns; /* connections */ + uint32_t nparties; /* number of parties */ +}; +struct atm_exstatus_ep { + char name[ATM_EPNAMSIZ]; + uint8_t state; /* Ux */ +}; +struct atm_exstatus_port { + uint32_t portno; + uint8_t state; +}; +struct atm_exstatus_conn { + uint32_t id; + uint32_t cref; /* (flag << 23) | cref */ + uint32_t port; + char ep[ATM_EPNAMSIZ]; /* \0 - none */ + uint8_t state; /* Cx */ +}; +struct atm_exstatus_party { + uint32_t connid; + uint16_t epref; + uint8_t state; /* Px */ +}; +#endif diff --git a/sys/contrib/ngatm/netnatm/api/cc_conn.c b/sys/contrib/ngatm/netnatm/api/cc_conn.c new file mode 100644 index 000000000000..3350e2cb3806 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/api/cc_conn.c @@ -0,0 +1,2096 @@ +/* + * Copyright (c) 2003-2007 + * 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. + * + * $Id: cc_conn.c 1291 2007-07-10 10:35:38Z brandt_h $ + * + * ATM API as defined per af-saa-0108 + * + * Lower half - connection handling + */ +#include <netnatm/unimsg.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.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> + +static const char *stab[] = { +#define DEF(N) [N] = #N, + CONN_STATES +#undef DEF +}; + +static const char *ptab[] = { +#define DEF(N) [PARTY_##N] = #N, + PARTY_STATES +#undef DEF +}; + +const char * +cc_conn_state2str(u_int s) +{ + if (s >= sizeof(stab) / sizeof(stab[0]) || stab[s] == NULL) + return ("?"); + return (stab[s]); +} + +void +cc_conn_set_state(struct ccconn *conn, enum conn_state ns) +{ + if (conn->state != ns) { + if (conn->cc->log & CCLOG_CONN_STATE) + cc_conn_log(conn, "%s -> %s", + stab[conn->state], stab[ns]); + conn->state = ns; + } +} + +const char * +cc_party_state2str(u_int s) +{ + if (s >= sizeof(ptab) / sizeof(ptab[0]) || ptab[s] == NULL) + return ("?"); + return (ptab[s]); +} + +void +cc_party_set_state(struct ccparty *party, enum party_state ns) +{ + + if (party->state != ns) { + if (party->conn->cc->log & CCLOG_PARTY_STATE) + cc_party_log(party, "%s -> %s", + ptab[party->state], ptab[ns]); + party->state = ns; + } +} + +/* + * Remove connection from its user's queue + */ +void +cc_disconnect_from_user(struct ccconn *conn) +{ + + if (conn->user == NULL) + cc_conn_log(conn, "no %s", "user"); + else { + TAILQ_REMOVE(&conn->user->connq, conn, connq_link); + conn->user->queue_act--; + conn->user = NULL; + } +} + +/* + * Put connection on user queue + */ +void +cc_connect_to_user(struct ccconn *conn, struct ccuser *user) +{ + + if (conn->user != NULL) + cc_conn_log(conn, "still connected to %p", conn->user); + conn->user = user; + TAILQ_INSERT_TAIL(&user->connq, conn, connq_link); + conn->user->queue_act++; +} + +/* + * Send a signal to the UNI stack for this connection + */ +static void +cc_send_uni(struct ccconn *conn, u_int op, struct uni_msg *msg) +{ + struct ccreq *r; + + r = CCZALLOC(sizeof(*r)); + if (r == NULL) { + if (msg != NULL) + uni_msg_destroy(msg); + cc_conn_log(conn, "no memory for cookie op=%u", op); + return; + } + + if ((r->cookie = ++conn->port->cc->cookie) == 0) + r->cookie = ++conn->port->cc->cookie; + r->req = op; + r->conn = conn; + + TAILQ_INSERT_TAIL(&conn->port->cookies, r, link); + + conn->port->cc->funcs->send_uni(conn, conn->port->uarg, op, + r->cookie, msg); +} + +/* + * Send a RELEASE.request for this connection. + */ +static void +do_release_request(struct ccconn *conn, const struct uni_ie_cause cause[2]) +{ + struct uni_msg *u; + struct uniapi_release_request *req; + + if ((u = uni_msg_alloc(sizeof(*req))) == NULL) + return; + req = uni_msg_wptr(u, struct uniapi_release_request *); + memset(req, 0, sizeof(*req)); + u->b_wptr += sizeof(struct uniapi_release_request); + + req->release.hdr.cref = conn->cref; + req->release.hdr.act = UNI_MSGACT_DEFAULT; + + if (cause == NULL) { + IE_SETPRESENT(req->release.cause[0]); + req->release.cause[0].h.act = UNI_IEACT_DEFAULT; + req->release.cause[0].loc = UNI_CAUSE_LOC_USER; + req->release.cause[0].cause = UNI_CAUSE_UNSPEC; + } else { + req->release.cause[0] = cause[0]; + req->release.cause[1] = cause[1]; + } + + cc_send_uni(conn, UNIAPI_RELEASE_request, u); +} + +/* + * Make a RELEASE.response for this connection + */ +static void +do_release_response(struct ccconn *conn, uint8_t cause, struct uni_ie_cause *ie) +{ + struct uni_msg *u; + struct uniapi_release_response *resp; + + if ((u = uni_msg_alloc(sizeof(*resp))) == NULL) + return; + resp = uni_msg_wptr(u, struct uniapi_release_response *); + memset(resp, 0, sizeof(*resp)); + u->b_wptr += sizeof(struct uniapi_release_response); + + resp->release_compl.hdr.cref = conn->cref; + resp->release_compl.hdr.act = UNI_MSGACT_DEFAULT; + + if (ie != NULL) + resp->release_compl.cause[0] = *ie; + + if (cause != 0) { + IE_SETPRESENT(resp->release_compl.cause[0]); + resp->release_compl.cause[0].h.act = UNI_IEACT_DEFAULT; + resp->release_compl.cause[0].loc = UNI_CAUSE_LOC_USER; + resp->release_compl.cause[0].cause = cause; + } + + cc_send_uni(conn, UNIAPI_RELEASE_response, u); +} + +/********************************************************************** + * + * INSTANCE handling + */ +struct ccconn * +cc_conn_create(struct ccdata *cc) +{ + struct ccconn *conn; + + conn = CCZALLOC(sizeof(*conn)); + if (conn == NULL) + return (NULL); + + conn->state = CONN_NULL; + conn->port = NULL; + conn->cc = cc; + LIST_INIT(&conn->parties); + + LIST_INSERT_HEAD(&cc->orphaned_conns, conn, port_link); + + if (conn->cc->log & CCLOG_CONN_INST) + cc_conn_log(conn, "created %s", "orphaned"); + + return (conn); +} + +/* + * assign to port + */ +void +cc_conn_ins_port(struct ccconn *conn, struct ccport *port) +{ + + if (conn->port != NULL) { + cc_conn_log(conn, "conn is already on port %u", + conn->port->param.port); + cc_conn_rem_port(conn); + } + LIST_REMOVE(conn, port_link); + + conn->port = port; + LIST_INSERT_HEAD(&port->conn_list, conn, port_link); + +} + +/* + * remove from port + */ +void +cc_conn_rem_port(struct ccconn *conn) +{ + + if (conn->port == NULL) { + cc_conn_log(conn, "conn not on any %s", "port"); + return; + } + LIST_REMOVE(conn, port_link); + conn->port = NULL; + LIST_INSERT_HEAD(&conn->cc->orphaned_conns, conn, port_link); +} + +static void +cc_conn_flush_cookies(struct ccconn *conn) +{ + struct ccreq *r, *r1; + + if (conn->port == NULL) + return; + TAILQ_FOREACH_SAFE(r, &conn->port->cookies, link, r1) { + if (r->conn == conn) { + TAILQ_REMOVE(&conn->port->cookies, r, link); + CCFREE(r); + } + } +} + +void +cc_conn_reset_acceptor(struct ccconn *conn) +{ + if (conn->acceptor != NULL) { + conn->acceptor->accepted = NULL; + conn->acceptor = NULL; + } +} + +/* + * Destroy a connection + */ +void +cc_conn_destroy(struct ccconn *conn) +{ + struct ccparty *p; + + if (conn->cc->log & CCLOG_CONN_INST) + cc_conn_log(conn, "destroy%s", ""); + + if (conn->user != NULL) { + cc_conn_log(conn, "still connected to user %p\n", conn->user); + conn->user->queue_act--; + TAILQ_REMOVE(&conn->user->connq, conn, connq_link); + } + + if (conn->acceptor != NULL) + conn->acceptor->accepted = NULL; + + cc_conn_flush_cookies(conn); + cc_conn_sig_flush(conn); + + LIST_REMOVE(conn, port_link); + while ((p = LIST_FIRST(&conn->parties)) != NULL) { + LIST_REMOVE(p, link); + CCFREE(p); + } + + CCFREE(conn); +} + +struct ccparty * +cc_party_create(struct ccconn *conn, u_int ident, u_int flag) +{ + struct ccparty *party; + + party = CCZALLOC(sizeof(*party)); + if (party == NULL) + return (NULL); + + party->conn = conn; + party->state = PARTY_NULL; + IE_SETPRESENT(party->epref); + party->epref.flag = flag; + party->epref.epref = ident; + LIST_INSERT_HEAD(&conn->parties, party, link); + + if (party->conn->cc->log & CCLOG_PARTY_INST) + cc_party_log(party, "created %u.%u", flag, ident); + + return (party); +} + +static void +cc_party_destroy(struct ccparty *party) +{ + + if (party->conn->cc->log & CCLOG_PARTY_INST) + cc_party_log(party, "destroyed %u.%u", party->epref.flag, + party->epref.epref); + + LIST_REMOVE(party, link); + CCFREE(party); +} + +static struct ccparty * +cc_party_find(struct ccconn *conn, u_int ident) +{ + struct ccparty *party; + + LIST_FOREACH(party, &conn->parties, link) + if (party->epref.epref == ident) + return (party); + return (NULL); +} +/* + * Abort connection from down stream (because of the UNI hook beeing + * disconnected). This is called from two places: + * 1) the shutdown code. + * In this case the connections should be already dissociated from + * users and be only in states waiting for the UNI stack. + * 2) from the disconnect code. + */ +void +cc_conn_abort(struct ccconn *conn, int shutdown) +{ + struct ccuser *u = conn->user; + struct ccparty *p, *p1; + + if (shutdown) { + CCASSERT(u == NULL, ("still in use")); + CCASSERT(conn->acceptor == NULL, ("still in use")); + cc_conn_destroy(conn); + return; + } + + /* + * Look whether any parties are blocked waiting for a response + * from the stack. We don't use extra party states to handle + * user aborts, so check that there is a user before using it. + */ + if (u == NULL) { + while ((p = LIST_FIRST(&conn->parties)) != NULL) + cc_party_destroy(p); + } else { + LIST_FOREACH_SAFE(p, &conn->parties, link, p1) { + switch (p->state) { + + case PARTY_NULL: /* P0 */ + /* should not happen */ + goto dpty; + + case PARTY_ACTIVE: /* P1 */ + /* don't send a drop - user'll get a rel */ + goto dpty; + + case PARTY_ADD_WAIT_CREATE: /* P2 */ + case PARTY_ADD_WAIT_OK: /* P3 */ + /* we're adding - synthesise an error */ + cc_user_sig(u, USER_SIG_ADD_PARTY_ERR, + NULL, ATMERR_BAD_PORT); + goto dpty; + + case PARTY_ADD_WAIT_ACK: /* P4 */ + /* don't send a drop - user'll get a rel */ + goto dpty; + + case PARTY_DROP_WAIT_OK: /* P5 */ + case PARTY_DROP_WAIT_ACK: /* P6 */ + case PARTY_ADD_DROP_WAIT_OK: /* P11 */ + /* we're dropping - synthesis an ok */ + cc_user_sig(u, USER_SIG_DROP_PARTY_OK, + NULL, p->epref.epref); + goto dpty; + + case PARTY_WAIT_DESTROY: /* P7 */ + goto dpty; + + case PARTY_WAIT_SETUP_COMPL: /* P8 */ + case PARTY_WAIT_SETUP_CONF: /* P10 */ + /* first party - nothing to do */ + goto dpty; + + case PARTY_WAIT_DROP_ACK_OK: /* P9 */ + case PARTY_ADD_DROPACK_WAIT_OK:/* P12 */ + /* we're dropping - nothing to do */ + goto dpty; + } + cc_party_log(p, "bad uabort for party in state %s", + ptab[p->state]); + dpty: + cc_party_destroy(p); + } + } + + /* + * Now do what the connection needs + */ + switch (conn->state) { + + case CONN_NULL: /* 0 */ + case CONN_OUT_PREPARING: /* 1 */ + /* may not happen because we're not associated with + * aport yet */ + break; + + case CONN_OUT_WAIT_CREATE: /* 2 */ + case CONN_OUT_WAIT_OK: /* 3 */ + case CONN_OUT_WAIT_DESTROY: /* 37 */ + /* return an error to the user, go back to C1/U1 + * reset cref (for C37, C3) and cookie */ + conn->cref.flag = 0; + conn->cref.cref = 0; + cc_conn_flush_cookies(conn); + cc_conn_set_state(conn, CONN_OUT_PREPARING); + cc_conn_rem_port(conn); + cc_user_sig(u, USER_SIG_CONNECT_OUTGOING_ERR, + NULL, ATMERR_BAD_PORT); + return; + + case CONN_OUT_WAIT_CONF: /* 4 */ + case CONN_ACTIVE: /* 5 */ + case CONN_IN_WAIT_COMPL: /* 13 */ + /* emulate a RELEASE.confirm */ + memset(&u->cause, 0, sizeof(u->cause)); + cc_user_sig(u, USER_SIG_RELEASE_CONFIRM, NULL, 0); + cc_disconnect_from_user(conn); + cc_conn_destroy(conn); + return; + + case CONN_IN_PREPARING: /* 10 */ + case CONN_AB_WAIT_REQ_OK: /* 33 */ + case CONN_AB_WAIT_RESP_OK: /* 34 */ + case CONN_AB_FLUSH_IND: /* 35 */ + /* no user - destroy */ + cc_conn_destroy(conn); + return; + + case CONN_IN_ARRIVED: /* 11 */ + u->aborted = 1; + cc_disconnect_from_user(conn); + cc_conn_destroy(conn); + return; + + case CONN_IN_WAIT_ACCEPT_OK: /* 12 */ + /* return ACCEPT error */ + cc_disconnect_from_user(conn); + cc_conn_reset_acceptor(conn); + cc_user_sig(u, USER_SIG_ACCEPT_ERR, + u, ATMERR_PREVIOUSLY_ABORTED); + cc_conn_destroy(conn); + return; + + case CONN_REJ_WAIT_OK: /* 14 */ + /* return REJECT ok */ + cc_disconnect_from_user(conn); + cc_conn_destroy(conn); + cc_user_sig(u, USER_SIG_REJECT_OK, NULL, 0); + return; + + case CONN_REL_IN_WAIT_OK: /* 15 */ + case CONN_REL_WAIT_OK: /* 20 */ + /* confirm destroy */ + if (u != NULL) { + /* connection not aborted */ + memset(&u->cause, 0, sizeof(u->cause)); + cc_user_sig(u, USER_SIG_RELEASE_CONFIRM, NULL, 0); + cc_disconnect_from_user(conn); + } + cc_conn_destroy(conn); + return; + + case CONN_IN_WAITING: /* 21 */ + /* user has not seen the connection - destroy */ + cc_disconnect_from_user(conn); + cc_conn_destroy(conn); + return; + } + cc_conn_log(conn, "bad state %s", stab[conn->state]); +} + +#ifdef DEBUG_MATCH +static void +print_sap(const struct uni_sap *sap) +{ + static const char *const tags[] = { + [UNISVE_ABSENT] "absent", + [UNISVE_PRESENT]"present", + [UNISVE_ANY] "any", + }; + u_int i; + + printf("addr={%s", tags[sap->addr.tag]); + if (sap->addr.tag == UNISVE_PRESENT) { + printf(",%d-%d", sap->addr.type, sap->addr.plan); + for (i = 0; i < sap->addr.len; i++) + printf("%c%02x", ",:"[i!=0], sap->addr.addr[i]); + } + printf("}\n"); + + printf("selector={%s", tags[sap->selector.tag]); + if (sap->selector.tag == UNISVE_PRESENT) + printf(",%02x", sap->selector.selector); + printf("}\n"); + + printf("blli_id2={%s", tags[sap->blli_id2.tag]); + if (sap->blli_id2.tag == UNISVE_PRESENT) + printf(",%02x,%02x", sap->blli_id2.proto, sap->blli_id2.user); + printf("}\n"); + + printf("blli_id3={%s", tags[sap->blli_id3.tag]); + if (sap->blli_id3.tag == UNISVE_PRESENT) + printf(",%02x,%02x,%02x,%06x,%04x,%d", + sap->blli_id3.proto, sap->blli_id3.user, + sap->blli_id3.ipi, sap->blli_id3.oui, + sap->blli_id3.pid, sap->blli_id3.noipi); + printf("}\n"); + + printf("bhli={%s", tags[sap->bhli.tag]); + if (sap->bhli.tag == UNISVE_PRESENT) { + printf(",%d", sap->bhli.type); + for (i = 0; i < sap->bhli.len; i++) + printf("%c%02x", ",:"[i!=0], sap->bhli.info[i]); + } + printf("}\n"); +} +#endif + +/********************************************************************* + * + * DISPATCH incoming call + */ +void +cc_conn_dispatch(struct ccconn *conn) +{ + struct ccdata *priv = conn->port->cc; + struct ccuser *user; + u_int blli_index; + +#ifdef DEBUG_MATCH + static char buf[1000]; + static struct unicx cx; + static int init = 1; + + if (init) { + uni_initcx(&cx); + init = 0; + } +#endif + + /* + * Do call dispatching according to 4.6 + */ +#ifdef DEBUG_MATCH + printf("+++++ DISPATCH++++++\n"); +#endif + for (blli_index = 0; blli_index < UNI_NUM_IE_BLLI; blli_index++) { + if (blli_index > 0 && !IE_ISGOOD(conn->blli[blli_index])) + break; +#ifdef DEBUG_MATCH + if (IE_ISPRESENT(conn->called)) { + uni_print_ie(buf, sizeof(buf), UNI_IE_CALLED, + (union uni_ieall *)&conn->called, &cx); + printf("called=%s\n", buf); + } + if (IE_ISPRESENT(conn->bhli)) { + uni_print_ie(buf, sizeof(buf), UNI_IE_BHLI, + (union uni_ieall *)&conn->bhli, &cx); + printf("bhli=%s\n", buf); + } + if (IE_ISPRESENT(conn->blli[blli_index])) { + uni_print_ie(buf, sizeof(buf), UNI_IE_BLLI, + (union uni_ieall *)&conn->blli[blli_index], &cx); + printf("%s\n", buf); + } +#endif + LIST_FOREACH(user, &priv->user_list, node_link) { + if ((user->state == USER_IN_WAITING || + user->state == USER_IN_ARRIVED || + user->state == USER_IN_WAIT_ACC || + user->state == USER_IN_WAIT_REJ) && + !unisve_is_catchall(user->sap)) { +#ifdef DEBUG_MATCH + printf("TRYING user=%p\n", user); + print_sap(user->sap); +#endif + if (unisve_match(user->sap, &conn->called, + &conn->blli[blli_index], &conn->bhli)) + goto found; + } + } + } +#ifdef DEBUG_MATCH + printf("TRYING CATCHALL\n"); +#endif + blli_index = 0; + LIST_FOREACH(user, &priv->user_list, node_link) { + if ((user->state == USER_IN_WAITING || + user->state == USER_IN_ARRIVED || + user->state == USER_IN_WAIT_ACC || + user->state == USER_IN_WAIT_REJ) && + unisve_is_catchall(user->sap)) + goto found; + } +#ifdef DEBUG_MATCH + printf("SORRY\n"); +#endif + + /* + * No application found - reject call. + */ + do_release_response(conn, UNI_CAUSE_INCOMP, NULL); + cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK); + return; + + found: +#ifdef DEBUG_MATCH + printf("MATCH\n"); +#endif + if (user->queue_max == user->queue_act) { + do_release_response(conn, UNI_CAUSE_BUSY, NULL); + cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK); + return; + } + + if (blli_index == 0 && !IE_ISGOOD(conn->blli[blli_index])) + conn->blli_selector = 0; + else + conn->blli_selector = blli_index + 1; + + cc_conn_set_state(conn, CONN_IN_WAITING); + cc_connect_to_user(conn, user); + + cc_user_sig(user, USER_SIG_SETUP_IND, NULL, 0); +} + +static void +cc_party_setup_conf(struct ccconn *conn) +{ + struct ccparty *party; + + party = cc_party_find(conn, conn->epref.epref); + if (party == NULL) { + cc_party_log(party, "no party for %s", + cc_conn_sigtab[CONN_SIG_SETUP_CONFIRM]); + return; + } + if (party->state != PARTY_WAIT_SETUP_CONF) { + cc_party_log(party, "bad state=%s for signal=%s", + ptab[party->state], cc_conn_sigtab[CONN_SIG_SETUP_CONFIRM]); + return; + } + cc_party_set_state(party, PARTY_ACTIVE); +} + +static void +cc_party_add_ack_ind(struct ccconn *conn, const struct uni_ie_epref *epref) +{ + struct ccparty *party; + + party = cc_party_find(conn, epref->epref); + if (party == NULL) { + cc_party_log(party, "no party for %s", + cc_conn_sigtab[CONN_SIG_PARTY_ADD_ACK_IND]); + } + if (party->state != PARTY_ADD_WAIT_ACK) { + cc_party_log(party, "bad state=%s for signal=%s", + ptab[party->state], + cc_conn_sigtab[CONN_SIG_PARTY_ADD_ACK_IND]); + return; + } + cc_party_set_state(party, PARTY_ACTIVE); + cc_user_sig(conn->user, USER_SIG_ADD_PARTY_ACK, + NULL, epref->epref); +} + +static void +cc_party_add_rej_ind(struct ccconn *conn, const struct uni_ie_epref *epref) +{ + struct ccparty *party; + + party = cc_party_find(conn, epref->epref); + if (party == NULL) { + cc_party_log(party, "no party for %s", + cc_conn_sigtab[CONN_SIG_PARTY_ADD_REJ_IND]); + return; + } + if (party->state != PARTY_ADD_WAIT_ACK) { + cc_party_log(party, "bad state=%s for signal=%s", + ptab[party->state], + cc_conn_sigtab[CONN_SIG_PARTY_ADD_REJ_IND]); + return; + } + cc_party_set_state(party, PARTY_WAIT_DESTROY); + cc_user_sig(conn->user, USER_SIG_ADD_PARTY_REJ, NULL, epref->epref); +} + +static void +cc_party_drop_ack_ind(struct ccconn *conn, + const struct uni_drop_party *drop) +{ + struct ccparty *party; + + party = cc_party_find(conn, drop->epref.epref); + if (party == NULL) { + cc_party_log(party, "no party for %s", + cc_conn_sigtab[CONN_SIG_DROP_PARTY_ACK_IND]); + return; + } + switch (party->state) { + + case PARTY_ACTIVE: /* P1 */ + memset(&conn->user->cause[1], 0, sizeof(conn->user->cause[1])); + conn->user->cause[0] = drop->cause; + cc_party_set_state(party, PARTY_WAIT_DESTROY); + cc_user_sig(conn->user, USER_SIG_DROP_PARTY_IND, + NULL, party->epref.epref); + break; + + case PARTY_ADD_WAIT_ACK: /* P4 */ + memset(&conn->user->cause[1], 0, sizeof(conn->user->cause[1])); + conn->user->cause[0] = drop->cause; + cc_party_set_state(party, PARTY_WAIT_DESTROY); + cc_user_sig(conn->user, USER_SIG_ADD_PARTY_REJ, + NULL, party->epref.epref); + break; + + case PARTY_DROP_WAIT_ACK: /* P6 */ + cc_party_set_state(party, PARTY_WAIT_DESTROY); + cc_user_sig(conn->user, USER_SIG_DROP_PARTY_OK, NULL, 0); + break; + + case PARTY_WAIT_SETUP_COMPL: /* P8 */ + case PARTY_WAIT_SETUP_CONF: /* P10 */ + cc_party_set_state(party, PARTY_WAIT_DESTROY); + break; + + default: + cc_party_log(party, "bad state=%s for signal=%s", + ptab[party->state], + cc_conn_sigtab[CONN_SIG_DROP_PARTY_ACK_IND]); + break; + } +} + +/* + * Handle a signal to this connection + */ +void +cc_conn_sig_handle(struct ccconn *conn, enum conn_sig sig, + void *arg, u_int iarg) +{ + struct ccparty *party; + + if (conn->cc->log & CCLOG_CONN_SIG) + cc_conn_log(conn, "signal %s in state %s", cc_conn_sigtab[sig], + stab[conn->state]); + + switch (sig) { + + case CONN_SIG_CONNECT_OUTGOING: + /* Do SETUP */ + { + struct uni_msg *u; + struct uniapi_setup_request *setup; + + if (conn->state != CONN_OUT_PREPARING) + goto bad_state; + + if (IE_ISGOOD(conn->bearer) && + conn->bearer.cfg == UNI_BEARER_MP) { + IE_SETPRESENT(conn->epref); + conn->epref.flag = 0; + conn->epref.epref = 0; + } + + /* + * Construct message to UNI. + */ + u = uni_msg_alloc(sizeof(struct uniapi_setup_request)); + if (u == NULL) { + cc_user_sig(conn->user, USER_SIG_CONNECT_OUTGOING_ERR, + NULL, ATMERR_NOMEM); + return; + } + setup = uni_msg_wptr(u, struct uniapi_setup_request *); + memset(setup, 0, sizeof(*setup)); + u->b_wptr += sizeof(struct uniapi_setup_request); + + setup->setup.hdr.act = UNI_MSGACT_DEFAULT; + memcpy(setup->setup.blli, conn->blli, sizeof(conn->blli)); + setup->setup.bearer = conn->bearer; + setup->setup.traffic = conn->traffic; + setup->setup.qos = conn->qos; + setup->setup.exqos = conn->exqos; + setup->setup.called = conn->called; + setup->setup.calledsub[0] = conn->calledsub; + setup->setup.aal = conn->aal; + setup->setup.epref = conn->epref; + setup->setup.eetd = conn->eetd; + setup->setup.abrsetup = conn->abrsetup; + setup->setup.abradd = conn->abradd; + setup->setup.calling = conn->calling; + setup->setup.callingsub[0] = conn->callingsub; + setup->setup.connid = conn->connid; + memcpy(setup->setup.tns, conn->tns, sizeof(conn->tns)); + setup->setup.atraffic = conn->atraffic; + setup->setup.mintraffic = conn->mintraffic; + setup->setup.cscope = conn->cscope; + setup->setup.bhli = conn->bhli; + setup->setup.mdcr = conn->mdcr; + + cc_conn_set_state(conn, CONN_OUT_WAIT_CREATE); + cc_send_uni(conn, UNIAPI_SETUP_request, u); + + break; + } + + + case CONN_SIG_ARRIVAL: + /* user informed of arrival of this call */ + if (conn->state != CONN_IN_WAITING) + goto bad_state; + cc_conn_set_state(conn, CONN_IN_ARRIVED); + break; + + + case CONN_SIG_RELEASE: + { + /* Release this call */ + struct uni_msg *u; + struct uniapi_release_request *req; + + if (conn->state != CONN_ACTIVE && + conn->state != CONN_IN_WAIT_COMPL) + goto bad_state; + + if ((u = uni_msg_alloc(sizeof(*req))) == NULL) + return; + + req = uni_msg_wptr(u, struct uniapi_release_request *); + memset(req, 0, sizeof(*req)); + u->b_wptr += sizeof(struct uniapi_release_request); + + req->release.hdr.cref = conn->cref; + req->release.hdr.act = UNI_MSGACT_DEFAULT; + + req->release.cause[0] = conn->cause[0]; + req->release.cause[1] = conn->cause[1]; + + if (conn->state == CONN_ACTIVE) + cc_conn_set_state(conn, CONN_REL_WAIT_OK); + else + cc_conn_set_state(conn, CONN_REL_IN_WAIT_OK); + + cc_send_uni(conn, UNIAPI_RELEASE_request, u); + break; + } + + case CONN_SIG_REJECT: + { + /* reject from user */ + struct ccuser *user = conn->user; + + if (conn->state != CONN_IN_ARRIVED) { + cc_user_sig(user, USER_SIG_REJECT_ERR, + NULL, ATMERR_BAD_STATE); + break; + } + cc_conn_set_state(conn, CONN_REJ_WAIT_OK); + do_release_response(conn, 0, conn->cause); + break; + } + + + case CONN_SIG_ACCEPT: + { + /* User accepts. */ + struct ccuser *newep = arg; + struct uni_msg *u; + struct uniapi_setup_response *resp; + struct ccuser *user = conn->user; + + if (conn->state != CONN_IN_ARRIVED) { + cc_user_sig(user, USER_SIG_ACCEPT_ERR, + NULL, ATMERR_PREVIOUSLY_ABORTED); + break; + } + + u = uni_msg_alloc(sizeof(struct uniapi_setup_response)); + if (u == NULL) { + cc_user_sig(user, USER_SIG_ACCEPT_ERR, + NULL, ATMERR_NOMEM); + return; + } + + /* + * Link to the new endpoint + */ + conn->acceptor = newep; + newep->accepted = conn; + + /* + * Construct connect message + */ + resp = uni_msg_wptr(u, struct uniapi_setup_response *); + memset(resp, 0, sizeof(*resp)); + u->b_wptr += sizeof(*resp); + + resp->connect.hdr.act = UNI_MSGACT_DEFAULT; + resp->connect.hdr.cref = conn->cref; + + /* + * attributes + */ + if (conn->dirty_attr & CCDIRTY_AAL) + resp->connect.aal = conn->aal; + if (conn->dirty_attr & CCDIRTY_BLLI) + resp->connect.blli = + conn->blli[conn->blli_selector - 1]; + if (conn->dirty_attr & CCDIRTY_CONNID) + resp->connect.connid = conn->connid; + /* XXX NOTIFY */ + if (conn->dirty_attr & CCDIRTY_EETD) + resp->connect.eetd = conn->eetd; + /* XXX GIT */ + /* XXX UU */ + if (conn->dirty_attr & CCDIRTY_TRAFFIC) + resp->connect.traffic = conn->traffic; + if (conn->dirty_attr & CCDIRTY_EXQOS) + resp->connect.exqos = conn->exqos; + if (conn->dirty_attr & CCDIRTY_ABRSETUP) + resp->connect.abrsetup = conn->abrsetup; + if (conn->dirty_attr & CCDIRTY_ABRADD) + resp->connect.abradd = conn->abradd; + + /* + * If the SETUP had an endpoint reference - echo it back + */ + if (IE_ISPRESENT(conn->epref)) { + resp->connect.epref = conn->epref; + resp->connect.epref.flag = !resp->connect.epref.flag; + } + + cc_conn_set_state(conn, CONN_IN_WAIT_ACCEPT_OK); + cc_send_uni(conn, UNIAPI_SETUP_response, u); + break; + } + + + case CONN_SIG_ADD_PARTY: + { + /* request to add party from user */ + struct uni_msg *u; + struct uniapi_add_party_request *req; + + if (conn->state != CONN_ACTIVE) + goto bad_state; + + /* create the party */ + party = cc_party_create(conn, (u_int)(uintptr_t)arg, 0); + if (party == NULL) { + cc_user_sig(conn->user, USER_SIG_ADD_PARTY_ERR, + NULL, ATMERR_NOMEM); + return; + } + party->called = conn->called; + + /* Construct message to UNI. */ + u = uni_msg_alloc(sizeof(struct uniapi_setup_request)); + if (u == NULL) { + cc_party_destroy(party); + cc_user_sig(conn->user, USER_SIG_ADD_PARTY_ERR, + NULL, ATMERR_NOMEM); + return; + } + + req = uni_msg_wptr(u, struct uniapi_add_party_request *); + memset(req, 0, sizeof(*req)); + u->b_wptr += sizeof(struct uniapi_add_party_request); + + req->add.hdr.act = UNI_MSGACT_DEFAULT; + req->add.hdr.cref = conn->cref; + req->add.epref = party->epref; + req->add.called = party->called; + + cc_party_set_state(party, PARTY_ADD_WAIT_CREATE); + cc_send_uni(conn, UNIAPI_ADD_PARTY_request, u); + break; + } + + + case CONN_SIG_DROP_PARTY: + { + /* user request to drop a party */ + struct uni_msg *u; + struct uniapi_drop_party_request *req; + + if (conn->state != CONN_ACTIVE) + goto bad_state; + + party = cc_party_find(conn, (u_int)(uintptr_t)arg); + if (party == NULL) { + cc_user_sig(conn->user, USER_SIG_DROP_PARTY_ERR, + NULL, ATMERR_BAD_PARTY); + return; + } + + switch (party->state) { + + case PARTY_ACTIVE: + case PARTY_ADD_WAIT_ACK: + break; + + default: + cc_user_sig(conn->user, USER_SIG_DROP_PARTY_ERR, + NULL, ATMERR_BAD_STATE); + return; + + } + /* + * Construct message to UNI. + */ + u = uni_msg_alloc(sizeof(*req)); + if (u == NULL) { + cc_user_sig(conn->user, USER_SIG_DROP_PARTY_ERR, + NULL, ATMERR_NOMEM); + return; + } + + req = uni_msg_wptr(u, struct uniapi_drop_party_request *); + memset(req, 0, sizeof(*req)); + u->b_wptr += sizeof(struct uniapi_drop_party_request); + + req->drop.hdr.act = UNI_MSGACT_DEFAULT; + req->drop.hdr.cref = conn->cref; + req->drop.epref = party->epref; + req->drop.cause = conn->cause[0]; + + if (party->state == PARTY_ACTIVE) + cc_party_set_state(party, PARTY_DROP_WAIT_OK); + else + cc_party_set_state(party, PARTY_ADD_DROP_WAIT_OK); + cc_send_uni(conn, UNIAPI_DROP_PARTY_request, u); + break; + } + + case CONN_SIG_DROP_PARTY_ACK_IND: + { + struct uni_msg *msg = arg; + struct uniapi_drop_party_ack_indication *ind = uni_msg_rptr(msg, + struct uniapi_drop_party_ack_indication *); + + cc_party_drop_ack_ind(conn, &ind->drop); + break; + } + + + case CONN_SIG_USER_ABORT: + /* + * Aborting a connection. This is callable in all states. + * The connection is already disconnected from the user. + * The cause is in cause[]. + */ + switch (conn->state) { + + case CONN_NULL: /* C0 */ + case CONN_OUT_PREPARING: /* C1 */ + cc_conn_destroy(conn); + break; + + case CONN_OUT_WAIT_CONF: /* C4 */ + case CONN_ACTIVE: /* C5 */ + do_release_request(conn, conn->cause); + cc_conn_set_state(conn, CONN_AB_WAIT_REQ_OK); + break; + + case CONN_IN_WAITING: /* C21 */ + /* that should not happen */ + goto bad_state; + break; + + case CONN_IN_ARRIVED: /* C11 */ + /* + * This is called only for the first connection + * of the user - the others are re-dispatched. + */ + do_release_response(conn, 0, conn->cause); + cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK); + break; + + case CONN_IN_WAIT_COMPL: /* C13 */ + do_release_request(conn, conn->cause); + cc_conn_set_state(conn, CONN_AB_WAIT_REQ_OK); + break; + + case CONN_OUT_WAIT_DESTROY: /* C20 */ + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + break; + + case CONN_IN_WAIT_ACCEPT_OK: /* C12 */ + case CONN_AB_WAIT_REQ_OK: /* C33 */ + case CONN_AB_WAIT_RESP_OK: /* C34 */ + case CONN_AB_FLUSH_IND: /* C35 */ + /* just ignore */ + break; + + /* + * The following states may not happen, because + * we're waiting for a response from the UNI stack. + * As soon as the response comes the ABORT is undefered + * and will hit us (but in another state). + */ + case CONN_OUT_WAIT_CREATE: /* C2 */ + case CONN_OUT_WAIT_OK: /* C3 */ + case CONN_IN_PREPARING: /* C10 */ + case CONN_REJ_WAIT_OK: /* C14 */ + case CONN_REL_IN_WAIT_OK: /* C15 */ + case CONN_REL_WAIT_OK: /* C20 */ + goto bad_state; + } + break; + + + case CONN_SIG_CREATED: + { + /* + * CALL_CREATED message from UNI. This can happen for either + * incoming or outgoing connections. + */ + struct uni_msg *msg = arg; + struct uniapi_call_created *cr = uni_msg_rptr(msg, + struct uniapi_call_created *); + + switch (conn->state) { + + case CONN_OUT_WAIT_CREATE: + conn->cref = cr->cref; + cc_conn_set_state(conn, CONN_OUT_WAIT_OK); + break; + + case CONN_NULL: + conn->cref = cr->cref; + cc_conn_set_state(conn, CONN_IN_PREPARING); + break; + + default: + goto bad_state; + } + break; + } + + case CONN_SIG_DESTROYED: + /* + * CALL_DESTROYED message from UNI. + */ + switch (conn->state) { + + case CONN_OUT_WAIT_DESTROY: + cc_conn_rem_port(conn); + cc_conn_set_state(conn, CONN_OUT_PREPARING); + if (conn->user != NULL) + cc_user_sig(conn->user, + USER_SIG_CONNECT_OUTGOING_ERR, + NULL, ATM_MKUNIERR(conn->reason)); + break; + + case CONN_AB_FLUSH_IND: + cc_conn_destroy(conn); + break; + + case CONN_IN_PREPARING: + cc_conn_destroy(conn); + break; + + default: + goto bad_state; + } + break; + + + case CONN_SIG_SETUP_CONFIRM: + /* Setup confirm from the UNI. */ + { + struct uni_msg *msg = arg; + struct uniapi_setup_confirm *conf = uni_msg_rptr(msg, + struct uniapi_setup_confirm *); + + switch (conn->state) { + + case CONN_OUT_WAIT_CONF: + /* + * Shuffle attributes and inform the user. + * Negotiable attributes are condititionally shuffled, + * because not returning it means accepting it + * (in case of blli the first instance of it). + * All others are shuffled unconditionally. + * Here we should also open the VCI in the driver. (XXX) + */ +#define SHUFFLE(ATTR) conn->ATTR = conf->connect.ATTR +#define COND_SHUFFLE(ATTR) if (IE_ISPRESENT(conf->connect.ATTR)) SHUFFLE(ATTR) + + COND_SHUFFLE(aal); + (void)memset(conn->blli + 1, 0, + sizeof(conn->blli) - sizeof(conn->blli[0])); + if (IE_ISPRESENT(conf->connect.blli)) + conn->blli[0] = conf->connect.blli; + conn->blli_selector = 1; + COND_SHUFFLE(epref); + SHUFFLE(conned); + SHUFFLE(connedsub); + SHUFFLE(eetd); + COND_SHUFFLE(traffic); + COND_SHUFFLE(exqos); + COND_SHUFFLE(abrsetup); + COND_SHUFFLE(abradd); + COND_SHUFFLE(connid); +#undef SHUFFLE +#undef COND_SHUFFLE + if (IE_ISGOOD(conn->epref)) + cc_party_setup_conf(conn); + + cc_conn_set_state(conn, CONN_ACTIVE); + cc_user_sig(conn->user, USER_SIG_SETUP_CONFIRM, + NULL, 0); + break; + + case CONN_AB_FLUSH_IND: + case CONN_AB_WAIT_RESP_OK: + break; + + default: + goto bad_state; + } + break; + } + + case CONN_SIG_SETUP_IND: + { + /* SETUP indication */ + struct uni_msg *msg = arg; + struct uniapi_setup_indication *ind = uni_msg_rptr(msg, + struct uniapi_setup_indication *); + u_int i; + + if (conn->state != CONN_IN_PREPARING) + goto bad_state; + + /* + * Shuffle information elements. + */ + for (i = 0; i < UNI_NUM_IE_BLLI; i++) + conn->blli[i] = ind->setup.blli[i]; + conn->bearer = ind->setup.bearer; + conn->traffic = ind->setup.traffic; + conn->qos = ind->setup.qos; + conn->exqos = ind->setup.exqos; + conn->called = ind->setup.called; + conn->calledsub = ind->setup.calledsub[0]; + conn->aal = ind->setup.aal; + conn->epref = ind->setup.epref; + conn->eetd = ind->setup.eetd; + conn->abrsetup = ind->setup.abrsetup; + conn->abradd = ind->setup.abradd; + conn->calling = ind->setup.calling; + conn->callingsub = ind->setup.callingsub[0]; + conn->connid = ind->setup.connid; + for (i = 0; i < UNI_NUM_IE_TNS; i++) + conn->tns[i] = ind->setup.tns[i]; + conn->atraffic = ind->setup.atraffic; + conn->mintraffic = ind->setup.mintraffic; + conn->cscope = ind->setup.cscope; + conn->bhli = ind->setup.bhli; + conn->mdcr = ind->setup.mdcr; + + cc_conn_dispatch(conn); + break; + } + + + case CONN_SIG_SETUP_COMPL: + { + struct uni_msg *msg = arg; + struct uniapi_setup_indication *ind __unused = + uni_msg_rptr(msg, struct uniapi_setup_indication *); + + /* SETUP_COMPLETE.indication from UNI */ + if (conn->state == CONN_AB_FLUSH_IND || + conn->state == CONN_AB_WAIT_RESP_OK) + break; + + if (conn->state != CONN_IN_WAIT_COMPL) + goto bad_state; + + cc_conn_set_state(conn, CONN_ACTIVE); + + LIST_FOREACH(party, &conn->parties, link) { + if (party->state == PARTY_WAIT_SETUP_COMPL) + cc_party_set_state(party, PARTY_ACTIVE); + else + cc_party_log(party, "bad state=%s for sig=%s", + ptab[party->state], + cc_conn_sigtab[CONN_SIG_SETUP_COMPL]); + } + + cc_user_sig(conn->user, USER_SIG_SETUP_COMPL, NULL, 0); + break; + } + + + case CONN_SIG_PROC_IND: + { + /* + * ALERTING.indication and PROCEEDING.indication are entirly + * ignored by the specification. We need to at least save the + * connid information element. + */ + struct uni_msg *msg = arg; + struct uniapi_proceeding_indication *ind = uni_msg_rptr(msg, + struct uniapi_proceeding_indication *); + + switch (conn->state) { + + case CONN_OUT_WAIT_CONF: + if (IE_ISGOOD(ind->call_proc.connid)) + conn->connid = ind->call_proc.connid; + break; + + case CONN_AB_FLUSH_IND: + case CONN_AB_WAIT_RESP_OK: + break; + + default: + goto bad_state; + } + break; + } + + case CONN_SIG_ALERTING_IND: + { + struct uni_msg *msg = arg; + struct uniapi_alerting_indication *ind = uni_msg_rptr(msg, + struct uniapi_alerting_indication *); + + switch (conn->state) { + + case CONN_OUT_WAIT_CONF: + if (IE_ISGOOD(ind->alerting.connid)) + conn->connid = ind->alerting.connid; + break; + + case CONN_AB_FLUSH_IND: + case CONN_AB_WAIT_RESP_OK: + break; + + default: + goto bad_state; + } + break; + } + + case CONN_SIG_REL_CONF: + { + /* RELEASE.confirm from UNI */ + struct uni_msg *msg = arg; + struct uniapi_release_confirm *conf = uni_msg_rptr(msg, + struct uniapi_release_confirm *); + + switch (conn->state) { + + case CONN_OUT_WAIT_CONF: + case CONN_ACTIVE: + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + memcpy(conn->user->cause, conf->release.cause, + sizeof(conn->user->cause)); + /* + * If any party is in P6, ok the user + */ + LIST_FOREACH(party, &conn->parties, link) { + if (party->state == PARTY_DROP_WAIT_ACK) { + cc_party_set_state(party, + PARTY_WAIT_DESTROY); + cc_user_sig(conn->user, + USER_SIG_DROP_PARTY_OK, + NULL, party->epref.epref); + } + } + cc_user_sig(conn->user, USER_SIG_RELEASE_CONFIRM, + NULL, 0); + cc_disconnect_from_user(conn); + break; + + case CONN_AB_FLUSH_IND: + case CONN_AB_WAIT_RESP_OK: + break; + + case CONN_IN_WAITING: + cc_disconnect_from_user(conn); + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + break; + + case CONN_IN_ARRIVED: + conn->user->aborted = 1; + memcpy(conn->user->cause, conf->release.cause, + sizeof(conn->user->cause)); + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + cc_disconnect_from_user(conn); + break; + + case CONN_IN_WAIT_COMPL: + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + memcpy(conn->user->cause, conf->release.cause, + sizeof(conn->user->cause)); + cc_user_sig(conn->user, USER_SIG_RELEASE_CONFIRM, + NULL, 0); + cc_disconnect_from_user(conn); + break; + + default: + goto bad_state; + } + break; + } + + case CONN_SIG_REL_IND: + { + /* RELEASE.ind from UNI */ + struct uni_msg *msg = arg; + struct uniapi_release_indication *conf = uni_msg_rptr(msg, + struct uniapi_release_indication *); + + switch (conn->state) { + + case CONN_OUT_WAIT_CONF: + case CONN_ACTIVE: + do_release_response(conn, 0, NULL); + cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK); + memcpy(conn->user->cause, conf->release.cause, + sizeof(conn->user->cause)); + /* + * If any party is in P6, ok the user + */ + LIST_FOREACH(party, &conn->parties, link) { + if (party->state == PARTY_DROP_WAIT_ACK) { + cc_party_set_state(party, + PARTY_WAIT_DESTROY); + cc_user_sig(conn->user, + USER_SIG_DROP_PARTY_OK, + NULL, party->epref.epref); + } + } + cc_user_sig(conn->user, USER_SIG_RELEASE_CONFIRM, + NULL, 0); + cc_disconnect_from_user(conn); + break; + + case CONN_AB_FLUSH_IND: + case CONN_AB_WAIT_RESP_OK: + break; + + case CONN_IN_WAITING: + cc_disconnect_from_user(conn); + do_release_response(conn, 0, NULL); + cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK); + break; + + case CONN_IN_ARRIVED: + conn->user->aborted = 1; + cc_disconnect_from_user(conn); + do_release_response(conn, 0, NULL); + cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK); + break; + + case CONN_IN_WAIT_COMPL: + do_release_response(conn, 0, NULL); + cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK); + memcpy(conn->user->cause, conf->release.cause, + sizeof(conn->user->cause)); + cc_user_sig(conn->user, USER_SIG_RELEASE_CONFIRM, + NULL, 0); + cc_disconnect_from_user(conn); + break; + default: + goto bad_state; + break; + } + break; + } + + case CONN_SIG_PARTY_ALERTING_IND: + /* party alerting from UNI */ + if (conn->state == CONN_AB_FLUSH_IND) + break; + if (conn->state != CONN_ACTIVE) + goto bad_state; + /* ignore */ + break; + + case CONN_SIG_PARTY_ADD_ACK_IND: + { + /* ADD PARTY ACKNOWLEDGE from UNI */ + struct uni_msg *msg = arg; + struct uniapi_add_party_ack_indication *ind = uni_msg_rptr(msg, + struct uniapi_add_party_ack_indication *); + + if (conn->state == CONN_AB_FLUSH_IND) + break; + if (conn->state != CONN_ACTIVE) + goto bad_state; + + cc_party_add_ack_ind(conn, &ind->ack.epref); + break; + } + + + case CONN_SIG_PARTY_ADD_REJ_IND: + { + /* ADD PARTY REJECT indication */ + struct uni_msg *msg = arg; + struct uniapi_add_party_rej_indication *ind = uni_msg_rptr(msg, + struct uniapi_add_party_rej_indication *); + + if (conn->state == CONN_AB_FLUSH_IND) + break; + if (conn->state != CONN_ACTIVE) + goto bad_state; + + memset(&conn->user->cause[1], 0, sizeof(conn->user->cause[1])); + conn->user->cause[0] = ind->rej.cause; + + cc_party_add_rej_ind(conn, &ind->rej.epref); + break; + } + + + case CONN_SIG_DROP_PARTY_IND: + { + /* DROP_PARTY.indication from UNI */ + struct uni_msg *msg = arg; + struct uniapi_drop_party_indication *ind = uni_msg_rptr(msg, + struct uniapi_drop_party_indication *); + struct uniapi_drop_party_ack_request *req; + struct uni_msg *u; + + if (conn->state == CONN_AB_FLUSH_IND) + break; + if (conn->state != CONN_ACTIVE) + goto bad_state; + + party = cc_party_find(conn, ind->drop.epref.epref); + if (party == NULL) { + cc_party_log(party, "no party for %s", + cc_conn_sigtab[sig]); + break; + } + + u = uni_msg_alloc(sizeof(*req)); + if (u == NULL) + return; + + memset(&conn->user->cause[1], 0, sizeof(conn->user->cause[1])); + conn->user->cause[0] = ind->drop.cause; + + switch (party->state) { + + default: + cc_party_log(party, "bad state %s for DROP.ind", + ptab[party->state]); + /* FALLTHRU */ + + case PARTY_ACTIVE: /* P1 -> P9 */ + cc_party_set_state(party, PARTY_WAIT_DROP_ACK_OK); + break; + + case PARTY_ADD_WAIT_ACK: /* P4 -> P12 */ + cc_party_set_state(party, PARTY_ADD_DROPACK_WAIT_OK); + break; + } + + /* + * Construct message to UNI. + */ + req = uni_msg_wptr(u, struct uniapi_drop_party_ack_request *); + memset(req, 0, sizeof(*req)); + u->b_wptr += sizeof(*req); + + IE_SETPRESENT(req->ack.epref); + req->ack.hdr.act = UNI_MSGACT_DEFAULT; + req->ack.hdr.cref = conn->cref; + + req->ack.epref.flag = 0; + req->ack.epref.epref = ind->drop.epref.epref; + + cc_send_uni(conn, UNIAPI_DROP_PARTY_ACK_request, u); + break; + } + + case CONN_SIG_OK: + { + /* OK response from UNI */ + struct ccuser *user = conn->user; + + switch (conn->state) { + + case CONN_OUT_WAIT_OK: /* C3 */ + cc_conn_set_state(conn, CONN_OUT_WAIT_CONF); + if (conn->user != NULL) + cc_user_sig(conn->user, + USER_SIG_CONNECT_OUTGOING_OK, NULL, 0); + break; + + case CONN_AB_WAIT_RESP_OK: /* C33 */ + case CONN_AB_WAIT_REQ_OK: /* C34 */ + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + break; + + case CONN_REL_WAIT_OK: /* C20 */ + case CONN_REL_IN_WAIT_OK: /* C15 */ + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + if (conn->user != NULL) { + /* connection has not been aborted */ + memset(&conn->user->cause, 0, + sizeof(conn->user->cause)); + cc_user_sig(conn->user, + USER_SIG_RELEASE_CONFIRM, NULL, 0); + cc_disconnect_from_user(conn); + } + break; + + case CONN_IN_WAIT_ACCEPT_OK: /* C12 */ + if (user == NULL) { + /* has been aborted */ + do_release_request(conn, NULL); + cc_conn_set_state(conn, CONN_AB_WAIT_REQ_OK); + break; + } + cc_conn_set_state(conn, CONN_IN_WAIT_COMPL); + cc_disconnect_from_user(conn); + cc_user_sig(user, USER_SIG_ACCEPT_OK, NULL, 0); + if (conn->acceptor == NULL) { + do_release_request(conn, NULL); + cc_conn_set_state(conn, CONN_AB_WAIT_REQ_OK); + break; + } + cc_connect_to_user(conn, conn->acceptor); + cc_conn_reset_acceptor(conn); + cc_user_sig(conn->user, USER_SIG_ACCEPTING, NULL, 0); + break; + + case CONN_REJ_WAIT_OK: /* C14 */ + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + if (user != NULL) { + cc_disconnect_from_user(conn); + cc_user_sig(user, USER_SIG_REJECT_OK, NULL, 0); + } + break; + + default: + /* maybe it's for a party */ + LIST_FOREACH(party, &conn->parties, link) { + switch (party->state) { + + case PARTY_ADD_WAIT_OK: /* P3 */ + if (user != NULL) + cc_user_sig(user, + USER_SIG_ADD_PARTY_OK, + NULL, 0); + cc_party_set_state(party, + PARTY_ADD_WAIT_ACK); + goto ex_party_ok; + + case PARTY_DROP_WAIT_OK: /* P5 */ + cc_party_set_state(party, + PARTY_DROP_WAIT_ACK); + goto ex_party_ok; + + case PARTY_WAIT_DROP_ACK_OK: /* P9 */ + case PARTY_ADD_DROPACK_WAIT_OK:/* P12 */ + { + struct ccparty *p1; + + cc_party_set_state(party, + PARTY_WAIT_DESTROY); + /* signal to user only if there are any other parties */ + LIST_FOREACH(p1, &conn->parties, link) + if (p1 != party) + break; + if (p1 != NULL && user != NULL) + cc_user_sig(user, + USER_SIG_DROP_PARTY_IND, + NULL, + party->epref.epref); + + goto ex_party_ok; + } + + case PARTY_ADD_DROP_WAIT_OK: /* P11 */ + cc_party_set_state(party, + PARTY_DROP_WAIT_ACK); + goto ex_party_ok; + + default: + break; + } + } + goto bad_state; + ex_party_ok: + break; + } + break; + } + + case CONN_SIG_ERROR: + { + /* error response from UNI */ + u_int reason = (iarg >> 16) & 0xffff; + u_int state = iarg & 0xffff; + struct ccuser *user = conn->user; + + switch (conn->state) { + + case CONN_OUT_WAIT_CREATE: /* C2 */ + cc_conn_rem_port(conn); + cc_conn_set_state(conn, CONN_OUT_PREPARING); + if (conn->user != NULL) + cc_user_sig(conn->user, + USER_SIG_CONNECT_OUTGOING_ERR, + NULL, ATM_MKUNIERR(reason)); + break; + + case CONN_OUT_WAIT_OK: /* C3 */ + cc_conn_set_state(conn, CONN_OUT_WAIT_DESTROY); + conn->reason = reason; + break; + + case CONN_AB_WAIT_REQ_OK: /* C33 */ + if (state == UNI_CALLSTATE_U12) { + do_release_response(conn, 0, conn->cause); + cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK); + break; + } + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + break; + + case CONN_AB_WAIT_RESP_OK: /* C34 */ + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + break; + + case CONN_REL_WAIT_OK: /* C20 */ + if (user == NULL) { + /* connection has been aborted. */ + if (state == UNI_CALLSTATE_U10) { + /* do what we can */ + do_release_request(conn, conn->cause); + cc_conn_set_state(conn, + CONN_AB_WAIT_REQ_OK); + } else if (state == UNI_CALLSTATE_U12) { + do_release_response(conn, 0, NULL); + cc_conn_set_state(conn, + CONN_AB_WAIT_RESP_OK); + } else { + cc_conn_set_state(conn, + CONN_AB_FLUSH_IND); + } + break; + } + if (state == UNI_CALLSTATE_U10) { + cc_conn_set_state(conn, CONN_ACTIVE); + cc_user_sig(conn->user, USER_SIG_RELEASE_ERR, + NULL, reason); + } else if (state == UNI_CALLSTATE_U12) { + do_release_response(conn, 0, NULL); + cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK); + memset(&conn->user->cause, 0, + sizeof(conn->user->cause)); + cc_user_sig(conn->user, + USER_SIG_RELEASE_CONFIRM, NULL, 0); + cc_disconnect_from_user(conn); + } else { + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + memset(&conn->user->cause, 0, + sizeof(conn->user->cause)); + cc_user_sig(conn->user, + USER_SIG_RELEASE_CONFIRM, NULL, 0); + cc_disconnect_from_user(conn); + } + break; + + case CONN_IN_WAIT_ACCEPT_OK: /* C12 */ + if (user == NULL) { + /* connection was aborted */ + if (state == UNI_CALLSTATE_U6 || + state == UNI_CALLSTATE_U7 || + state == UNI_CALLSTATE_U9 || + state == UNI_CALLSTATE_U12) { + do_release_response(conn, 0, NULL); + cc_conn_set_state(conn, + CONN_AB_WAIT_RESP_OK); + } else { + cc_conn_set_state(conn, + CONN_AB_FLUSH_IND); + } + break; + } + cc_conn_reset_acceptor(conn); + if (state == UNI_CALLSTATE_U6 || + state == UNI_CALLSTATE_U9 || + state == UNI_CALLSTATE_U7) { + cc_user_sig(user, USER_SIG_ACCEPT_ERR, + NULL, ATM_MKUNIERR(reason)); + cc_conn_set_state(conn, CONN_IN_ARRIVED); + } else if (state == UNI_CALLSTATE_U12) { + do_release_response(conn, 0, NULL); + cc_disconnect_from_user(conn); + cc_user_sig(user, USER_SIG_ACCEPT_ERR, + user, ATMERR_PREVIOUSLY_ABORTED); + cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK); + } else { + cc_disconnect_from_user(conn); + cc_user_sig(user, USER_SIG_ACCEPT_ERR, + user, ATMERR_PREVIOUSLY_ABORTED); + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + } + break; + + case CONN_REJ_WAIT_OK: /* C14 */ + if (user == NULL) { + /* connection has been aborted. */ + if (state == UNI_CALLSTATE_U6 || + state == UNI_CALLSTATE_U7 || + state == UNI_CALLSTATE_U9 || + state == UNI_CALLSTATE_U12) { + /* do what we can */ + do_release_response(conn, 0, NULL); + cc_conn_set_state(conn, + CONN_AB_WAIT_RESP_OK); + } else { + cc_conn_set_state(conn, + CONN_AB_FLUSH_IND); + } + break; + } + if (state == UNI_CALLSTATE_U6 || + state == UNI_CALLSTATE_U9 || + state == UNI_CALLSTATE_U7) { + cc_user_sig(user, USER_SIG_REJECT_ERR, + NULL, ATM_MKUNIERR(reason)); + cc_conn_set_state(conn, CONN_IN_ARRIVED); + } else { + cc_disconnect_from_user(conn); + cc_user_sig(user, USER_SIG_REJECT_OK, NULL, 0); + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + } + break; + + case CONN_REL_IN_WAIT_OK: /* C15 */ + if (user == NULL) { + /* connection has been aborted. */ + if (state == UNI_CALLSTATE_U8) { + /* do what we can */ + do_release_request(conn, conn->cause); + cc_conn_set_state(conn, + CONN_AB_WAIT_REQ_OK); + } else if (state == UNI_CALLSTATE_U12) { + do_release_response(conn, 0, NULL); + cc_conn_set_state(conn, + CONN_AB_WAIT_RESP_OK); + } else { + cc_conn_set_state(conn, + CONN_AB_FLUSH_IND); + } + break; + } + if (state == UNI_CALLSTATE_U8) { + cc_conn_set_state(conn, CONN_IN_WAIT_COMPL); + cc_user_sig(conn->user, USER_SIG_RELEASE_ERR, + NULL, reason); + } else if (state == UNI_CALLSTATE_U12) { + do_release_response(conn, 0, NULL); + cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK); + memset(&conn->user->cause, 0, + sizeof(conn->user->cause)); + cc_user_sig(conn->user, + USER_SIG_RELEASE_CONFIRM, NULL, 0); + cc_disconnect_from_user(conn); + } else { + cc_conn_set_state(conn, CONN_AB_FLUSH_IND); + memset(&conn->user->cause, 0, + sizeof(conn->user->cause)); + cc_user_sig(conn->user, + USER_SIG_RELEASE_CONFIRM, NULL, 0); + cc_disconnect_from_user(conn); + } + break; + + default: + /* maybe it's for a party */ + LIST_FOREACH(party, &conn->parties, link) { + switch (party->state) { + + case PARTY_ADD_WAIT_CREATE: /* P2 */ + cc_party_destroy(party); + if (user != NULL) + cc_user_sig(user, + USER_SIG_ADD_PARTY_ERR, + NULL, ATM_MKUNIERR(reason)); + goto ex_party_err; + + case PARTY_ADD_WAIT_OK: /* P3 */ + cc_party_set_state(party, + PARTY_WAIT_DESTROY); + if (user != NULL) + cc_user_sig(user, + USER_SIG_ADD_PARTY_ERR, + NULL, ATM_MKUNIERR(reason)); + goto ex_party_err; + + case PARTY_DROP_WAIT_OK: /* P5 */ + cc_party_set_state(party, + PARTY_ACTIVE); + if (user != NULL) + cc_user_sig(user, + USER_SIG_DROP_PARTY_ERR, + NULL, ATM_MKUNIERR(reason)); + goto ex_party_err; + + case PARTY_WAIT_DROP_ACK_OK: /* P9 */ + cc_party_set_state(party, + PARTY_ACTIVE); + goto ex_party_err; + + case PARTY_ADD_DROP_WAIT_OK: /* P11 */ + cc_party_set_state(party, + PARTY_ADD_WAIT_ACK); + if (user != NULL) + cc_user_sig(user, + USER_SIG_DROP_PARTY_ERR, + NULL, ATM_MKUNIERR(reason)); + goto ex_party_err; + + case PARTY_ADD_DROPACK_WAIT_OK:/* P12 */ + cc_party_set_state(party, + PARTY_ADD_WAIT_ACK); + goto ex_party_err; + + default: + break; + } + } + cc_conn_log(conn, "unexpected reason=%u ustate=%u " + "state=%s\n", reason, state, stab[conn->state]); + ex_party_err: + break; + } + break; + } + + case CONN_SIG_PARTY_CREATED: + { + struct uni_msg *msg = arg; + struct uniapi_party_created *pcr = uni_msg_rptr(msg, + struct uniapi_party_created *); + + party = cc_party_find(conn, pcr->epref.epref); + if (party == NULL) { + /* for incoming connections we see the party-created + * immediately after the call-create so that we + * must be in C10 */ + switch (conn->state) { + + case CONN_IN_PREPARING: + party = cc_party_create(conn, + pcr->epref.epref, 1); + if (party == NULL) + break; + cc_party_set_state(party, + PARTY_WAIT_SETUP_COMPL); + break; + + case CONN_OUT_WAIT_OK: + party = cc_party_create(conn, + pcr->epref.epref, 0); + if (party == NULL) + break; + cc_party_set_state(party, + PARTY_WAIT_SETUP_CONF); + break; + + default: + goto bad_state; + } + break; + } + /* this is for an ADD-PARTY */ + if (conn->state != CONN_ACTIVE) + goto bad_state; + if (party->state != PARTY_ADD_WAIT_CREATE) + goto bad_party_state; + cc_party_set_state(party, PARTY_ADD_WAIT_OK); + break; + } + + case CONN_SIG_PARTY_DESTROYED: + { + struct uni_msg *msg = arg; + struct uniapi_party_destroyed *pcr = uni_msg_rptr(msg, + struct uniapi_party_destroyed *); + + party = cc_party_find(conn, pcr->epref.epref); + if (party == NULL) { + cc_conn_log(conn, "no party to destroy %u/%u", + pcr->epref.flag, pcr->epref.epref); + break; + } + cc_party_destroy(party); + break; + } + + } + + return; + + bad_state: + cc_conn_log(conn, "bad state=%s for signal=%s", + stab[conn->state], cc_conn_sigtab[sig]); + return; + + bad_party_state: + cc_conn_log(conn, "bad party state=%s for signal=%s", + ptab[party->state], cc_conn_sigtab[sig]); + return; +} diff --git a/sys/contrib/ngatm/netnatm/api/cc_data.c b/sys/contrib/ngatm/netnatm/api/cc_data.c new file mode 100644 index 000000000000..bf607de1e45b --- /dev/null +++ b/sys/contrib/ngatm/netnatm/api/cc_data.c @@ -0,0 +1,226 @@ +/* +* Copyright (c) 2004 +* Hartmut Brandt +* 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_data.c,v 1.1 2004/07/08 08:21:50 brandt Exp $ +* +* ATM API as defined per af-saa-0108 +*/ +#include <netnatm/unimsg.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.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> + +/* + * Create a new call control instance + */ +struct ccdata * +cc_create(const struct cc_funcs *vtab) +{ + struct ccdata *cc; + + cc = CCMALLOC(sizeof(*cc)); + if (cc == NULL) + return (NULL); + + LIST_INIT(&cc->user_list); + TAILQ_INIT(&cc->port_list); + LIST_INIT(&cc->orphaned_conns); + TAILQ_INIT(&cc->sigs); + TAILQ_INIT(&cc->def_sigs); + TAILQ_INIT(&cc->free_sigs); + cc->funcs = vtab; + cc->cookie = 0; + + return (cc); +} + +/* + * Reset everything the hard way by just freeing the data + */ +void +cc_reset(struct ccdata *cc) +{ + + while (!LIST_EMPTY(&cc->user_list)) + cc_user_destroy(LIST_FIRST(&cc->user_list)); + + while (!TAILQ_EMPTY(&cc->port_list)) + cc_port_destroy(TAILQ_FIRST(&cc->port_list), 1); + + while (!LIST_EMPTY(&cc->orphaned_conns)) + cc_conn_destroy(LIST_FIRST(&cc->orphaned_conns)); + + CCASSERT(LIST_EMPTY(&cc->user_list), + ("user list not empty")); + CCASSERT(LIST_EMPTY(&cc->orphaned_conns), + ("still orphaned conns")); + + cc_sig_flush_all(cc); + + cc->cookie = 0; +} + +/* + * Destroy a call control instance and free all data + */ +void +cc_destroy(struct ccdata *cc) +{ + + cc_reset(cc); + CCFREE(cc); +} + +/* + * set/get logging flags + */ +void +cc_set_log(struct ccdata *cc, u_int flags) +{ + cc->log = flags; +} +u_int +cc_get_log(const struct ccdata *cc) +{ + return (cc->log); +} + +/* get extended status */ +int +cc_get_extended_status(const struct ccdata *cc, struct atm_exstatus *status, + struct atm_exstatus_ep **pep, struct atm_exstatus_port **pport, + struct atm_exstatus_conn **pconn, struct atm_exstatus_party **pparty) +{ + const struct ccuser *user; + const struct ccport *port; + const struct ccconn *conn; + const struct ccparty *party; + struct atm_exstatus_ep *eep; + struct atm_exstatus_port *eport; + struct atm_exstatus_conn *econn; + struct atm_exstatus_party *eparty; + + /* count and allocate */ + status->neps = 0; + LIST_FOREACH(user, &cc->user_list, node_link) + status->neps++; + + status->nports = 0; + status->nconns = 0; + status->nparties = 0; + LIST_FOREACH(conn, &cc->orphaned_conns, port_link) { + status->nconns++; + LIST_FOREACH(party, &conn->parties, link) + status->nparties++; + } + TAILQ_FOREACH(port, &cc->port_list, node_link) { + status->nports++; + LIST_FOREACH(conn, &port->conn_list, port_link) { + status->nconns++; + LIST_FOREACH(party, &conn->parties, link) + status->nparties++; + } + } + + *pep = CCMALLOC(sizeof(**pep) * status->neps); + *pport = CCMALLOC(sizeof(**pport) * status->nports); + *pconn = CCMALLOC(sizeof(**pconn) * status->nconns); + *pparty = CCMALLOC(sizeof(**pparty) * status->nparties); + + if (*pep == NULL || *pport == NULL || + *pconn == NULL || *pparty == NULL) { + CCFREE(*pep); + CCFREE(*pport); + CCFREE(*pconn); + CCFREE(*pparty); + return (ENOMEM); + } + + eep = *pep; + eport = *pport; + econn = *pconn; + eparty = *pparty; + + /* collect information */ + LIST_FOREACH(user, &cc->user_list, node_link) { + strcpy(eep->name, user->name); + eep->state = user->state; + eep++; + } + + LIST_FOREACH(conn, &cc->orphaned_conns, port_link) { + econn->id = econn - *pconn; + econn->port = 0; + if (conn->user != NULL) + strcpy(econn->ep, conn->user->name); + else + econn->ep[0] = '\0'; + econn->state = conn->state; + econn->cref = conn->cref.cref; + if (conn->cref.flag) + econn->cref |= (1 << 23); + LIST_FOREACH(party, &conn->parties, link) { + eparty->connid = econn - *pconn; + eparty->epref = party->epref.epref; + eparty->state = party->state; + eparty++; + } + econn++; + } + + TAILQ_FOREACH(port, &cc->port_list, node_link) { + eport->portno = port->param.port; + eport->state = port->admin; + LIST_FOREACH(conn, &port->conn_list, port_link) { + econn->id = econn - *pconn; + econn->port = port->param.port; + if (conn->user != NULL) + strcpy(econn->ep, conn->user->name); + else + econn->ep[0] = '\0'; + econn->state = conn->state; + econn->cref = conn->cref.cref; + if (conn->cref.flag) + econn->cref |= (1 << 23); + LIST_FOREACH(party, &conn->parties, link) { + eparty->connid = econn - *pconn; + eparty->epref = party->epref.epref; + eparty->state = party->state; + eparty++; + } + econn++; + } + eport++; + } + return (0); +} diff --git a/sys/contrib/ngatm/netnatm/api/cc_dump.c b/sys/contrib/ngatm/netnatm/api/cc_dump.c new file mode 100644 index 000000000000..245f8b7b5f04 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/api/cc_dump.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2003-2004 + * Hartmut Brandt + * 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_dump.c,v 1.3 2004/08/05 07:10:56 brandt Exp $ + * + * ATM API as defined per af-saa-0108 + */ + +#include <netnatm/unimsg.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.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> + +#ifdef _KERNEL +#ifdef __FreeBSD__ +#include <machine/stdarg.h> +#endif +#else /* !_KERNEL */ +#include <stdarg.h> +#endif + +/* + * local structure to reduce number of arguments to functions + */ +struct dump { + struct ccdata *cc; /* what to dump */ + size_t maxsiz; /* size of user buffer */ + cc_dump_f func; /* user function */ + void *uarg; /* user supplied argument */ + char *buf; /* user buffer */ + size_t len; /* current string length */ + int ret; /* return code */ +}; + +static void cc_dumpf(struct dump *, const char *, ...) __printflike(2, 3); + +static void +cc_dumpf(struct dump *d, const char *fmt, ...) +{ + va_list ap; + int n; + + if (d->ret != 0) + return; + if (d->len >= d->maxsiz - 1) { + d->ret = d->func(d->cc, d->uarg, d->buf); + if (d->ret != 0) + return; + d->buf[0] = '\0'; + d->len = 0; + } + va_start(ap, fmt); + n = vsnprintf(d->buf + d->len, d->maxsiz - d->len, fmt, ap); + va_end(ap); + + if (n < 0) { + d->ret = CCGETERRNO(); + return; + } + if ((size_t)n < d->maxsiz - d->len) { + d->len += n; + return; + } + + /* undo the vsnprintf() and flush */ + d->buf[d->len] = '\0'; + d->ret = d->func(d->cc, d->uarg, d->buf); + if (d->ret != 0) + return; + d->buf[0] = '\0'; + d->len = 0; + + va_start(ap, fmt); + n = vsnprintf(d->buf, d->maxsiz, fmt, ap); + va_end(ap); + + if (n < 0) { + d->ret = CCGETERRNO(); + return; + } + if ((size_t)n >= d->maxsiz) { + /* ok, truncate */ + d->len = d->maxsiz - 1; + return; + } + d->len = n; +} + +/* + * Dump a SAP + */ +static void +cc_dump_sap(struct dump *d, const struct uni_sap *sap) +{ + static const char *const tagtab[] = { + [UNISVE_ABSENT] = "absent", + [UNISVE_ANY] = "any", + [UNISVE_PRESENT] = "present" + }; + static const char *const plantab[] = { + [UNI_ADDR_E164] = "E164", + [UNI_ADDR_ATME] = "ATME", + }; + static const char *const hlitab[] = { + [UNI_BHLI_ISO] = "ISO", + [UNI_BHLI_VENDOR] = "VENDOR", + [UNI_BHLI_USER] = "USER" + }; + u_int i; + + cc_dumpf(d, " sap(%p):\n", sap); + cc_dumpf(d, " addr=%s", tagtab[sap->addr.tag]); + if (sap->addr.tag == UNISVE_PRESENT) { + cc_dumpf(d, " %s %u ", plantab[sap->addr.plan], sap->addr.len); + if (sap->addr.plan == UNI_ADDR_E164) + for (i = 0; i < sap->addr.len; i++) + cc_dumpf(d, "%c", sap->addr.addr[i]); + else + for (i = 0; i < sap->addr.len; i++) + cc_dumpf(d, "%02x", sap->addr.addr[i]); + } + cc_dumpf(d, "\n"); + + cc_dumpf(d, " selector=%s", tagtab[sap->selector.tag]); + if (sap->selector.tag == UNISVE_PRESENT) + cc_dumpf(d, " %02x", sap->selector.selector); + cc_dumpf(d, "\n"); + + cc_dumpf(d, " blli_id2=%s", tagtab[sap->blli_id2.tag]); + if (sap->blli_id2.tag == UNISVE_PRESENT) + cc_dumpf(d, " %02x %02x", sap->blli_id2.proto, + sap->blli_id2.user); + cc_dumpf(d, "\n"); + + cc_dumpf(d, " blli_id3=%s", tagtab[sap->blli_id3.tag]); + if (sap->blli_id3.tag == UNISVE_PRESENT) + cc_dumpf(d, " %02x,%02x, %02x(%d),%03x,%02x", + sap->blli_id3.proto, sap->blli_id3.user, + sap->blli_id3.ipi, sap->blli_id3.noipi, + sap->blli_id3.oui, sap->blli_id3.pid); + cc_dumpf(d, "\n"); + + cc_dumpf(d, " bhli=%s", tagtab[sap->bhli.tag]); + if (sap->bhli.tag == UNISVE_PRESENT) { + cc_dumpf(d, " %s ", hlitab[sap->bhli.type]); + for (i = 0; i < sap->bhli.len; i++) + cc_dumpf(d, "%02x", sap->bhli.info[i]); + } + cc_dumpf(d, "\n"); +} + +/* + * Dump a user. + */ +static void +cc_dump_user(struct dump *d, const struct ccuser *user) +{ + struct ccconn *conn; + + cc_dumpf(d, "user(%p): %s '%s' %s\n", user, + cc_user_state2str(user->state), user->name, + (user->config == USER_P2P) ? "p2p" : + (user->config == USER_ROOT) ? "root" : + (user->config == USER_LEAF) ? "leaf" : "?"); + if (user->sap) + cc_dump_sap(d, user->sap); + + cc_dumpf(d, " queue=%u/%u accepted=%p aborted=%u\n", user->queue_max, + user->queue_act, user->accepted, user->aborted); + + cc_dumpf(d, " connq:"); + TAILQ_FOREACH(conn, &user->connq, connq_link) + cc_dumpf(d, "%p", conn); + cc_dumpf(d, "\n"); +} + +/* + * Dump a party + */ +static void +cc_dump_party(struct dump *d, const struct ccparty *party, const char *pfx) +{ + + cc_dumpf(d, "%s party(%p): %u.%u %s\n", pfx, party, + party->epref.flag, party->epref.epref, + cc_party_state2str(party->state)); +} + +/* + * Dump a connection + */ +static void +cc_dump_conn(struct dump *d, const struct ccconn *conn, const char *pfx) +{ + const struct ccparty *party; + + cc_dumpf(d, "%sconn(%p): %s\n", pfx, conn, + cc_conn_state2str(conn->state)); + cc_dumpf(d, "%s user=%p cref=%u.%u acceptor=%p\n", pfx, + conn->user, conn->cref.cref, conn->cref.flag, + conn->acceptor); + + cc_dumpf(d, "%s blli_sel=%u\n", pfx, conn->blli_selector); + + LIST_FOREACH(party, &conn->parties, link) + cc_dump_party(d, party, pfx); +} + +/* + * Dump a port + */ +static void +cc_dump_port(struct dump *d, const struct ccport *p) +{ + u_int i; + const struct ccaddr *a; + const struct ccconn *c; + const struct ccreq *r; + + static const char *const ttab[] = { + [UNI_ADDR_UNKNOWN] = "unknown", + [UNI_ADDR_INTERNATIONAL] = "international", + [UNI_ADDR_NATIONAL] = "national", + [UNI_ADDR_NETWORK] = "network", + [UNI_ADDR_SUBSCR] = "subscr", + [UNI_ADDR_ABBR] = "abbr", + }; + static const char *const ptab[] = { + [UNI_ADDR_UNKNOWN] = "unknown", + [UNI_ADDR_E164] = "e164", + [UNI_ADDR_ATME] = "atme", + [UNI_ADDR_DATA] = "data", + [UNI_ADDR_PRIVATE] = "private", + }; + + cc_dumpf(d, "port(%p) %u: %s\n", p, p->param.port, + (p->admin == CCPORT_STOPPED) ? "STOPPED" : + (p->admin == CCPORT_RUNNING) ? "RUNNING" : "????"); + cc_dumpf(d, " pcr=%u bits=%u.%u ids=%u/%u/%u esi=%02x:%02x:" + "%02x:%02x:%02x:%02x naddrs=%u\n", p->param.pcr, + p->param.max_vpi_bits, p->param.max_vci_bits, p->param.max_svpc_vpi, + p->param.max_svcc_vpi, p->param.min_svcc_vci, p->param.esi[0], + p->param.esi[1], p->param.esi[2], p->param.esi[3], p->param.esi[4], + p->param.esi[5], p->param.num_addrs); + + cc_dumpf(d, " cookies:"); + TAILQ_FOREACH(r, &p->cookies, link) + cc_dumpf(d, " %u(%p,%u)", r->cookie, r->conn, r->req); + cc_dumpf(d, "\n"); + + TAILQ_FOREACH(a, &p->addr_list, port_link) { + cc_dumpf(d, " addr(%p): %s %s %u ", a, + (a->addr.type < sizeof(ttab) / sizeof(ttab[0]) && + ttab[a->addr.type] != NULL) ? ttab[a->addr.type] : "?", + (a->addr.plan < sizeof(ptab) / sizeof(ptab[0]) && + ptab[a->addr.plan] != NULL) ? ptab[a->addr.plan] : "?", + a->addr.len); + for (i = 0; i < a->addr.len; i++) + cc_dumpf(d, "%02x", a->addr.addr[i]); + cc_dumpf(d, "\n"); + } + LIST_FOREACH(c, &p->conn_list, port_link) + cc_dump_conn(d, c, " "); +} + +/* + * Produce a textual dump of the state + */ +int +cc_dump(struct ccdata *cc, size_t maxsiz, cc_dump_f func, void *uarg) +{ + struct dump d; + struct ccuser *user; + struct ccconn *conn; + struct ccport *port; + + d.ret = 0; + d.uarg = uarg; + d.maxsiz = maxsiz; + d.cc = cc; + d.func = func; + d.buf = CCMALLOC(maxsiz); + if (d.buf == NULL) + return (ENOMEM); + d.len = 0; + + cc_dumpf(&d, "dump of node %p\n", cc); + + TAILQ_FOREACH(port, &cc->port_list, node_link) + cc_dump_port(&d, port); + + LIST_FOREACH(user, &cc->user_list, node_link) + cc_dump_user(&d, user); + + cc_dumpf(&d, "orphaned conns:\n"); + LIST_FOREACH(conn, &cc->orphaned_conns, port_link) + cc_dump_conn(&d, conn, ""); + + if (d.len > 0 && d.ret == 0) + d.ret = d.func(d.cc, d.uarg, d.buf); + + CCFREE(d.buf); + return (d.ret); +} 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 000000000000..f01a723260b2 --- /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); +} + diff --git a/sys/contrib/ngatm/netnatm/api/cc_sig.c b/sys/contrib/ngatm/netnatm/api/cc_sig.c new file mode 100644 index 000000000000..ae6fcce51229 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/api/cc_sig.c @@ -0,0 +1,350 @@ +/* +* Copyright (c) 2004 +* Hartmut Brandt +* 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_sig.c,v 1.1 2004/07/08 08:21:54 brandt Exp $ +* +* ATM API as defined per af-saa-0108 +* +* Generic signal handling +*/ +#include <netnatm/unimsg.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.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> + +enum { + SIG_USER, + SIG_CONN, +}; + +struct ccsig { + u_char type; /* type of target */ + u_char has_msg; /* arg1 is a message */ + void *target; /* target instance */ + u_int sig; /* signal */ + void *arg1; /* argument */ + u_int arg2; /* argument */ + TAILQ_ENTRY(ccsig) link; +}; + +#if defined(__GNUC__) && __GNUC__ < 3 +#define cc_sig_log(CC, FMT, ARGS...) do { \ + if ((CC)->log & CCLOG_SIGS) \ + (CC)->funcs->log("%s: " FMT, __FUNCTION__ , ## ARGS); \ + } while (0) +#else +#define cc_sig_log(CC, FMT, ...) do { \ + if ((CC)->log & CCLOG_SIGS) \ + (CC)->funcs->log("%s: " FMT, __func__, __VA_ARGS__); \ + } while (0) +#endif + + +const char *const cc_user_sigtab[] = { +#define DEF(N) [USER_SIG_##N] = #N, +USER_SIGS +#undef DEF +}; + +const char *const cc_conn_sigtab[] = { +#define DEF(N) [CONN_SIG_##N] = #N, +CONN_SIGS +#undef DEF +}; + + +/* + * Allocate and populate a signal + */ +static /* __inline */ struct ccsig * +sig_alloc(struct ccdata *cc, u_int type, void *target, u_int has_msg, + u_int sig, void *arg1, u_int arg2) +{ + struct ccsig *s; + + if ((s = TAILQ_FIRST(&cc->free_sigs)) == NULL) { + s = CCZALLOC(sizeof(struct ccsig)); + if (s == NULL) { + cc_log(cc, "signal %u/%u lost - ENOMEM", type, sig); + return (NULL); + } + } else + TAILQ_REMOVE(&cc->free_sigs, s, link); + + s->type = type; + s->has_msg = has_msg; + s->target = target; + s->sig = sig; + s->arg1 = arg1; + s->arg2 = arg2; + + return (s); +} + +/* + * Queue a signal to this user + */ +int +cc_user_sig(struct ccuser *user, enum user_sig sig, void *arg1, u_int arg2) +{ + struct ccsig *s; + + s = sig_alloc(user->cc, SIG_USER, user, 0, sig, arg1, arg2); + if (s == NULL) + return (ENOMEM); + TAILQ_INSERT_TAIL(&user->cc->sigs, s, link); + cc_sig_log(user->cc, "queuing sig %s to user %p", cc_user_sigtab[sig], + user); + return (0); +} + +/* Queue a signal with message to this user */ +int +cc_user_sig_msg(struct ccuser *user, enum user_sig sig, struct uni_msg *msg) +{ + struct ccsig *s; + + s = sig_alloc(user->cc, SIG_USER, user, msg != NULL, sig, msg, 0); + if (s == NULL) + return (ENOMEM); + TAILQ_INSERT_TAIL(&user->cc->sigs, s, link); + cc_sig_log(user->cc, "queuing sig %s to user %p", cc_user_sigtab[sig], + user); + return (0); +} + +/* + * Signal to connection + */ +static int +sig_conn(struct ccconn *conn, enum conn_sig sig, u_int has_msg, void *arg) +{ + struct ccsig *s; + const struct ccreq *r = NULL; + + s = sig_alloc(conn->cc, SIG_CONN, conn, has_msg, sig, arg, 0); + if (s == NULL) + return (ENOMEM); + + if (conn->port != NULL) { + /* argh */ + TAILQ_FOREACH(r, &conn->port->cookies, link) + if (r->conn == conn) + break; + } + if (r == NULL) { + TAILQ_INSERT_TAIL(&conn->cc->sigs, s, link); + cc_sig_log(conn->cc, "queuing sig %s to conn %p", + cc_conn_sigtab[sig], conn); + } else { + TAILQ_INSERT_TAIL(&conn->cc->def_sigs, s, link); + cc_sig_log(conn->cc, "queuing defered sig %s to conn %p", + cc_conn_sigtab[sig], conn); + } + return (0); +} + +/* + * Queue a signal to a connection. + */ +int +cc_conn_sig(struct ccconn *conn, enum conn_sig sig, void *arg1) +{ + + return (sig_conn(conn, sig, 0, arg1)); +} + +/* + * signal with message to connection + */ +int +cc_conn_sig_msg(struct ccconn *conn, enum conn_sig sig, struct uni_msg *msg) +{ + + return (sig_conn(conn, sig, (msg != NULL), msg)); +} +int +cc_conn_sig_msg_nodef(struct ccconn *conn, enum conn_sig sig, + struct uni_msg *msg) +{ + struct ccsig *s; + + s = sig_alloc(conn->cc, SIG_CONN, conn, (msg != NULL), sig, msg, 0); + if (s == NULL) + return (ENOMEM); + + TAILQ_INSERT_TAIL(&conn->cc->sigs, s, link); + cc_sig_log(conn->cc, "queuing sig %s to conn %p", + cc_conn_sigtab[sig], conn); + + return (0); +} + +/* + * Queue a response signal to a connection. + */ +int +cc_conn_resp(struct ccconn *conn, enum conn_sig sig, u_int cookie __unused, + u_int reason, u_int state) +{ + struct ccsig *s, *s1, *s2; + + s = sig_alloc(conn->cc, SIG_CONN, conn, 0, sig, NULL, + ((reason & 0xffff) << 16) | (state & 0xffff)); + if (s == NULL) + return (ENOMEM); + + TAILQ_INSERT_TAIL(&conn->cc->sigs, s, link); + + cc_sig_log(conn->cc, "queuing response %s to conn %p", + cc_conn_sigtab[sig], conn); + + s1 = TAILQ_FIRST(&conn->cc->def_sigs); + while (s1 != NULL) { + s2 = TAILQ_NEXT(s1, link); + if (s1->type == SIG_CONN && s1->target == conn) { + TAILQ_REMOVE(&conn->cc->def_sigs, s1, link); + TAILQ_INSERT_AFTER(&conn->cc->sigs, s, s1, link); + cc_sig_log(conn->cc, "undefering sig %s to conn %p", + cc_conn_sigtab[s1->sig], conn); + s = s1; + } + s1 = s2; + } + + return (0); +} + +/* + * Flush all signals to a given target from both queues + */ +static /* __inline */ void +sig_flush(struct ccdata *cc, u_int type, void *target) +{ + struct ccsig *s, *s1; + + s = TAILQ_FIRST(&cc->sigs); + while (s != NULL) { + s1 = TAILQ_NEXT(s, link); + if (s->type == type && s->target == target) { + if (s->has_msg) + uni_msg_destroy((struct uni_msg *)s->arg1); + TAILQ_REMOVE(&cc->sigs, s, link); + TAILQ_INSERT_HEAD(&cc->free_sigs, s, link); + } + s = s1; + } + + s = TAILQ_FIRST(&cc->def_sigs); + while (s != NULL) { + s1 = TAILQ_NEXT(s, link); + if (s->type == type && s->target == target) { + if (s->has_msg) + uni_msg_destroy((struct uni_msg *)s->arg1); + TAILQ_REMOVE(&cc->def_sigs, s, link); + TAILQ_INSERT_HEAD(&cc->free_sigs, s, link); + } + s = s1; + } +} + +/* + * Flush all signals to this user + */ +void +cc_user_sig_flush(struct ccuser *user) +{ + + cc_sig_log(user->cc, "flushing signals to user %p", user); + sig_flush(user->cc, SIG_USER, user); +} + +/* + * Flush all signals to this connection + */ +void +cc_conn_sig_flush(struct ccconn *conn) +{ + + cc_sig_log(conn->cc, "flushing signals to conn %p", conn); + sig_flush(conn->cc, SIG_CONN, conn); +} + +/* + * Do the work + */ +void +cc_work(struct ccdata *cc) +{ + struct ccsig *s; + + cc_sig_log(cc, "start %s", "work"); + while ((s = TAILQ_FIRST(&cc->sigs)) != NULL) { + TAILQ_REMOVE(&cc->sigs, s, link); + if (s->type == SIG_USER) + cc_user_sig_handle(s->target, s->sig, s->arg1, s->arg2); + else { + cc_conn_sig_handle(s->target, s->sig, s->arg1, s->arg2); + if (s->has_msg) + uni_msg_destroy(s->arg1); + } + TAILQ_INSERT_HEAD(&cc->free_sigs, s, link); + } + cc_sig_log(cc, "end %s", "work"); +} + +/* + * flush all signals + */ +void +cc_sig_flush_all(struct ccdata *cc) +{ + struct ccsig *s; + + while ((s = TAILQ_FIRST(&cc->sigs)) != NULL) { + if (s->has_msg) + uni_msg_destroy((struct uni_msg *)s->arg1); + TAILQ_REMOVE(&cc->sigs, s, link); + CCFREE(s); + } + while ((s = TAILQ_FIRST(&cc->def_sigs)) != NULL) { + if (s->has_msg) + uni_msg_destroy((struct uni_msg *)s->arg1); + TAILQ_REMOVE(&cc->def_sigs, s, link); + CCFREE(s); + } + while ((s = TAILQ_FIRST(&cc->free_sigs)) != NULL) { + TAILQ_REMOVE(&cc->free_sigs, s, link); + CCFREE(s); + } +} diff --git a/sys/contrib/ngatm/netnatm/api/cc_user.c b/sys/contrib/ngatm/netnatm/api/cc_user.c new file mode 100644 index 000000000000..75ce91eb4e56 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/api/cc_user.c @@ -0,0 +1,1922 @@ +/* + * 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_user.c,v 1.3 2004/07/16 18:46:55 brandt Exp $ + * + * ATM API as defined per af-saa-0108 + * + * User side (upper half) + */ + +#include <netnatm/unimsg.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.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> + +/* +* This file handles messages to a USER. +*/ +static const char *stab[] = { +#define DEF(N) [N] = #N, + USER_STATES +#undef DEF +}; + +const char * +cc_user_state2str(u_int s) +{ + if (s >= sizeof(stab) / sizeof(stab[0]) || stab[s] == NULL) + return ("?"); + return (stab[s]); +} + +static __inline void +set_state(struct ccuser *user, enum user_state ns) +{ + if (user->state != ns) { + if (user->cc->log & CCLOG_USER_STATE) + cc_user_log(user, "%s -> %s", + stab[user->state], stab[ns]); + user->state = ns; + } +} + +static __inline void +cc_user_send(struct ccuser *user, u_int op, void *arg, size_t len) +{ + user->cc->funcs->send_user(user, user->uarg, op, arg, len); +} + +static __inline void +cc_user_ok(struct ccuser *user, u_int data, void *arg, size_t len) +{ + user->cc->funcs->respond_user(user, user->uarg, + ATMERR_OK, data, arg, len); +} + +static __inline void +cc_user_err(struct ccuser *user, int err) +{ + user->cc->funcs->respond_user(user, user->uarg, + err, ATMRESP_NONE, NULL, 0); +} + + +/********************************************************************** +* +* INSTANCE MANAGEMENT +*/ +/* +* New endpoint created +*/ +struct ccuser * +cc_user_create(struct ccdata *cc, void *uarg, const char *name) +{ + struct ccuser *user; + + user = CCZALLOC(sizeof(*user)); + if (user == NULL) + return (NULL); + + user->cc = cc; + user->state = USER_NULL; + user->uarg = uarg; + strncpy(user->name, name, sizeof(user->name)); + user->name[sizeof(user->name) - 1] = '\0'; + TAILQ_INIT(&user->connq); + LIST_INSERT_HEAD(&cc->user_list, user, node_link); + + if (user->cc->log & CCLOG_USER_INST) + cc_user_log(user, "created with name '%s'", name); + + return (user); +} + +/* + * Reset a user instance + */ +static void +cc_user_reset(struct ccuser *user) +{ + + CCASSERT(TAILQ_EMPTY(&user->connq), ("connq not empty")); + + if (user->sap != NULL) { + CCFREE(user->sap); + user->sap = NULL; + } + + if (user->accepted != NULL) { + user->accepted->acceptor = NULL; + user->accepted = NULL; + } + user->config = USER_P2P; + user->queue_act = 0; + user->queue_max = 0; + user->aborted = 0; + + set_state(user, USER_NULL); + + cc_user_sig_flush(user); +} + +static void +cc_user_abort(struct ccuser *user, const struct uni_ie_cause *cause) +{ + struct ccconn *conn; + + /* + * Although the standard state that 'all connections + * associated with this endpoint are aborted' we only + * have to abort the head one, because in state A6 + * (call present) the endpoint is only associated to the + * head connection - the others are 'somewhere else' and + * need to be redispatched. + * + * First bring user into a state that the connections + * are not dispatched back to it. + */ + set_state(user, USER_NULL); + if (!user->aborted) { + if ((conn = TAILQ_FIRST(&user->connq)) != NULL) { + memset(conn->cause, 0, sizeof(conn->cause)); + if (cause != NULL) + conn->cause[0] = *cause; + cc_conn_reset_acceptor(conn); + cc_disconnect_from_user(conn); + cc_conn_sig(conn, CONN_SIG_USER_ABORT, NULL); + } + } + + while ((conn = TAILQ_FIRST(&user->connq)) != NULL) { + /* these should be in C21 */ + cc_disconnect_from_user(conn); + cc_conn_dispatch(conn); + } + + cc_user_reset(user); +} + +/* + * Application has closed this endpoint. Clean up all user resources and + * abort all connections. This can be called in any state. + */ +void +cc_user_destroy(struct ccuser *user) +{ + + if (user->cc->log & CCLOG_USER_INST) + cc_user_log(user, "destroy '%s'", user->name); + + cc_user_abort(user, NULL); + + if (user->sap != NULL) + CCFREE(user->sap); + + cc_user_sig_flush(user); + + LIST_REMOVE(user, node_link); + CCFREE(user); +} + +/********************************************************************** + * + * OUTGOING CALLS + */ +/* + * Return true when the calling address of the connection matches the address. + */ +static int +addr_matches(const struct ccaddr *addr, const struct ccconn *conn) +{ + + if (!IE_ISPRESENT(conn->calling)) + return (0); + + return (addr->addr.type == conn->calling.addr.type && + addr->addr.plan == conn->calling.addr.plan && + addr->addr.len == conn->calling.addr.len && + memcmp(addr->addr.addr, conn->calling.addr.addr, + addr->addr.len) == 0); +} + +/* + * Check if the user's SAP (given he is in the right state) and + * the given SAP overlap + */ +static int +check_overlap(struct ccuser *user, struct uni_sap *sap) +{ + return ((user->state == USER_IN_PREPARING || + user->state == USER_IN_WAITING) && + unisve_overlap_sap(user->sap, sap)); +} + +/* + * Send arrival notification to user + */ +static void +do_arrival(struct ccuser *user) +{ + struct ccconn *conn; + + user->aborted = 0; + if ((conn = TAILQ_FIRST(&user->connq)) != NULL) { + set_state(user, USER_IN_ARRIVED); + cc_user_send(user, ATMOP_ARRIVAL_OF_INCOMING_CALL, NULL, 0); + cc_conn_sig(conn, CONN_SIG_ARRIVAL, NULL); + } +} + +/********************************************************************** + * + * ATTRIBUTES + */ +/* + * Query an attribute. This is possible only in some states: preparation + * of an outgoing call, after an incoming call was offered to the application + * and in the three active states (P2P, P2PLeaf, P2PRoot). + */ +static struct ccconn * +cc_query_check(struct ccuser *user) +{ + + switch (user->state) { + + case USER_OUT_PREPARING: + case USER_IN_ARRIVED: + case USER_ACTIVE: + return (TAILQ_FIRST(&user->connq)); + + case USER_NULL: + /* if we are waiting for the SETUP_confirm, we are in + * the NULL state still (we are the new endpoint), but + * have a connection in 'accepted' that is in the + * CONN_IN_WAIT_ACCEPT_OK state. + */ + if (user->accepted != NULL && + user->accepted->state == CONN_IN_WAIT_ACCEPT_OK) + return (user->accepted); + /* FALLTHRU */ + + default: + return (NULL); + } +} + +/* + * Query attributes + */ +static void +cc_attr_query(struct ccuser *user, struct ccconn *conn, + uint32_t *attr, u_int count) +{ + void *val, *ptr; + size_t total, len; + u_int i; + uint32_t *atab; + + /* determine the length of the total attribute buffer */ + total = sizeof(uint32_t) + count * sizeof(uint32_t); + for (i = 0; i < count; i++) { + len = 0; + switch ((enum atm_attribute)attr[i]) { + + case ATM_ATTR_NONE: + break; + + case ATM_ATTR_BLLI_SELECTOR: + len = sizeof(uint32_t); + break; + + case ATM_ATTR_BLLI: + len = sizeof(struct uni_ie_blli); + break; + + case ATM_ATTR_BEARER: + len = sizeof(struct uni_ie_bearer); + break; + + case ATM_ATTR_TRAFFIC: + len = sizeof(struct uni_ie_traffic); + break; + + case ATM_ATTR_QOS: + len = sizeof(struct uni_ie_qos); + break; + + case ATM_ATTR_EXQOS: + len = sizeof(struct uni_ie_exqos); + break; + + case ATM_ATTR_CALLED: + len = sizeof(struct uni_ie_called); + break; + + case ATM_ATTR_CALLEDSUB: + len = sizeof(struct uni_ie_calledsub); + break; + + case ATM_ATTR_CALLING: + len = sizeof(struct uni_ie_calling); + break; + + case ATM_ATTR_CALLINGSUB: + len = sizeof(struct uni_ie_callingsub); + break; + + case ATM_ATTR_AAL: + len = sizeof(struct uni_ie_aal); + break; + + case ATM_ATTR_EPREF: + len = sizeof(struct uni_ie_epref); + break; + + case ATM_ATTR_CONNED: + len = sizeof(struct uni_ie_conned); + break; + + case ATM_ATTR_CONNEDSUB: + len = sizeof(struct uni_ie_connedsub); + break; + + case ATM_ATTR_EETD: + len = sizeof(struct uni_ie_eetd); + break; + + case ATM_ATTR_ABRSETUP: + len = sizeof(struct uni_ie_abrsetup); + break; + + case ATM_ATTR_ABRADD: + len = sizeof(struct uni_ie_abradd); + break; + + case ATM_ATTR_CONNID: + len = sizeof(struct uni_ie_connid); + break; + + case ATM_ATTR_MDCR: + len = sizeof(struct uni_ie_mdcr); + break; + } + if (len == 0) { + cc_user_err(user, ATMERR_BAD_ATTR); + return; + } + total += len; + } + + /* allocate buffer */ + val = CCMALLOC(total); + if (val == NULL) + return; + + atab = val; + atab[0] = count; + + /* fill */ + ptr = (u_char *)val + (sizeof(uint32_t) + count * sizeof(uint32_t)); + for (i = 0; i < count; i++) { + len = 0; + atab[i + 1] = attr[i]; + switch (attr[i]) { + + case ATM_ATTR_NONE: + break; + + case ATM_ATTR_BLLI_SELECTOR: + len = sizeof(uint32_t); + memcpy(ptr, &conn->blli_selector, len); + break; + + case ATM_ATTR_BLLI: + /* in A6 the blli_selector may be 0 when + * there was no blli in the SETUP. + */ + len = sizeof(struct uni_ie_blli); + if (conn->blli_selector == 0) + memset(ptr, 0, len); + else + memcpy(ptr, &conn->blli[conn->blli_selector - + 1], len); + break; + + case ATM_ATTR_BEARER: + len = sizeof(struct uni_ie_bearer); + memcpy(ptr, &conn->bearer, len); + break; + + case ATM_ATTR_TRAFFIC: + len = sizeof(struct uni_ie_traffic); + memcpy(ptr, &conn->traffic, len); + break; + + case ATM_ATTR_QOS: + len = sizeof(struct uni_ie_qos); + memcpy(ptr, &conn->qos, len); + break; + + case ATM_ATTR_EXQOS: + len = sizeof(struct uni_ie_exqos); + memcpy(ptr, &conn->exqos, len); + break; + + case ATM_ATTR_CALLED: + len = sizeof(struct uni_ie_called); + memcpy(ptr, &conn->called, len); + break; + + case ATM_ATTR_CALLEDSUB: + len = sizeof(struct uni_ie_calledsub); + memcpy(ptr, &conn->calledsub, len); + break; + + case ATM_ATTR_CALLING: + len = sizeof(struct uni_ie_calling); + memcpy(ptr, &conn->calling, len); + break; + + case ATM_ATTR_CALLINGSUB: + len = sizeof(struct uni_ie_callingsub); + memcpy(ptr, &conn->callingsub, len); + break; + + case ATM_ATTR_AAL: + len = sizeof(struct uni_ie_aal); + memcpy(ptr, &conn->aal, len); + break; + + case ATM_ATTR_EPREF: + len = sizeof(struct uni_ie_epref); + memcpy(ptr, &conn->epref, len); + break; + + case ATM_ATTR_CONNED: + len = sizeof(struct uni_ie_conned); + memcpy(ptr, &conn->conned, len); + break; + + case ATM_ATTR_CONNEDSUB: + len = sizeof(struct uni_ie_connedsub); + memcpy(ptr, &conn->connedsub, len); + break; + + case ATM_ATTR_EETD: + len = sizeof(struct uni_ie_eetd); + memcpy(ptr, &conn->eetd, len); + break; + + case ATM_ATTR_ABRSETUP: + len = sizeof(struct uni_ie_abrsetup); + memcpy(ptr, &conn->abrsetup, len); + break; + + case ATM_ATTR_ABRADD: + len = sizeof(struct uni_ie_abradd); + memcpy(ptr, &conn->abradd, len); + break; + + case ATM_ATTR_CONNID: + len = sizeof(struct uni_ie_connid); + memcpy(ptr, &conn->connid, len); + break; + + case ATM_ATTR_MDCR: + len = sizeof(struct uni_ie_mdcr); + memcpy(ptr, &conn->mdcr, len); + break; + } + ptr = (u_char *)ptr + len; + } + + cc_user_ok(user, ATMRESP_ATTRS, val, total); + + CCFREE(val); +} + +/* + * Check whether the state is ok and return the connection + */ +static struct ccconn * +cc_set_check(struct ccuser *user) +{ + switch(user->state) { + + case USER_OUT_PREPARING: + case USER_IN_ARRIVED: + return (TAILQ_FIRST(&user->connq)); + + default: + return (NULL); + } +} + +/* + * Set connection attribute(s) + */ +static void +cc_attr_set(struct ccuser *user, struct ccconn *conn, uint32_t *attr, + u_int count, u_char *val, size_t vallen) +{ + size_t total, len; + u_int i; + u_char *ptr; + + /* determine the length of the total attribute buffer */ + total = 0; + ptr = val; + for (i = 0; i < count; i++) { + len = 0; + switch ((enum atm_attribute)attr[i]) { + + case ATM_ATTR_NONE: + break; + + case ATM_ATTR_BLLI_SELECTOR: + { + uint32_t sel; + + if (conn->state != CONN_OUT_PREPARING) + goto rdonly; + memcpy(&sel, ptr, sizeof(sel)); + if (sel == 0 || sel > UNI_NUM_IE_BLLI) + goto bad_val; + len = sizeof(uint32_t); + break; + } + + case ATM_ATTR_BLLI: + len = sizeof(struct uni_ie_blli); + break; + + case ATM_ATTR_BEARER: + if (conn->state != CONN_OUT_PREPARING) + goto rdonly; + len = sizeof(struct uni_ie_bearer); + break; + + case ATM_ATTR_TRAFFIC: + len = sizeof(struct uni_ie_traffic); + break; + + case ATM_ATTR_QOS: + if (conn->state != CONN_OUT_PREPARING) + goto rdonly; + len = sizeof(struct uni_ie_qos); + break; + + case ATM_ATTR_EXQOS: + len = sizeof(struct uni_ie_exqos); + break; + + case ATM_ATTR_CALLED: + goto rdonly; + + case ATM_ATTR_CALLEDSUB: + if (conn->state != CONN_OUT_PREPARING) + goto rdonly; + len = sizeof(struct uni_ie_calledsub); + break; + + case ATM_ATTR_CALLING: + if (conn->state != CONN_OUT_PREPARING) + goto rdonly; + len = sizeof(struct uni_ie_calling); + break; + + case ATM_ATTR_CALLINGSUB: + if (conn->state != CONN_OUT_PREPARING) + goto rdonly; + len = sizeof(struct uni_ie_callingsub); + break; + + case ATM_ATTR_AAL: + len = sizeof(struct uni_ie_aal); + break; + + case ATM_ATTR_EPREF: + goto rdonly; + + case ATM_ATTR_CONNED: + goto rdonly; + + case ATM_ATTR_CONNEDSUB: + goto rdonly; + + case ATM_ATTR_EETD: + len = sizeof(struct uni_ie_eetd); + break; + + case ATM_ATTR_ABRSETUP: + len = sizeof(struct uni_ie_abrsetup); + break; + + case ATM_ATTR_ABRADD: + len = sizeof(struct uni_ie_abradd); + break; + + case ATM_ATTR_CONNID: + len = sizeof(struct uni_ie_connid); + break; + + case ATM_ATTR_MDCR: + if (conn->state != CONN_OUT_PREPARING) + goto rdonly; + len = sizeof(struct uni_ie_mdcr); + break; + } + if (len == 0) { + cc_user_err(user, ATMERR_BAD_ATTR); + return; + } + total += len; + ptr += len; + } + + /* check the length */ + if (vallen != total) { + cc_user_err(user, ATMERR_BAD_ARGS); + return; + } + + ptr = val; + for (i = 0; i < count; i++) { + len = 0; + switch ((enum atm_attribute)attr[i]) { + + case ATM_ATTR_NONE: + break; + + case ATM_ATTR_BLLI_SELECTOR: + { + uint32_t sel; + + memcpy(&sel, ptr, sizeof(sel)); + conn->blli_selector = sel; + len = sizeof(uint32_t); + break; + } + + case ATM_ATTR_BLLI: + len = sizeof(struct uni_ie_blli); + memcpy(&conn->blli[conn->blli_selector - 1], ptr, len); + conn->dirty_attr |= CCDIRTY_BLLI; + break; + + case ATM_ATTR_BEARER: + len = sizeof(struct uni_ie_bearer); + memcpy(&conn->bearer, ptr, len); + break; + + case ATM_ATTR_TRAFFIC: + len = sizeof(struct uni_ie_traffic); + memcpy(&conn->traffic, ptr, len); + conn->dirty_attr |= CCDIRTY_TRAFFIC; + break; + + case ATM_ATTR_QOS: + len = sizeof(struct uni_ie_qos); + memcpy(&conn->qos, ptr, len); + break; + + case ATM_ATTR_EXQOS: + len = sizeof(struct uni_ie_exqos); + memcpy(&conn->exqos, ptr, len); + conn->dirty_attr |= CCDIRTY_EXQOS; + break; + + case ATM_ATTR_CALLED: + len = sizeof(struct uni_ie_called); + break; + + case ATM_ATTR_CALLEDSUB: + len = sizeof(struct uni_ie_calledsub); + memcpy(&conn->calledsub, ptr, len); + break; + + case ATM_ATTR_CALLING: + len = sizeof(struct uni_ie_calling); + memcpy(&conn->calling, ptr, len); + break; + + case ATM_ATTR_CALLINGSUB: + len = sizeof(struct uni_ie_callingsub); + memcpy(&conn->callingsub, ptr, len); + break; + + case ATM_ATTR_AAL: + len = sizeof(struct uni_ie_aal); + memcpy(&conn->aal, ptr, len); + conn->dirty_attr |= CCDIRTY_AAL; + break; + + case ATM_ATTR_EPREF: + len = sizeof(struct uni_ie_epref); + break; + + case ATM_ATTR_CONNED: + len = sizeof(struct uni_ie_conned); + break; + + case ATM_ATTR_CONNEDSUB: + len = sizeof(struct uni_ie_connedsub); + break; + + case ATM_ATTR_EETD: + len = sizeof(struct uni_ie_eetd); + memcpy(&conn->eetd, ptr, len); + conn->dirty_attr |= CCDIRTY_EETD; + break; + + case ATM_ATTR_ABRSETUP: + len = sizeof(struct uni_ie_abrsetup); + memcpy(&conn->abrsetup, ptr, len); + conn->dirty_attr |= CCDIRTY_ABRSETUP; + break; + + case ATM_ATTR_ABRADD: + len = sizeof(struct uni_ie_abradd); + memcpy(&conn->abradd, ptr, len); + conn->dirty_attr |= CCDIRTY_ABRADD; + break; + + case ATM_ATTR_CONNID: + len = sizeof(struct uni_ie_connid); + memcpy(&conn->connid, ptr, len); + conn->dirty_attr |= CCDIRTY_CONNID; + break; + + case ATM_ATTR_MDCR: + len = sizeof(struct uni_ie_mdcr); + memcpy(&conn->mdcr, ptr, len); + break; + } + ptr += len; + } + + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + return; + + bad_val: + cc_user_err(user, ATMERR_BAD_VALUE); + return; + + rdonly: + cc_user_err(user, ATMERR_RDONLY); + return; +} + +#ifdef CCATM_DEBUG +static const char *op_names[] = { +#define S(OP) [ATMOP_##OP] = #OP + S(RESP), + S(ABORT_CONNECTION), + S(ACCEPT_INCOMING_CALL), + S(ADD_PARTY), + S(ADD_PARTY_REJECT), + S(ADD_PARTY_SUCCESS), + S(ARRIVAL_OF_INCOMING_CALL), + S(CALL_RELEASE), + S(CONNECT_OUTGOING_CALL), + S(DROP_PARTY), + S(GET_LOCAL_PORT_INFO), + S(P2MP_CALL_ACTIVE), + S(P2P_CALL_ACTIVE), + S(PREPARE_INCOMING_CALL), + S(PREPARE_OUTGOING_CALL), + S(QUERY_CONNECTION_ATTRIBUTES), + S(REJECT_INCOMING_CALL), + S(SET_CONNECTION_ATTRIBUTES), + S(WAIT_ON_INCOMING_CALL), + S(SET_CONNECTION_ATTRIBUTES_X), + S(QUERY_CONNECTION_ATTRIBUTES_X), + S(QUERY_STATE), +#undef S +}; +#endif + +/* + * Signal from user - map this to our internal signals and queue + * the mapped signal. + */ +int +cc_user_signal(struct ccuser *user, enum atmop sig, struct uni_msg *msg) +{ + size_t len = uni_msg_len(msg); + int err = EINVAL; + + if (user->cc->log & CCLOG_USER_SIG) + cc_user_log(user, "signal %s to user", op_names[sig]); + + if ((u_int)sig > ATMOP_QUERY_STATE) + goto bad_signal; + + switch (sig) { + + case ATMOP_ABORT_CONNECTION: + if (len != sizeof(struct atm_abort_connection)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_ABORT_CONNECTION, msg); + break; + + case ATMOP_ACCEPT_INCOMING_CALL: + if (len != sizeof(struct atm_accept_incoming_call)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_ACCEPT_INCOMING, msg); + break; + + case ATMOP_ADD_PARTY: + if (len != sizeof(struct atm_add_party)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_ADD_PARTY, msg); + break; + + case ATMOP_CALL_RELEASE: + if (len != sizeof(struct atm_call_release)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_CALL_RELEASE, msg); + break; + + case ATMOP_CONNECT_OUTGOING_CALL: + if (len != sizeof(struct atm_connect_outgoing_call)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_CONNECT_OUTGOING, msg); + break; + + case ATMOP_DROP_PARTY: + if (len != sizeof(struct atm_drop_party)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_DROP_PARTY, msg); + break; + + case ATMOP_GET_LOCAL_PORT_INFO: + if (len != sizeof(struct atm_get_local_port_info)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_GET_LOCAL_PORT_INFO, msg); + break; + + case ATMOP_PREPARE_INCOMING_CALL: + if (len != sizeof(struct atm_prepare_incoming_call)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_PREPARE_INCOMING, msg); + break; + + case ATMOP_PREPARE_OUTGOING_CALL: + if (len != 0) + goto bad_len; + uni_msg_destroy(msg); + err = cc_user_sig(user, USER_SIG_PREPARE_OUTGOING, NULL, 0); + break; + + case ATMOP_QUERY_CONNECTION_ATTRIBUTES: + if (len != sizeof(struct atm_query_connection_attributes)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_QUERY_ATTR, msg); + break; + + case ATMOP_REJECT_INCOMING_CALL: + if (len != sizeof(struct atm_reject_incoming_call)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_REJECT_INCOMING, msg); + break; + + case ATMOP_SET_CONNECTION_ATTRIBUTES: + if (len < sizeof(struct atm_set_connection_attributes)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_SET_ATTR, msg); + break; + + case ATMOP_WAIT_ON_INCOMING_CALL: + if (len != 0) + goto bad_len; + uni_msg_destroy(msg); + err = cc_user_sig(user, USER_SIG_WAIT_ON_INCOMING, NULL, 0); + break; + + case ATMOP_QUERY_CONNECTION_ATTRIBUTES_X: + if (len < sizeof(struct atm_set_connection_attributes_x) || + len != offsetof(struct atm_set_connection_attributes_x, + attr) + uni_msg_rptr(msg, + struct atm_set_connection_attributes_x *)->count * + sizeof(uint32_t)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_QUERY_ATTR_X, msg); + break; + + case ATMOP_SET_CONNECTION_ATTRIBUTES_X: + if (len < sizeof(struct atm_set_connection_attributes_x)) + goto bad_len; + err = cc_user_sig_msg(user, USER_SIG_SET_ATTR_X, msg); + break; + + case ATMOP_QUERY_STATE: + if (len != 0) + goto bad_len; + uni_msg_destroy(msg); + err = cc_user_sig(user, USER_SIG_QUERY_STATE, NULL, 0); + break; + + case ATMOP_RESP: + case ATMOP_ADD_PARTY_REJECT: + case ATMOP_ADD_PARTY_SUCCESS: + case ATMOP_ARRIVAL_OF_INCOMING_CALL: + case ATMOP_P2MP_CALL_ACTIVE: + case ATMOP_P2P_CALL_ACTIVE: + bad_signal: + /* bad signal */ + if (user->cc->log & CCLOG_USER_SIG) + cc_user_log(user, "bad signal %u", sig); + cc_user_err(user, ATMERR_BAD_OP); + uni_msg_destroy(msg); + break; + } + return (err); + + bad_len: + /* bad argument length */ + if (user->cc->log & CCLOG_USER_SIG) + cc_user_log(user, "signal %s had bad len=%zu", + op_names[sig], len); + cc_user_err(user, ATMERR_BAD_ARGS); + uni_msg_destroy(msg); + return (EINVAL); +} + +/* + * Send active signal to user + */ +static void +cc_user_active(struct ccuser *user) +{ + struct ccconn *conn = TAILQ_FIRST(&user->connq); + + set_state(user, USER_ACTIVE); + if (conn->bearer.cfg == UNI_BEARER_P2P) { + struct atm_p2p_call_active *act; + + user->config = USER_P2P; + act = CCZALLOC(sizeof(*act)); + if (act == NULL) + return; + act->connid = conn->connid; + cc_user_send(user, ATMOP_P2P_CALL_ACTIVE, act, sizeof(*act)); + CCFREE(act); + } else { + struct atm_p2mp_call_active *act; + + user->config = USER_ROOT; + act = CCZALLOC(sizeof(*act)); + if (act == NULL) + return; + act->connid = conn->connid; + cc_user_send(user, ATMOP_P2MP_CALL_ACTIVE, act, sizeof(*act)); + CCFREE(act); + } +} + +/* +* Handle a signal to this user +*/ +void +cc_user_sig_handle(struct ccuser *user, enum user_sig sig, + void *arg, u_int arg2) +{ + + if (user->cc->log & CCLOG_USER_SIG) + cc_user_log(user, "signal %s to user state %s", + cc_user_sigtab[sig], stab[user->state]); + + switch (sig) { + + + case USER_SIG_PREPARE_OUTGOING: + { + /* + * Here we create a connection for the call we soon will make. + * We put this call on the list of orphaned connections, + * because we don't know yet, which port will get the + * connection. It is assigned, when the user issues the call + * to connect. + */ + struct ccconn *conn; + + if (user->state != USER_NULL) { + cc_user_err(user, ATMERR_BAD_STATE); + goto bad_state; + } + conn = cc_conn_create(user->cc); + if (conn == NULL) { + cc_user_err(user, ATMERR_NOMEM); + return; + } + set_state(user, USER_OUT_PREPARING); + cc_conn_set_state(conn, CONN_OUT_PREPARING); + conn->blli_selector = 1; + cc_connect_to_user(conn, user); + + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + return; + } + + + case USER_SIG_CONNECT_OUTGOING: + { + /* + * Request to connect that call + * + * Here we assign the connection to a port. + */ + struct uni_msg *msg = arg; + struct atm_connect_outgoing_call *req = uni_msg_rptr(msg, + struct atm_connect_outgoing_call *); + struct ccdata *priv = user->cc; + struct ccport *port; + struct ccaddr *addr; + struct ccconn *conn = TAILQ_FIRST(&user->connq); + + if (user->state != USER_OUT_PREPARING) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_STATE); + goto bad_state; + } + if (!IE_ISPRESENT(req->called)) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_ARGS); + return; + } + CCASSERT(conn->port == NULL, ("connection still on port")); + + if (TAILQ_EMPTY(&priv->port_list)) { + /* + * We have no ports - reject + */ + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_PORT); + return; + } + + /* + * Find the correct port + * Routing of outgoing calls goes to the lowest numbered port + * with a matching address or, if no address match is found to + * the lowest numbered port. + */ + TAILQ_FOREACH(port, &priv->port_list, node_link) + TAILQ_FOREACH(addr, &port->addr_list, port_link) + if (addr_matches(addr, conn)) + break; + + if (port == NULL) + port = TAILQ_FIRST(&priv->port_list); + + cc_conn_ins_port(conn, port); + conn->called = req->called; + uni_msg_destroy(msg); + + /* + * Now move the state + */ + set_state(user, USER_OUT_WAIT_OK); + cc_conn_sig(conn, CONN_SIG_CONNECT_OUTGOING, NULL); + + return; + } + + + case USER_SIG_CONNECT_OUTGOING_ERR: + switch (user->state) { + + case USER_OUT_WAIT_OK: + set_state(user, USER_OUT_PREPARING); + cc_user_err(user, arg2); + break; + + case USER_REL_WAIT_CONN: + { + struct ccconn *conn; + + conn = TAILQ_FIRST(&user->connq); + if (conn != NULL) { + cc_disconnect_from_user(conn); + cc_conn_destroy(conn); + } + + cc_user_reset(user); + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + break; + } + + default: + goto bad_state; + } + return; + + + case USER_SIG_CONNECT_OUTGOING_OK: + switch (user->state) { + + case USER_OUT_WAIT_OK: + set_state(user, USER_OUT_WAIT_CONF); + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + break; + + case USER_REL_WAIT_CONN: + set_state(user, USER_REL_WAIT_SCONF); + break; + + default: + goto bad_state; + } + return; + + + case USER_SIG_SETUP_CONFIRM: + /* + * SETUP.confirm from UNI stack. + */ + switch (user->state) { + + case USER_OUT_WAIT_CONF: + cc_user_active(user); + break; + + case USER_REL_WAIT_SCONF: + /* now try to release */ + set_state(user, USER_REL_WAIT_CONF); + cc_conn_sig(TAILQ_FIRST(&user->connq), + CONN_SIG_RELEASE, NULL); + break; + + default: + goto bad_state; + } + return; + + + case USER_SIG_PREPARE_INCOMING: + { + struct uni_msg *msg = arg; + struct ccuser *ptr; + struct atm_prepare_incoming_call *prep = uni_msg_rptr(msg, + struct atm_prepare_incoming_call *); + + if (user->state != USER_NULL) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_STATE); + goto bad_state; + } + + /* + * Check the SAP + */ + if (unisve_check_sap(&prep->sap) != UNISVE_OK) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_SAP); + return; + } + + /* + * Loop through all incoming calls and check whether there + * is an overlap in SAP space. + */ + LIST_FOREACH(ptr, &user->cc->user_list, node_link) { + if (check_overlap(ptr, &prep->sap)) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_OVERLAP); + return; + } + } + + /* + * Save info and set state + */ + user->sap = CCZALLOC(sizeof(struct uni_sap)); + if (user->sap == NULL) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_NOMEM); + return; + } + *user->sap = prep->sap; + user->queue_max = prep->queue_size; + user->queue_act = 0; + uni_msg_destroy(msg); + + set_state(user, USER_IN_PREPARING); + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + + return; + } + + + case USER_SIG_WAIT_ON_INCOMING: + if (user->state != USER_IN_PREPARING) { + cc_user_err(user, ATMERR_BAD_STATE); + goto bad_state; + } + + set_state(user, USER_IN_WAITING); + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + return; + + + case USER_SIG_SETUP_IND: + /* + * New connection queued up in the queue. If this is the + * first one, inform the application of the arrival. + */ + switch (user->state) { + + case USER_IN_WAITING: + do_arrival(user); + break; + + case USER_IN_ARRIVED: + case USER_IN_WAIT_REJ: + case USER_IN_WAIT_ACC: + break; + + default: + goto bad_state; + } + return; + + + case USER_SIG_REJECT_INCOMING: + { + /* + * User rejects call. This is done on the OLD user + * (i.e. the one sending the arrival). + */ + struct uni_msg *msg = arg; + struct atm_reject_incoming_call *rej = uni_msg_rptr(msg, + struct atm_reject_incoming_call *); + struct ccconn *conn = TAILQ_FIRST(&user->connq); + + if (user->state != USER_IN_ARRIVED) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_STATE); + goto bad_state; + } + if (user->aborted) { + /* connection has disappeared. Send an ok + * to the user and lock whether there is another + * connection at this endpoint */ + uni_msg_destroy(msg); + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + + set_state(user, USER_IN_WAITING); + do_arrival(user); + return; + } + conn->cause[0] = rej->cause; + memset(&conn->cause[1], 0, sizeof(conn->cause[1])); + uni_msg_destroy(msg); + + set_state(user, USER_IN_WAIT_REJ); + cc_conn_sig(conn, CONN_SIG_REJECT, NULL); + + return; + } + + + case USER_SIG_REJECT_OK: + if (user->state != USER_IN_WAIT_REJ) + goto bad_state; + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + + set_state(user, USER_IN_WAITING); + do_arrival(user); + return; + + + case USER_SIG_REJECT_ERR: + if (user->state != USER_IN_WAIT_REJ) + goto bad_state; + cc_user_err(user, arg2); + + if (arg == NULL) + set_state(user, USER_IN_ARRIVED); + else { + set_state(user, USER_IN_WAITING); + do_arrival(user); + } + return; + + + case USER_SIG_ACCEPT_INCOMING: + { + /* + * User accepts call. This is done on the OLD user (i.e. the one + * sending the arrival), the message contains a pointer to the + * new endpoint. + */ + struct uni_msg *msg = arg; + struct atm_accept_incoming_call *acc = + uni_msg_rptr(msg, struct atm_accept_incoming_call *); + struct ccuser *newep; + + if (user->state != USER_IN_ARRIVED) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_STATE); + return; + } + if (user->aborted) { + /* connection has disappeared. Send an error + * to the user and lock whether there is another + * connection at this endpoint */ + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_PREVIOUSLY_ABORTED); + + set_state(user, USER_IN_WAITING); + do_arrival(user); + return; + } + acc->newep[sizeof(acc->newep) - 1] = '\0'; + + LIST_FOREACH(newep, &user->cc->user_list, node_link) + if (strcmp(acc->newep, newep->name) == 0) + break; + uni_msg_destroy(msg); + + if (newep == NULL) { + cc_user_err(user, ATMERR_BAD_ENDPOINT); + return; + } + + if (newep->state != USER_NULL || newep->accepted != NULL) { + cc_user_err(user, ATMERR_BAD_STATE); + return; + } + + set_state(user, USER_IN_WAIT_ACC); + cc_conn_sig(TAILQ_FIRST(&user->connq), CONN_SIG_ACCEPT, newep); + + return; + } + + + case USER_SIG_ACCEPT_OK: + if (user->state != USER_IN_WAIT_ACC) + goto bad_state; + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + + set_state(user, USER_IN_WAITING); + do_arrival(user); + return; + + + case USER_SIG_ACCEPT_ERR: + if (user->state != USER_IN_WAIT_ACC) + goto bad_state; + cc_user_err(user, arg2); + + if (arg == NULL) { + /* arg used as flag! */ + set_state(user, USER_IN_ARRIVED); + } else { + set_state(user, USER_IN_WAITING); + do_arrival(user); + } + return; + + + case USER_SIG_ACCEPTING: + if (user->state != USER_NULL) + goto bad_state; + set_state(user, USER_IN_ACCEPTING); + return; + + + case USER_SIG_SETUP_COMPL: + { + struct ccconn *conn = TAILQ_FIRST(&user->connq); + + if (user->state != USER_IN_ACCEPTING) + goto bad_state; + + user->state = USER_ACTIVE; + if (conn->bearer.cfg == UNI_BEARER_P2P) { + struct atm_p2p_call_active *act; + + user->config = USER_P2P; + act = CCZALLOC(sizeof(*act)); + if (act == NULL) + return; + act->connid = conn->connid; + cc_user_send(user, ATMOP_P2P_CALL_ACTIVE, + act, sizeof(*act)); + CCFREE(act); + } else { + struct atm_p2mp_call_active *act; + + user->config = USER_LEAF; + act = CCZALLOC(sizeof(*act)); + if (act == NULL) + return; + act->connid = conn->connid; + cc_user_send(user, ATMOP_P2MP_CALL_ACTIVE, + act, sizeof(*act)); + CCFREE(act); + } + return; + } + + + case USER_SIG_CALL_RELEASE: + { + struct uni_msg *msg = arg; + struct atm_call_release *api = uni_msg_rptr(msg, + struct atm_call_release *); + struct ccconn *conn; + + conn = TAILQ_FIRST(&user->connq); + switch (user->state) { + + case USER_OUT_WAIT_OK: /* U2/A3 */ + /* wait for CONN_OK first */ + conn->cause[0] = api->cause[0]; + conn->cause[1] = api->cause[1]; + set_state(user, USER_REL_WAIT_CONN); + break; + + case USER_OUT_WAIT_CONF: /* U3/A3 */ + /* wait for SETUP.confirm first */ + conn->cause[0] = api->cause[0]; + conn->cause[1] = api->cause[1]; + set_state(user, USER_REL_WAIT_SCONF); + break; + + case USER_IN_ACCEPTING: /* U11/A7 */ + conn->cause[0] = api->cause[0]; + conn->cause[1] = api->cause[1]; + set_state(user, USER_REL_WAIT_SCOMP); + cc_conn_sig(conn, CONN_SIG_RELEASE, NULL); + break; + + case USER_ACTIVE: /* U4/A8,A9,A10 */ + conn->cause[0] = api->cause[0]; + conn->cause[1] = api->cause[1]; + set_state(user, USER_REL_WAIT); + cc_conn_sig(conn, CONN_SIG_RELEASE, NULL); + break; + + default: + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_STATE); + goto bad_state; + } + uni_msg_destroy(msg); + return; + } + + + case USER_SIG_RELEASE_CONFIRM: + { + struct atm_call_release *ind; + + switch (user->state) { + + case USER_OUT_WAIT_CONF: /* U3/A3 */ + case USER_ACTIVE: /* U4/A8,A9,A10 */ + cc_user_reset(user); + break; + + case USER_REL_WAIT: /* U5 /A8,A9,A10 */ + case USER_REL_WAIT_SCOMP: /* U12/A7 */ + case USER_REL_WAIT_SCONF: /* U13/A3 */ + case USER_REL_WAIT_CONF: /* U14/A3 */ + cc_user_reset(user); + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + return; + + case USER_IN_ACCEPTING: /* U11/A7 */ + cc_user_reset(user); + break; + + default: + goto bad_state; + } + + ind = CCZALLOC(sizeof(*ind)); + if (ind == NULL) + return; + memcpy(ind->cause, user->cause, sizeof(ind->cause)); + cc_user_send(user, ATMOP_CALL_RELEASE, ind, sizeof(*ind)); + CCFREE(ind); + return; + } + + + case USER_SIG_RELEASE_ERR: + switch (user->state) { + + case USER_REL_WAIT: /* U5/A8,A9,A10 */ + set_state(user, USER_ACTIVE); + cc_user_err(user, ATM_MKUNIERR(arg2)); + break; + + case USER_REL_WAIT_CONF: /* U14/A3 */ + cc_user_err(user, ATM_MKUNIERR(arg2)); + cc_user_active(user); + break; + + case USER_REL_WAIT_SCOMP: /* U12/A7 */ + set_state(user, USER_IN_ACCEPTING); + cc_user_err(user, ATM_MKUNIERR(arg2)); + break; + + default: + goto bad_state; + } + return; + + + case USER_SIG_ADD_PARTY: + { + struct uni_msg *msg = arg; + struct atm_add_party *add = uni_msg_rptr(msg, + struct atm_add_party *); + struct ccconn *conn; + + if (user->state != USER_ACTIVE || user->config != USER_ROOT) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_STATE); + return; + } + + if (add->leaf_ident == 0 || add->leaf_ident >= 32786) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_LEAF_IDENT); + return; + } + + conn = TAILQ_FIRST(&user->connq); + conn->called = add->called; + + cc_conn_sig(conn, CONN_SIG_ADD_PARTY, + (void *)(uintptr_t)add->leaf_ident); + + uni_msg_destroy(msg); + return; + } + + + case USER_SIG_ADD_PARTY_ERR: + if (user->state != USER_ACTIVE) + goto bad_state; + cc_user_err(user, arg2); + return; + + + case USER_SIG_ADD_PARTY_OK: + if (user->state != USER_ACTIVE) + goto bad_state; + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + return; + + + case USER_SIG_ADD_PARTY_ACK: + { + u_int leaf_ident = arg2; + struct atm_add_party_success *succ; + + if (user->state != USER_ACTIVE) + goto bad_state; + + succ = CCZALLOC(sizeof(*succ)); + if (succ == NULL) + return; + + succ->leaf_ident = leaf_ident; + cc_user_send(user, ATMOP_ADD_PARTY_SUCCESS, + succ, sizeof(*succ)); + + CCFREE(succ); + return; + } + + + case USER_SIG_ADD_PARTY_REJ: + { + u_int leaf_ident = arg2; + struct atm_add_party_reject *reject; + + if (user->state != USER_ACTIVE) + goto bad_state; + + reject = CCZALLOC(sizeof(*reject)); + if (reject == NULL) + return; + + reject->leaf_ident = leaf_ident; + reject->cause = user->cause[0]; + cc_user_send(user, ATMOP_ADD_PARTY_REJECT, + reject, sizeof(*reject)); + + CCFREE(reject); + return; + } + + + case USER_SIG_DROP_PARTY: + { + struct uni_msg *msg = arg; + struct atm_drop_party *drop = uni_msg_rptr(msg, + struct atm_drop_party *); + struct ccconn *conn; + + if (user->state != USER_ACTIVE || user->config != USER_ROOT) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_STATE); + return; + } + + if (drop->leaf_ident >= 32786) { + uni_msg_destroy(msg); + cc_user_err(user, ATMERR_BAD_LEAF_IDENT); + return; + } + + conn = TAILQ_FIRST(&user->connq); + conn->cause[0] = drop->cause; + memset(&conn->cause[1], 0, sizeof(conn->cause[1])); + + cc_conn_sig(conn, CONN_SIG_DROP_PARTY, + (void *)(uintptr_t)drop->leaf_ident); + + uni_msg_destroy(msg); + return; + } + + + case USER_SIG_DROP_PARTY_ERR: + if (user->state != USER_ACTIVE) + goto bad_state; + cc_user_err(user, arg2); + return; + + + case USER_SIG_DROP_PARTY_OK: + if (user->state != USER_ACTIVE) + goto bad_state; + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + return; + + + case USER_SIG_DROP_PARTY_IND: + { + u_int leaf_ident = arg2; + struct atm_drop_party *drop; + + if (user->state != USER_ACTIVE) + goto bad_state; + + drop = CCZALLOC(sizeof(*drop)); + if (drop == NULL) + return; + + drop->leaf_ident = leaf_ident; + drop->cause = user->cause[0]; + cc_user_send(user, ATMOP_DROP_PARTY, drop, sizeof(*drop)); + + CCFREE(drop); + return; + } + + + case USER_SIG_QUERY_ATTR: + { + struct uni_msg *msg = arg; + struct atm_query_connection_attributes *req; + struct ccconn *conn; + + if (user->aborted) { + cc_user_err(user, ATMERR_PREVIOUSLY_ABORTED); + uni_msg_destroy(msg); + return; + } + conn = cc_query_check(user); + if (conn == NULL) { + cc_user_err(user, ATMERR_BAD_STATE); + uni_msg_destroy(msg); + return; + } + req = uni_msg_rptr(msg, + struct atm_query_connection_attributes *); + cc_attr_query(user, conn, &req->attr, 1); + uni_msg_destroy(msg); + return; + } + + case USER_SIG_QUERY_ATTR_X: + { + struct uni_msg *msg = arg; + struct atm_query_connection_attributes_x *req; + struct ccconn *conn; + + conn = cc_query_check(user); + if (conn == NULL) { + cc_user_err(user, ATMERR_BAD_STATE); + uni_msg_destroy(msg); + return; + } + req = uni_msg_rptr(msg, + struct atm_query_connection_attributes_x *); + cc_attr_query(user, conn, req->attr, req->count); + uni_msg_destroy(msg); + return; + } + + case USER_SIG_SET_ATTR: + { + struct uni_msg *msg = arg; + struct atm_set_connection_attributes *req; + struct ccconn *conn; + + if (user->aborted) { + cc_user_err(user, ATMERR_PREVIOUSLY_ABORTED); + uni_msg_destroy(msg); + return; + } + conn = cc_set_check(user); + if (conn == NULL) { + cc_user_err(user, ATMERR_BAD_STATE); + uni_msg_destroy(msg); + return; + } + req = uni_msg_rptr(msg, struct atm_set_connection_attributes *); + cc_attr_set(user, conn, &req->attr, 1, (u_char *)(req + 1), + uni_msg_len(msg) - sizeof(*req)); + uni_msg_destroy(msg); + return; + } + + case USER_SIG_SET_ATTR_X: + { + struct uni_msg *msg = arg; + struct atm_set_connection_attributes_x *req; + struct ccconn *conn; + + conn = cc_set_check(user); + if (conn == NULL) { + cc_user_err(user, ATMERR_BAD_STATE); + uni_msg_destroy(msg); + return; + } + req = uni_msg_rptr(msg, + struct atm_set_connection_attributes_x *); + cc_attr_set(user, conn, req->attr, req->count, + (u_char *)req->attr + req->count * sizeof(req->attr[0]), + uni_msg_len(msg) - + offsetof(struct atm_set_connection_attributes_x, attr) - + req->count * sizeof(req->attr[0])); + uni_msg_destroy(msg); + return; + } + + case USER_SIG_QUERY_STATE: + { + struct atm_epstate state; + + strcpy(state.name, user->name); + switch (user->state) { + + case USER_NULL: + if (user->accepted != NULL) + state.state = ATM_A7; + else + state.state = ATM_A1; + break; + + case USER_OUT_PREPARING: + state.state = ATM_A2; + break; + + case USER_OUT_WAIT_OK: + case USER_OUT_WAIT_CONF: + case USER_REL_WAIT_SCONF: + case USER_REL_WAIT_CONF: + case USER_REL_WAIT_CONN: + state.state = ATM_A3; + break; + + case USER_ACTIVE: + case USER_REL_WAIT: + switch (user->config) { + + case USER_P2P: + state.state = ATM_A8; + break; + + case USER_ROOT: + state.state = ATM_A9; + break; + + case USER_LEAF: + state.state = ATM_A10; + break; + } + break; + + case USER_IN_PREPARING: + state.state = ATM_A4; + break; + + case USER_IN_WAITING: + state.state = ATM_A5; + break; + + case USER_IN_ARRIVED: + case USER_IN_WAIT_REJ: + case USER_IN_WAIT_ACC: + state.state = ATM_A6; + break; + + case USER_IN_ACCEPTING: + case USER_REL_WAIT_SCOMP: + state.state = ATM_A7; + break; + } + cc_user_ok(user, ATMRESP_STATE, &state, sizeof(state)); + return; + } + + case USER_SIG_GET_LOCAL_PORT_INFO: + { + struct uni_msg *msg = arg; + struct atm_port_list *list; + size_t list_len; + + list = cc_get_local_port_info(user->cc, + uni_msg_rptr(msg, struct atm_get_local_port_info *)->port, + &list_len); + uni_msg_destroy(msg); + if (list == NULL) { + cc_user_err(user, ATMERR_NOMEM); + return; + } + cc_user_ok(user, ATMRESP_PORTS, list, list_len); + CCFREE(list); + return; + } + + case USER_SIG_ABORT_CONNECTION: + { + struct uni_msg *msg = arg; + struct atm_abort_connection *abo = uni_msg_rptr(msg, + struct atm_abort_connection *); + + cc_user_abort(user, &abo->cause); + uni_msg_destroy(msg); + cc_user_ok(user, ATMRESP_NONE, NULL, 0); + return; + } + + } + if (user->cc->log & CCLOG_USER_SIG) + cc_user_log(user, "bad signal=%u in state=%u", + sig, user->state); + return; + + bad_state: + if (user->cc->log & CCLOG_USER_SIG) + cc_user_log(user, "bad state=%u for signal=%u", + user->state, sig); + return; +} diff --git a/sys/contrib/ngatm/netnatm/api/ccatm.h b/sys/contrib/ngatm/netnatm/api/ccatm.h new file mode 100644 index 000000000000..1b4a179a3348 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/api/ccatm.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2003-2004 + * Hartmut Brandt + * 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/ccatm.h,v 1.1 2004/07/08 08:21:58 brandt Exp $ + * + * ATM API as defined per af-saa-0108 + * + * Interface to the supporting code. + */ + +#ifndef _API_CCATM_H_ +#define _API_CCATM_H_ + +struct ccuser; +struct ccconn; +struct ccport; +struct ccdata; + +struct cc_funcs { + /* send signal to API user */ + void (*send_user)(struct ccuser *, void *, u_int, void *, size_t); + + /* respond API user */ + void (*respond_user)(struct ccuser *, void *, int, u_int, + void *, size_t); + + /* send signal to uni for connection */ + void (*send_uni)(struct ccconn *, void *, u_int, u_int, + struct uni_msg *); + + /* send global signal to uni */ + void (*send_uni_glob)(struct ccport *, void *, u_int, u_int, + struct uni_msg *); + + /* log a message */ + void (*log)(const char *, ...); +}; + +enum { + CCLOG_USER_STATE = 0x00000001, + CCLOG_USER_INST = 0x00000002, + CCLOG_USER_SIG = 0x00000004, + CCLOG_CONN_STATE = 0x00000010, + CCLOG_CONN_INST = 0x00000020, + CCLOG_CONN_SIG = 0x00000040, + CCLOG_PARTY_STATE = 0x00000100, + CCLOG_PARTY_INST = 0x00000200, + CCLOG_PARTY_SIG = 0x00000400, + CCLOG_SIGS = 0x00001000, +}; + +/* instance handling */ +struct ccdata *cc_create(const struct cc_funcs *); +void cc_destroy(struct ccdata *); +void cc_reset(struct ccdata *); + +/* input a response from the UNI layer to CC */ +int cc_uni_response(struct ccport *, u_int cookie, u_int reason, u_int state); + +/* Signal from UNI on this port */ +int cc_uni_signal(struct ccport *, u_int cookie, u_int sig, struct uni_msg *); + +/* retrieve addresses */ +int cc_get_addrs(struct ccdata *, u_int, struct uni_addr **, u_int **, u_int *); + +/* dump state */ +typedef int (*cc_dump_f)(struct ccdata *, void *, const char *); +int cc_dump(struct ccdata *, size_t, cc_dump_f, void *); + +/* start/stop port */ +int cc_port_stop(struct ccdata *, u_int); +int cc_port_start(struct ccdata *, u_int); + +/* is port running? */ +int cc_port_isrunning(struct ccdata *, u_int, int *); + +/* return port number */ +u_int cc_port_no(struct ccport *); + +/* Clear address and prefix information from the named port. */ +int cc_port_clear(struct ccdata *, u_int); + +/* Address registered. */ +int cc_addr_register(struct ccdata *, u_int, const struct uni_addr *); + +/* Address unregistered. */ +int cc_addr_unregister(struct ccdata *, u_int, const struct uni_addr *); + +/* get port info */ +int cc_port_get_param(struct ccdata *, u_int, struct atm_port_info *); + +/* set port info */ +int cc_port_set_param(struct ccdata *, const struct atm_port_info *); + +/* get port list */ +int cc_port_getlist(struct ccdata *, u_int *, u_int **); + +/* create a port */ +struct ccport *cc_port_create(struct ccdata *, void *, u_int); + +/* destroy a port */ +void cc_port_destroy(struct ccport *, int); + +/* New endpoint created */ +struct ccuser *cc_user_create(struct ccdata *, void *, const char *); + +/* destroy user endpoint */ +void cc_user_destroy(struct ccuser *); + +/* signal from user */ +int cc_user_signal(struct ccuser *, u_int, struct uni_msg *); + +/* Management is given up on this node. */ +void cc_unmanage(struct ccdata *); + +/* handle all queued signals */ +void cc_work(struct ccdata *); + +/* set/get logging flags */ +void cc_set_log(struct ccdata *, u_int); +u_int cc_get_log(const struct ccdata *); + +/* get extended status */ +int cc_get_extended_status(const struct ccdata *, struct atm_exstatus *, + struct atm_exstatus_ep **, struct atm_exstatus_port **, + struct atm_exstatus_conn **, struct atm_exstatus_party **); + +#endif diff --git a/sys/contrib/ngatm/netnatm/api/ccpriv.h b/sys/contrib/ngatm/netnatm/api/ccpriv.h new file mode 100644 index 000000000000..c0f30750fc10 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/api/ccpriv.h @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2003-2004 + * Hartmut Brandt + * 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/ccpriv.h,v 1.2 2005/05/23 11:49:17 brandt_h Exp $ + * + * ATM API as defined per af-saa-0108 + * + * Private declarations. + */ +#ifdef _KERNEL +#ifdef __FreeBSD__ +#include <netgraph/atm/ccatm/ng_ccatm_cust.h> +#endif +#else /* !_KERNEL */ +#include "cccust.h" +#endif + +struct ccuser; +struct ccconn; +struct ccaddr; +struct ccport; +struct ccdata; +struct ccsig; +struct ccparty; + +LIST_HEAD(ccuser_list, ccuser); +LIST_HEAD(ccconn_list, ccconn); +TAILQ_HEAD(ccaddr_list, ccaddr); +TAILQ_HEAD(ccport_list, ccport); +TAILQ_HEAD(ccsig_list, ccsig); +LIST_HEAD(ccparty_list, ccparty); + +/* + * Private node data. + */ +struct ccdata { + struct ccuser_list user_list; /* instance list */ + struct ccport_list port_list; /* list of ports */ + struct ccconn_list orphaned_conns; /* list of connections */ + struct ccsig_list sigs; /* current signals */ + struct ccsig_list def_sigs; /* deferred signals */ + struct ccsig_list free_sigs; /* free signals */ + + const struct cc_funcs *funcs; + uint32_t cookie; /* cookie generator */ + u_int log; /* logging flags */ +}; + +/* retrieve info on local ports */ +struct atm_port_list *cc_get_local_port_info(struct ccdata *, + u_int, size_t *); + +/* log */ +#ifdef CCATM_DEBUG +#if defined(__GNUC__) && __GNUC__ < 3 +#define cc_log(CC, FMT, ARGS...) do { \ + (CC)->funcs->log("%s (data=%p): " FMT, __FUNCTION__, \ + (CC) , ## ARGS); \ + } while (0) +#else +#define cc_log(CC, FMT, ...) do { \ + (CC)->funcs->log("%s (data=%p): " FMT, __func__, \ + (CC), __VA_ARGS__); \ + } while (0) +#endif +#else +#if defined(__GNUC__) && __GNUC__ < 3 +#define cc_log(CC, FMT, ARGS...) do { } while (0) +#else +#define cc_log(CC, FMT, ...) do { } while (0) +#endif +#endif + +/* + * structure to remember cookies for outstanding requests + * we also remember the request itself but don't use it. + */ +struct ccreq { + TAILQ_ENTRY(ccreq) link; + uint32_t cookie; + uint32_t req; + struct ccconn *conn; +}; +TAILQ_HEAD(ccreq_list, ccreq); + +/* + * Port data. Each port has one UNI stack below. + * The port number is in param.port. The number is assigned when the + * hook to the uni is connected. This hook has the name 'uni<port>'. + */ +struct ccport { + void *uarg; /* hook to UNI protocol */ + struct ccdata *cc; /* back pointer to node */ + enum { + CCPORT_STOPPED, /* halted */ + CCPORT_RUNNING, /* ok */ + } admin; /* admin status */ + struct ccconn_list conn_list; /* list of connections */ + struct ccaddr_list addr_list; /* list of network addresses */ + struct atm_port_info param; /* parameters */ + + /* list of outstanding requests */ + struct ccreq_list cookies; + + TAILQ_ENTRY(ccport) node_link; +}; + +#ifdef CCATM_DEBUG +#if defined(__GNUC__) && __GNUC__ < 3 +#define cc_port_log(P, FMT, ARGS...) do { \ + (P)->cc->funcs->log("%s (port=%p/%u): " FMT, __FUNCTION__, \ + (P), (P)->param.port , ## ARGS); \ + } while (0) +#else +#define cc_port_log(P, FMT, ...) do { \ + (P)->cc->funcs->log("%s (port=%p/%u): " FMT, __func__, \ + (P), (P)->param.port, __VA_ARGS__); \ + } while (0) +#endif +#else +#if defined(__GNUC__) && __GNUC__ < 3 +#define cc_port_log(P, FMT, ARGS...) do { } while (0) +#else +#define cc_port_log(P, FMT, ...) do { } while (0) +#endif +#endif + +#define CONN_STATES \ + DEF(CONN_NULL) /* C0 */ \ + DEF(CONN_OUT_PREPARING) /* C1 */ \ + DEF(CONN_OUT_WAIT_CREATE) /* C2 */ \ + DEF(CONN_OUT_WAIT_OK) /* C3 */ \ + DEF(CONN_OUT_WAIT_CONF) /* C4 */ \ + \ + DEF(CONN_ACTIVE) /* C5 */ \ + \ + DEF(CONN_IN_PREPARING) /* C10 */ \ + DEF(CONN_IN_WAITING) /* C21 */ \ + DEF(CONN_IN_ARRIVED) /* C11 */ \ + DEF(CONN_IN_WAIT_ACCEPT_OK) /* C12 */ \ + DEF(CONN_IN_WAIT_COMPL) /* C13 */ \ + \ + DEF(CONN_REJ_WAIT_OK) /* C14 */ \ + DEF(CONN_REL_IN_WAIT_OK) /* C15 */ \ + DEF(CONN_REL_WAIT_OK) /* C20 */ \ + \ + DEF(CONN_AB_WAIT_REQ_OK) /* C33 */ \ + DEF(CONN_AB_WAIT_RESP_OK) /* C34 */ \ + DEF(CONN_AB_FLUSH_IND) /* C35 */ \ + DEF(CONN_OUT_WAIT_DESTROY) /* C37 */ + +enum conn_state { +#define DEF(N) N, + CONN_STATES +#undef DEF +}; + +#define CONN_SIGS \ + DEF(CONNECT_OUTGOING) /* U */ \ + DEF(ARRIVAL) /* U */ \ + DEF(RELEASE) /* U */ \ + DEF(REJECT) /* U */ \ + DEF(ACCEPT) /* U newuser */ \ + DEF(ADD_PARTY) /* U ident */ \ + DEF(DROP_PARTY) /* U ident */ \ + DEF(USER_ABORT) /* U */ \ + \ + DEF(CREATED) /* P msg */ \ + DEF(DESTROYED) /* P */ \ + DEF(SETUP_CONFIRM) /* P msg */ \ + DEF(SETUP_IND) /* P msg */ \ + DEF(SETUP_COMPL) /* P msg */ \ + DEF(PROC_IND) /* P msg */ \ + DEF(ALERTING_IND) /* P msg */ \ + DEF(REL_CONF) /* P msg */ \ + DEF(REL_IND) /* P msg */ \ + DEF(PARTY_CREATED) /* P msg */ \ + DEF(PARTY_DESTROYED) /* P msg */ \ + DEF(PARTY_ALERTING_IND) /* P msg */ \ + DEF(PARTY_ADD_ACK_IND) /* P msg */ \ + DEF(PARTY_ADD_REJ_IND) /* P msg */ \ + DEF(DROP_PARTY_IND) /* P msg */ \ + DEF(DROP_PARTY_ACK_IND) /* P msg */ \ + \ + DEF(OK) /* P msg */ \ + DEF(ERROR) /* P msg */ + +enum conn_sig { +#define DEF(NAME) CONN_SIG_##NAME, +CONN_SIGS +#undef DEF +}; +extern const char *const cc_conn_sigtab[]; + +/* + * This describes a connection and must be in sync with the UNI + * stack. + */ +struct ccconn { + enum conn_state state; /* API state of the connection */ + struct ccdata *cc; /* owner node */ + struct ccport *port; /* the port we belong to */ + struct ccuser *user; /* user instance we belong to */ + TAILQ_ENTRY(ccconn) connq_link; /* queue of the owner */ + LIST_ENTRY(ccconn) port_link; /* link in list of port */ + struct uni_cref cref; + uint8_t reason; + struct ccuser *acceptor; + + /* attributes */ + uint32_t blli_selector; + struct uni_ie_blli blli[UNI_NUM_IE_BLLI]; + + struct uni_ie_bearer bearer; + struct uni_ie_traffic traffic; + struct uni_ie_qos qos; + struct uni_ie_exqos exqos; + struct uni_ie_called called; + struct uni_ie_calledsub calledsub; + struct uni_ie_aal aal; + struct uni_ie_epref epref; + struct uni_ie_conned conned; + struct uni_ie_connedsub connedsub; + struct uni_ie_eetd eetd; + struct uni_ie_abrsetup abrsetup; + struct uni_ie_abradd abradd; + struct uni_ie_mdcr mdcr; + + struct uni_ie_calling calling; + struct uni_ie_callingsub callingsub; + struct uni_ie_connid connid; + struct uni_ie_tns tns[UNI_NUM_IE_TNS]; + struct uni_ie_atraffic atraffic; + struct uni_ie_mintraffic mintraffic; + struct uni_ie_cscope cscope; + struct uni_ie_bhli bhli; + + /* bit mask of written attributes in A6 */ + u_int dirty_attr; + + struct uni_ie_cause cause[2]; + + struct ccparty_list parties; +}; + +/* dirty attribute mask values */ +enum { + CCDIRTY_AAL = 0x0001, + CCDIRTY_BLLI = 0x0002, + CCDIRTY_CONNID = 0x0004, + CCDIRTY_NOTIFY = 0x0008, /* XXX */ + CCDIRTY_EETD = 0x0010, + CCDIRTY_GIT = 0x0020, /* XXX */ + CCDIRTY_UU = 0x0040, /* XXX */ + CCDIRTY_TRAFFIC = 0x0080, + CCDIRTY_EXQOS = 0x0100, + CCDIRTY_ABRSETUP = 0x0200, + CCDIRTY_ABRADD = 0x0400, +}; + +/* set conn to new state */ +void cc_conn_set_state(struct ccconn *, enum conn_state); + +/* return string for state */ +const char *cc_conn_state2str(u_int); + +/* connect connection to user */ +void cc_connect_to_user(struct ccconn *, struct ccuser *); + +/* disconnect from the user */ +void cc_disconnect_from_user(struct ccconn *); + +/* abort the connection */ +void cc_conn_abort(struct ccconn *, int); + +/* destroy a connection */ +void cc_conn_destroy(struct ccconn *); + +/* create a connection */ +struct ccconn *cc_conn_create(struct ccdata *); + +/* assign to port */ +void cc_conn_ins_port(struct ccconn *, struct ccport *); + +/* remove from port */ +void cc_conn_rem_port(struct ccconn *); + +/* dispatch a connection to a user or reject it */ +void cc_conn_dispatch(struct ccconn *); + +/* disconnect from acceptor */ +void cc_conn_reset_acceptor(struct ccconn *); + +/* log on a connection */ +#ifdef CCATM_DEBUG +#if defined(__GNUC__) && __GNUC__ < 3 +#define cc_conn_log(C, FMT, ARGS...) do { \ + (C)->cc->funcs->log("%s (conn=%p): " FMT, __FUNCTION__, \ + (C) , ## ARGS); \ + } while (0) +#else +#define cc_conn_log(C, FMT, ...) do { \ + (C)->cc->funcs->log("%s (conn=%p): " FMT, __func__, \ + (C), __VA_ARGS__); \ + } while (0) +#endif +#else +#if defined(__GNUC__) && __GNUC__ < 3 +#define cc_conn_log(C, FMT, ARGS...) do { } while (0) +#else +#define cc_conn_log(C, FMT, ...) do { } while (0) +#endif +#endif + +/* handle signal to connection */ +void cc_conn_sig_handle(struct ccconn *, enum conn_sig, void *arg, u_int iarg); + +/* + * Mp connection parties + */ +#define PARTY_STATES \ + DEF(NULL) /* 0 created */ \ + DEF(ACTIVE) /* 1 active */ \ + DEF(ADD_WAIT_CREATE) /* 2 wait for PARTY_CREATE */ \ + DEF(ADD_WAIT_OK) /* 3 wait for OK for ADD.request */ \ + DEF(ADD_WAIT_ACK) /* 4 wait for ADD.ack/rej */ \ + DEF(DROP_WAIT_OK) /* 5 wait for OK for DROP.request */ \ + DEF(DROP_WAIT_ACK) /* 6 wait for DROP.ack */ \ + DEF(WAIT_DESTROY) /* 7 wait for destroy */ \ + DEF(WAIT_SETUP_COMPL) /* 8 wait for setup.complete */ \ + DEF(WAIT_DROP_ACK_OK) /* 9 wait for OK for DROP_ACK.request */\ + DEF(WAIT_SETUP_CONF) /* 10 wait for setup.confirm */ \ + DEF(ADD_DROP_WAIT_OK) /* 11 wait for ok to DROP.request */ \ + DEF(ADD_DROPACK_WAIT_OK)/* 12 wait for ok to DROP_ACK.req */ + +enum party_state { +#define DEF(N) PARTY_##N, +PARTY_STATES +#undef DEF +}; + +struct ccparty { + struct ccconn *conn; /* owner */ + LIST_ENTRY(ccparty) link; + enum party_state state; + struct uni_ie_called called; + struct uni_ie_epref epref; +}; + +/* set party to new state */ +void cc_party_set_state(struct ccparty *, enum party_state); + +/* return string for state */ +const char *cc_party_state2str(u_int); + +/* create new party */ +struct ccparty *cc_party_create(struct ccconn *, u_int ident, u_int flag); + +/* log on a party */ +#ifdef CCATM_DEBUG +#if defined(__GNUC__) && __GNUC__ < 3 +#define cc_party_log(P, FMT, ARGS...) do { \ + (P)->conn->cc->funcs->log("%s (conn=%p, party=%p): " FMT, \ + __FUNCTION__, (P)->conn, (P) , ## ARGS); \ + } while (0) +#else +#define cc_party_log(P, FMT, ...) do { \ + (P)->conn->cc->funcs->log("%s (conn=%p, party=%p): " FMT, \ + __func__, (P)->conn, (P), __VA_ARGS__); \ + } while (0) +#endif +#else +#if defined(__GNUC__) && __GNUC__ < 3 +#define cc_party_log(P, FMT, ARGS...) do { } while (0) +#else +#define cc_party_log(P, FMT, ...) do { } while (0) +#endif +#endif + +/* + * This is kind of a user socket, i.e. the entity managed towards the + * upper layer. + */ +#define USER_STATES \ + DEF(USER_NULL) /* U0 none */ \ + DEF(USER_OUT_PREPARING) /* U1 process set/query requests */ \ + DEF(USER_OUT_WAIT_OK) /* U2 wait for OK to setup */ \ + DEF(USER_OUT_WAIT_CONF) /* U3 wait for SETUP.confirm */ \ + DEF(USER_ACTIVE) /* U4 A8-9-10/U10 */ \ + DEF(USER_REL_WAIT) /* U5 wait for release to compl */ \ + DEF(USER_IN_PREPARING) /* U6 set SAP */ \ + DEF(USER_IN_WAITING) /* U7 wait and dispatch */ \ + DEF(USER_IN_ARRIVED) /* U8 waiting for rej/acc */ \ + DEF(USER_IN_WAIT_REJ) /* U9 wait for rejecting */ \ + DEF(USER_IN_WAIT_ACC) /* U10 wait for accepting */ \ + DEF(USER_IN_ACCEPTING) /* U11 wait for SETUP_complete */ \ + DEF(USER_REL_WAIT_SCOMP)/* U12 wait for SETUP_complete */ \ + DEF(USER_REL_WAIT_SCONF)/* U13 wait for SETUP.confirm */ \ + DEF(USER_REL_WAIT_CONF) /* U14 wait for confirm */ \ + DEF(USER_REL_WAIT_CONN) /* U15 wait for CONN_OK */ + +enum user_state { +#define DEF(N) N, +USER_STATES +#undef DEF +}; + +#define USER_SIGS \ + DEF(PREPARE_OUTGOING) /* U */ \ + DEF(CONNECT_OUTGOING) /* U msg */ \ + DEF(PREPARE_INCOMING) /* U msg */ \ + DEF(WAIT_ON_INCOMING) /* U msg */ \ + DEF(REJECT_INCOMING) /* U msg */ \ + DEF(ACCEPT_INCOMING) /* U msg */ \ + DEF(CALL_RELEASE) /* U msg */ \ + DEF(ADD_PARTY) /* U msg */ \ + DEF(DROP_PARTY) /* U msg */ \ + DEF(QUERY_ATTR) /* U msg */ \ + DEF(QUERY_ATTR_X) /* U msg */ \ + DEF(SET_ATTR) /* U msg */ \ + DEF(SET_ATTR_X) /* U msg */ \ + DEF(QUERY_STATE) /* U */ \ + DEF(GET_LOCAL_PORT_INFO) /* U msg */ \ + DEF(ABORT_CONNECTION) /* U msg */ \ + \ + DEF(CONNECT_OUTGOING_OK) /* */ \ + DEF(CONNECT_OUTGOING_ERR) /* reason */ \ + DEF(SETUP_CONFIRM) /* */ \ + DEF(SETUP_IND) /* */ \ + DEF(REJECT_OK) /* */ \ + DEF(REJECT_ERR) /* reason */ \ + DEF(ACCEPT_OK) /* */ \ + DEF(ACCEPT_ERR) /* reason */ \ + DEF(ACCEPTING) /* */ \ + DEF(SETUP_COMPL) /* */ \ + DEF(RELEASE_CONFIRM) /* */ \ + DEF(RELEASE_ERR) /* reason */ \ + DEF(ADD_PARTY_ERR) /* reason */ \ + DEF(ADD_PARTY_OK) /* */ \ + DEF(ADD_PARTY_ACK) /* leaf-ident */ \ + DEF(ADD_PARTY_REJ) /* leaf-ident */ \ + DEF(DROP_PARTY_ERR) /* reason */ \ + DEF(DROP_PARTY_OK) /* */ \ + DEF(DROP_PARTY_IND) /* leaf-ident */ \ + + +enum user_sig { +#define DEF(NAME) USER_SIG_##NAME, +USER_SIGS +#undef DEF +}; +extern const char *const cc_user_sigtab[]; + +struct ccuser { + LIST_ENTRY(ccuser) node_link; /* link in list of node */ + enum user_state state; /* type of this instance */ + struct ccdata *cc; /* the node */ + void *uarg; /* the hook (if any) */ + char name[ATM_EPNAMSIZ]; + enum { + USER_P2P, + USER_ROOT, + USER_LEAF + } config; /* configuration */ + + struct uni_sap *sap; /* listening SAP */ + u_int queue_max; /* maximum queue size */ + u_int queue_act; /* actual queue size */ + TAILQ_HEAD(,ccconn) connq; /* pending connections */ + struct ccconn *accepted; + struct uni_ie_cause cause[2]; /* cause from connection */ + u_int aborted; +}; + +/* set user to new state */ +void cc_user_set_state(struct ccuser *, enum user_state); + +/* return string for state */ +const char *cc_user_state2str(u_int); + +/* log on a user */ +#ifdef CCATM_DEBUG +#if defined(__GNUC__) && __GNUC__ < 3 +#define cc_user_log(U, FMT, ARGS...) do { \ + (U)->cc->funcs->log("%s (user=%p): " FMT, __FUNCTION__, \ + (U) , ## ARGS); \ + } while (0) +#else +#define cc_user_log(U, FMT, ...) do { \ + (U)->cc->funcs->log("%s (user=%p): " FMT, __func__, \ + (U), __VA_ARGS__); \ + } while (0) +#endif +#else +#if defined(__GNUC__) && __GNUC__ < 3 +#define cc_user_log(U, FMT, ARGS...) do { } while (0) +#else +#define cc_user_log(U, FMT, ...) do { } while (0) +#endif +#endif + +/* Handle a signal to this user */ +void cc_user_sig_handle(struct ccuser *, enum user_sig, void *, u_int); + +/* + * Addresses + */ +struct ccaddr { + TAILQ_ENTRY(ccaddr) port_link; + struct uni_addr addr; +}; + +/* signal to connection */ +int cc_conn_sig(struct ccconn *, enum conn_sig, void *arg); + +/* signal with message to connection */ +int cc_conn_sig_msg(struct ccconn *, enum conn_sig, struct uni_msg *); +int cc_conn_sig_msg_nodef(struct ccconn *, enum conn_sig, struct uni_msg *); + +/* response signal to connection */ +int cc_conn_resp(struct ccconn *, enum conn_sig, u_int, u_int, u_int); + +/* flush all signals to a given connection */ +void cc_conn_sig_flush(struct ccconn *); + +/* Queue a signal to this user */ +int cc_user_sig(struct ccuser *, enum user_sig, void *, u_int); + +/* Queue a signal with message to this user */ +int cc_user_sig_msg(struct ccuser *, enum user_sig, struct uni_msg *); + +/* Flush all signals to a given user */ +void cc_user_sig_flush(struct ccuser *); + +/* flush all signals */ +void cc_sig_flush_all(struct ccdata *); diff --git a/sys/contrib/ngatm/netnatm/api/unisap.c b/sys/contrib/ngatm/netnatm/api/unisap.c new file mode 100644 index 000000000000..d96f39ec1b1c --- /dev/null +++ b/sys/contrib/ngatm/netnatm/api/unisap.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * Copyright (c) 2004 + * Hartmut Brandt + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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/unisap.c,v 1.4 2004/07/08 08:22:01 brandt Exp $ + */ + +#include <sys/types.h> +#ifdef _KERNEL +#include <sys/ctype.h> +#include <sys/libkern.h> +#else +#include <ctype.h> +#include <string.h> +#endif +#include <netnatm/msg/unistruct.h> +#include <netnatm/api/unisap.h> + +int +unisve_check_addr(const struct unisve_addr *sve) +{ + if (sve->tag == UNISVE_ABSENT) + return (UNISVE_OK); + if (sve->tag == UNISVE_ANY) + return (UNISVE_OK); + if (sve->tag != UNISVE_PRESENT) + return (UNISVE_ERROR_BAD_TAG); + + if (sve->type == UNI_ADDR_INTERNATIONAL) { + if (sve->plan != UNI_ADDR_E164) + return (UNISVE_ERROR_TYPE_PLAN_CONFLICT); + if (sve->len == 0 || sve->len > 15) + return (UNISVE_ERROR_ADDR_LEN); + + } else if (sve->type == UNI_ADDR_UNKNOWN) { + if (sve->plan != UNI_ADDR_ATME) + return (UNISVE_ERROR_TYPE_PLAN_CONFLICT); + if (sve->len != 19) + return (UNISVE_ERROR_ADDR_LEN); + } else + return (UNISVE_ERROR_BAD_ADDR_TYPE); + + return (UNISVE_OK); +} + +int +unisve_check_selector(const struct unisve_selector *sve) +{ + if (sve->tag != UNISVE_PRESENT && + sve->tag != UNISVE_ABSENT && + sve->tag != UNISVE_ANY) + return (UNISVE_ERROR_BAD_TAG); + return (UNISVE_OK); +} + +/* + * We don't want to check the protocol values here. + */ +int +unisve_check_blli_id2(const struct unisve_blli_id2 *sve) +{ + if (sve->tag != UNISVE_PRESENT && + sve->tag != UNISVE_ABSENT && + sve->tag != UNISVE_ANY) + return (UNISVE_ERROR_BAD_TAG); + return (UNISVE_OK); +} + +/* + * We don't want to check the protocol values here. + */ +int +unisve_check_blli_id3(const struct unisve_blli_id3 *sve) +{ + if (sve->tag != UNISVE_PRESENT && + sve->tag != UNISVE_ABSENT && + sve->tag != UNISVE_ANY) + return (UNISVE_ERROR_BAD_TAG); + return (UNISVE_OK); +} + +int +unisve_check_bhli(const struct unisve_bhli *sve) +{ + if (sve->tag == UNISVE_ABSENT) + return (UNISVE_OK); + if (sve->tag == UNISVE_ANY) + return (UNISVE_OK); + + if (sve->tag != UNISVE_PRESENT) + return (UNISVE_ERROR_BAD_TAG); + + if (sve->type != UNI_BHLI_ISO && + sve->type != UNI_BHLI_USER && + sve->type != UNI_BHLI_VENDOR) + return (UNISVE_ERROR_BAD_BHLI_TYPE); + + if (sve->len > sizeof(sve->info)) + return (UNISVE_ERROR_BAD_BHLI_LEN); + + return (UNISVE_OK); +} + +int +unisve_check_sap(const struct uni_sap *sap) +{ + int err; + + if ((err = unisve_check_addr(&sap->addr)) != 0 || + (err = unisve_check_selector(&sap->selector)) != 0 || + (err = unisve_check_blli_id2(&sap->blli_id2)) != 0 || + (err = unisve_check_blli_id3(&sap->blli_id3)) != 0 || + (err = unisve_check_bhli(&sap->bhli)) != 0) + return (err); + + if (sap->addr.plan == UNI_ADDR_E164) { + if (sap->selector.tag == UNISVE_PRESENT) + return (UNISVE_ERROR_ADDR_SEL_CONFLICT); + } else if (sap->addr.plan == UNI_ADDR_ATME) { + if (sap->selector.tag == UNISVE_ABSENT) + return (UNISVE_ERROR_ADDR_SEL_CONFLICT); + } + return (0); +} + +#define COMMON_OVERLAP(A1,A2) \ + if ((A1->tag == UNISVE_ABSENT && A2->tag == UNISVE_ABSENT) || \ + A1->tag == UNISVE_ANY || A2->tag == UNISVE_ANY) \ + return (1); \ + if ((A1->tag == UNISVE_ABSENT && A2->tag == UNISVE_PRESENT) || \ + (A2->tag == UNISVE_ABSENT && A1->tag == UNISVE_PRESENT)) \ + return (0); + +int +unisve_overlap_addr(const struct unisve_addr *s1, const struct unisve_addr *s2) +{ + COMMON_OVERLAP(s1, s2); + + return (s1->type == s2->type && s1->plan == s2->plan && + s1->len == s2->len && memcmp(s1->addr, s2->addr, s1->len) == 0); +} + +int +unisve_overlap_selector(const struct unisve_selector *s1, + const struct unisve_selector *s2) +{ + COMMON_OVERLAP(s1, s2); + + return (s1->selector == s2->selector); +} + +int +unisve_overlap_blli_id2(const struct unisve_blli_id2 *s1, + const struct unisve_blli_id2 *s2) +{ + COMMON_OVERLAP(s1, s2); + + return (s1->proto == s2->proto && + (s1->proto != UNI_BLLI_L2_USER || s1->user == s2->user)); +} + +int +unisve_overlap_blli_id3(const struct unisve_blli_id3 *s1, + const struct unisve_blli_id3 *s2) +{ + COMMON_OVERLAP(s1, s2); + + if (s1->proto != s2->proto) + return (0); + if (s1->proto == UNI_BLLI_L3_USER) + return (s1->user == s2->user); + if (s1->proto == UNI_BLLI_L3_TR9577) { + if (s1->noipi && s2->noipi) + return (1); + if (!s1->noipi && !s2->noipi) { + if (s1->ipi == s2->ipi) { + if (s1->ipi != UNI_BLLI_L3_SNAP) + return (1); + if (s1->oui == s2->oui && s1->pid == s2->pid) + return (1); + } + } + return (0); + } + return (1); +} + +int +unisve_overlap_bhli(const struct unisve_bhli *s1, const struct unisve_bhli *s2) +{ + COMMON_OVERLAP(s1, s2); + + return (s1->type == s2->type && s1->len == s2->len && + memcmp(s1->info, s2->info, s1->len) == 0); +} + +int +unisve_overlap_sap(const struct uni_sap *s1, const struct uni_sap *s2) +{ + int any1, any2; + + /* + * Two catch-all's SAP's are not allowed. A catch-all does never + * overlap with a non-catch all SAP. + */ + any1 = unisve_is_catchall(s1); + any2 = unisve_is_catchall(s2); + + if (any1 && any2) + return (1); + if(any1 || any2) + return (0); + + return (unisve_overlap_addr(&s1->addr, &s2->addr) && + unisve_overlap_selector(&s1->selector, &s2->selector) && + unisve_overlap_blli_id2(&s1->blli_id2, &s2->blli_id2) && + unisve_overlap_blli_id3(&s1->blli_id3, &s2->blli_id3) && + unisve_overlap_bhli(&s1->bhli, &s2->bhli)); +} + +int +unisve_is_catchall(const struct uni_sap *sap) +{ + return (sap->addr.tag == UNISVE_ANY && + sap->selector.tag == UNISVE_ANY && + sap->blli_id2.tag == UNISVE_ANY && + sap->blli_id3.tag == UNISVE_ANY && + sap->bhli.tag == UNISVE_ANY); +} + +int +unisve_match(const struct uni_sap *sap, const struct uni_ie_called *called, + const struct uni_ie_blli *blli, const struct uni_ie_bhli *bhli) +{ + switch (sap->addr.tag) { + case UNISVE_ABSENT: + if (IE_ISGOOD(*called)) + return (0); + break; + + case UNISVE_ANY: + break; + + case UNISVE_PRESENT: + if (!IE_ISGOOD(*called)) + return (0); + if (called->addr.type != sap->addr.type || + called->addr.plan != sap->addr.plan) + return (0); + if (called->addr.plan == UNI_ADDR_E164) { + if (called->addr.len != sap->addr.len || + memcmp(called->addr.addr, sap->addr.addr, + called->addr.len) != 0) + return (0); + } else if (called->addr.plan == UNI_ADDR_ATME) { + if (called->addr.len != 20 || + memcmp(called->addr.addr, sap->addr.addr, 19) != 0) + return (0); + } + break; + + default: + return (0); + } + + switch (sap->selector.tag) { + + case UNISVE_ABSENT: + if (IE_ISGOOD(*called) && called->addr.plan == UNI_ADDR_ATME) + return (0); + break; + + case UNISVE_ANY: + break; + + case UNISVE_PRESENT: + if (!IE_ISGOOD(*called)) + return (0); + if (called->addr.plan != UNI_ADDR_ATME) + return (0); + if (called->addr.addr[19] != sap->selector.selector) + return (0); + break; + + default: + return (0); + } + + switch (sap->blli_id2.tag) { + + case UNISVE_ABSENT: + if (IE_ISGOOD(*blli) && (blli->h.present & UNI_BLLI_L2_P)) + return (0); + break; + + case UNISVE_ANY: + break; + + case UNISVE_PRESENT: + if (!IE_ISGOOD(*blli) || (blli->h.present & UNI_BLLI_L2_P) == 0) + return (0); + if (blli->l2 != sap->blli_id2.proto) + return (0); + if (blli->l2 == UNI_BLLI_L2_USER) { + if ((blli->h.present & UNI_BLLI_L2_USER_P) == 0) + return (0); + if (blli->l2_user != sap->blli_id2.user) + return (0); + } + break; + + default: + return (0); + } + + switch (sap->blli_id3.tag) { + + case UNISVE_ABSENT: + if (IE_ISGOOD(*blli) && (blli->h.present & UNI_BLLI_L3_P)) + return (0); + break; + + case UNISVE_ANY: + break; + + case UNISVE_PRESENT: + if (!IE_ISGOOD(*blli) || (blli->h.present & UNI_BLLI_L3_P) == 0) + return (0); + if (blli->l3 != sap->blli_id3.proto) + return (0); + if (blli->l3 == UNI_BLLI_L3_USER) { + if ((blli->h.present & UNI_BLLI_L3_USER_P) == 0) + return (0); + if (blli->l3_user != sap->blli_id3.user) + return (0); + break; + } + if (blli->l3 == UNI_BLLI_L3_TR9577) { + if (sap->blli_id3.noipi) { + if (blli->h.present & UNI_BLLI_L3_IPI_P) + return (0); + } else { + if (!(blli->h.present & UNI_BLLI_L3_IPI_P)) + return (0); + if (blli->l3_ipi != sap->blli_id3.ipi) + return (0); + if (blli->l3_ipi == UNI_BLLI_L3_SNAP) { + if (!(blli->h.present & + UNI_BLLI_L3_SNAP_P)) + return (0); + if (blli->oui != sap->blli_id3.oui || + blli->pid != sap->blli_id3.pid) + return (0); + } + } + } + break; + + default: + return (0); + } + + switch (sap->bhli.tag) { + + case UNISVE_ABSENT: + if (IE_ISGOOD(*bhli)) + return (0); + break; + + case UNISVE_ANY: + break; + + case UNISVE_PRESENT: + if (!IE_ISGOOD(*bhli)) + return (0); + if (sap->bhli.type != bhli->type) + return (0); + if (sap->bhli.len != bhli->len) + return (0); + if (memcmp(sap->bhli.info, bhli->info, bhli->len) != 0) + return (0); + break; + + default: + return (0); + } + /* Uff */ + return (1); +} diff --git a/sys/contrib/ngatm/netnatm/api/unisap.h b/sys/contrib/ngatm/netnatm/api/unisap.h new file mode 100644 index 000000000000..ffbfc9fa42e8 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/api/unisap.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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/unisap.h,v 1.6 2005/05/23 11:49:17 brandt_h Exp $ + */ +#ifndef _NETNATM_API_UNISAP_H_ +#define _NETNATM_API_UNISAP_H_ + +#include <netnatm/msg/uni_config.h> + +enum unisve_tag { + UNISVE_ABSENT, /* Element is absent */ + UNISVE_PRESENT, /* Element is present with specific value */ + UNISVE_ANY /* Any values is acceptable */ +}; + +struct unisve_addr { + enum unisve_tag tag; + enum uni_addr_type type; /* type of address */ + enum uni_addr_plan plan; /* addressing plan */ + uint32_t len; /* length of address */ + u_char addr[UNI_ADDR_MAXLEN]; +}; + +struct unisve_selector { + enum unisve_tag tag; + uint8_t selector; +}; + +struct unisve_blli_id2 { + enum unisve_tag tag; + u_int proto:5; /* the protocol */ + u_int user:7; /* user specific protocol */ +}; + +struct unisve_blli_id3 { + enum unisve_tag tag; + u_int proto:5; /* L3 protocol */ + u_int user:7; /* user specific protocol */ + u_int ipi:8; /* ISO/IEC TR 9557 IPI */ + u_int oui:24; /* IEEE 802.1 OUI */ + u_int pid:16; /* IEEE 802.1 PID */ + uint32_t noipi; /* ISO/IEC TR 9557 per frame */ +}; + +struct unisve_bhli { + enum unisve_tag tag; + enum uni_bhli type; /* type of info */ + uint32_t len; /* length of info */ + uint8_t info[8]; /* info itself */ +}; + +struct uni_sap { + struct unisve_addr addr; + struct unisve_selector selector; + struct unisve_blli_id2 blli_id2; + struct unisve_blli_id3 blli_id3; + struct unisve_bhli bhli; +}; + +int unisve_check_addr(const struct unisve_addr *); +int unisve_check_selector(const struct unisve_selector *); +int unisve_check_blli_id2(const struct unisve_blli_id2 *); +int unisve_check_blli_id3(const struct unisve_blli_id3 *); +int unisve_check_bhli(const struct unisve_bhli *); + +int unisve_check_sap(const struct uni_sap *); + +int unisve_overlap_addr(const struct unisve_addr *, const struct unisve_addr *); +int unisve_overlap_selector(const struct unisve_selector *, + const struct unisve_selector *); +int unisve_overlap_blli_id2(const struct unisve_blli_id2 *, + const struct unisve_blli_id2 *); +int unisve_overlap_blli_id3(const struct unisve_blli_id3 *, + const struct unisve_blli_id3 *); +int unisve_overlap_bhli(const struct unisve_bhli *, + const struct unisve_bhli *); +int unisve_overlap_sap(const struct uni_sap *, const struct uni_sap *); + +int unisve_is_catchall(const struct uni_sap *); +int unisve_match(const struct uni_sap *, const struct uni_ie_called *, + const struct uni_ie_blli *, const struct uni_ie_bhli *); + +enum { + UNISVE_OK = 0, + UNISVE_ERROR_BAD_TAG, + UNISVE_ERROR_TYPE_PLAN_CONFLICT, + UNISVE_ERROR_ADDR_SEL_CONFLICT, + UNISVE_ERROR_ADDR_LEN, + UNISVE_ERROR_BAD_ADDR_TYPE, + UNISVE_ERROR_BAD_BHLI_TYPE, + UNISVE_ERROR_BAD_BHLI_LEN, +}; + +#define UNISVE_ERRSTR \ + "no error", \ + "bad SVE tag", \ + "bad address type/plan combination", \ + "bad address plan/selector tag combination", \ + "bad address length in SVE", \ + "unknown address type in SVE", \ + "bad BHLI type in SVE", \ + "BHLI info too long in SVE", + +#endif diff --git a/sys/contrib/ngatm/netnatm/genfiles b/sys/contrib/ngatm/netnatm/genfiles new file mode 100644 index 000000000000..70fb5e880463 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/genfiles @@ -0,0 +1,15 @@ +#!/bin/sh +# Copyright (c) 2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Author: Harti Brandt <harti@freebsd.org> +# +# $Begemot: libunimsg/netnatm/genfiles,v 1.4 2004/07/08 08:21:45 brandt Exp $ +# +awk -f ${SRC}msg/parseie.awk -f ${SRC}msg/geniec.awk ${SRC}msg/ie.def >${DST}msg/uni_ietab.h +awk -f ${SRC}msg/parseie.awk -f ${SRC}msg/genieh.awk ${SRC}msg/ie.def >${DST}msg/uni_ie.h +awk -f ${SRC}msg/parsemsg.awk -f ${SRC}msg/genmsgc.awk ${SRC}msg/msg.def >${DST}msg/uni_msg.c +awk -f ${SRC}msg/parsemsg.awk -f ${SRC}msg/genmsgh.awk ${SRC}msg/msg.def >${DST}msg/uni_msg.h +awk -f ${SRC}msg/parsemsg.awk -f ${SRC}sig/genmsgcpyh.awk ${SRC}msg/msg.def >${DST}sig/unimsgcpy.h +awk -f ${SRC}msg/parsemsg.awk -f ${SRC}sig/genmsgcpyc.awk ${SRC}msg/msg.def >${DST}sig/sig_unimsgcpy.c diff --git a/sys/contrib/ngatm/netnatm/misc/straddr.c b/sys/contrib/ngatm/netnatm/misc/straddr.c new file mode 100644 index 000000000000..7d21b8f74206 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/misc/straddr.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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/misc/straddr.c,v 1.4 2004/07/08 08:22:02 brandt Exp $ + */ + +#include <sys/types.h> +#ifdef _KERNEL +#include <sys/ctype.h> +#include <sys/libkern.h> +#else +#include <ctype.h> +#include <string.h> +#endif +#include <netnatm/addr.h> + +/* + * Convert an NSAP address from the ASCII format to the binary. + * ASCII format means each byte formatted as a 2-byte hex number + * with dots freely interspersed between the bytes. + * If the conversion is succesful, the function returns 0, -1 + * on conversion errors. + */ +int +uni_str2nsap(u_char *out, const char *in) +{ + int i; + int c; + + for(i = 0; i < 20; i++) { + while((c = *in++) == '.') + ; + if(!isascii(c) || !isxdigit(c)) + return -1; + out[i] = isdigit(c) ? (c - '0') + : islower(c) ? (c - 'a' + 10) + : (c - 'A' + 10); + out[i] <<= 4; + c = *in++; + if(!isascii(c) || !isxdigit(c)) + return -1; + out[i] |= isdigit(c) ? (c - '0') + : islower(c) ? (c - 'a' + 10) + : (c - 'A' + 10); + } + return *in != '\0'; +} + +/* + * Parse an emebedded E.164 NSAP address. + * If check is 0, the contents of the last 11 bytes are ignored + * If check is 1, the contents of all of these but the selector byte + * are checked to be zero. If check is 2 all 11 bytes must be 0. + */ +int +uni_nsap2e164(char *e164, const u_char *nsap, int check) +{ + char *p = e164; + u_int d; + int i; + + if(nsap[0] != 0x45) + return -1; + if((nsap[8] & 0xf) != 0xf) + return -1; + for(i = 1; i <= 7; i++) { + d = (nsap[i] >> 4) & 0xf; + if(d == 0x00 && p == e164) + continue; + if(d >= 0xa) + return -1; + *p++ = d + '0'; + + d = nsap[i] & 0xf; + if(d == 0x00 && p == e164) + continue; + if(d >= 0xa) + return -1; + *p++ = d + '0'; + } + d = (nsap[i] >> 4) & 0xf; + if(d != 0x00 || p == e164) { + if(d >= 0xa) + return -1; + *p++ = d + '0'; + } + if(p == e164) + return -1; + *p++ = 0; + + if(check == 0) + return 0; + while(i < ((check == 1) ? 19 : 20)) { + if(nsap[i] != 0x00) + return -1; + i++; + } + + return 0; +} + +/* + * Convert a binary representation to ASCII. The standard formats are + * recognized and dotted. Non-standard formats get no dots altogether. + */ +void +uni_prefix2str(char *out, const u_char *in, u_int len, int dotit) +{ + static char hex[16] = "0123456789abcdef"; + static int fmt[3][6] = { + { 1, 2, 10, 6, 1, 0 }, + { 1, 2, 10, 6, 1, 0 }, + { 1, 8, 4, 6, 1, 0 }, + }; + int f, b; + u_int i; + + if (len > 20) + len = 20; + + if(dotit) { + switch(*in) { + + case 0x39: /* DCC */ + i = 0; + fmt: + for(f = 0; fmt[i][f]; f++) { + if (len == 0) + goto done; + if(f != 0) + *out++ = '.'; + for(b = 0; b < fmt[i][f]; b++) { + if (len-- == 0) + goto done; + *out++ = hex[(*in >> 4) & 0xf]; + *out++ = hex[*in & 0xf]; + in++; + } + } + done: + *out = '\0'; + return; + + case 0x47: /* ICD */ + i = 1; + goto fmt; + + case 0x45: /* E.164 */ + i = 2; + goto fmt; + } + } + + /* undotted */ + for(i = 0; i < len; i++) { + *out++ = hex[(*in >> 4) & 0xf]; + *out++ = hex[*in & 0xf]; + in++; + } + *out = '\0'; +} + +void +uni_nsap2str(char *out, const u_char *in, int dotit) +{ + uni_prefix2str(out, in, 20, dotit); +} + +/* + * Make an embedded E.164 NSAP address from a NSAP address. + * The E.164 address is a string of digits, at least one digit and + * not more than 15 digits long. The NSAP address will start with + * byte 0x45 and then a 8 byte field, which contains the right + * justified E.164 address in BCD coding, filled with a 0xf to the + * right. The rest of the address is zero. + * The function returns 0 if everything is ok, -1 in case of a wrong + * E.164 address. + */ +int +uni_e1642nsap(u_char *nsap, const char *e164) +{ + size_t len; + int fill; + u_int i; + + if((len = strlen(e164)) > 15 || len == 0) + return -1; + for(i = 0; i < len; i++) + if(!isdigit(e164[i])) + return -1; + + *nsap++ = 0x45; + fill = (15 - len) / 2; + while(fill--) + *nsap++ = 0x00; + if((len & 1) == 0) { + *nsap++ = *e164++ - '0'; + len--; + } + while(len > 1) { + len -= 2; + *nsap = (*e164++ - '0') << 4; + *nsap++ |= *e164 - '0'; + } + *nsap++ = ((*e164++ - '0') << 4) | 0xf; + for(fill = 0; fill < 11; fill++) + *nsap++ = 0; + + return 0; +} diff --git a/sys/contrib/ngatm/netnatm/misc/unimsg_common.c b/sys/contrib/ngatm/netnatm/misc/unimsg_common.c new file mode 100644 index 000000000000..033213aef781 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/misc/unimsg_common.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2003-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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/misc/unimsg_common.c,v 1.3 2004/07/08 08:22:03 brandt Exp $ + */ + +#include <netnatm/unimsg.h> + +/* + * Make sure there is enough space in front of the data for + * len bytes, and update the read pointer. + */ +int +uni_msg_prepend(struct uni_msg *msg, size_t len) +{ + size_t need; + + if (uni_msg_leading(msg) >= len) { + msg->b_rptr -= len; + return (0); + } + need = len - uni_msg_leading(msg); + if (uni_msg_ensure(msg, need)) + return (-1); + memcpy(msg->b_rptr + need, msg->b_rptr, uni_msg_len(msg)); + msg->b_rptr += need - len; + msg->b_wptr += need; + return (0); +} diff --git a/sys/contrib/ngatm/netnatm/msg/geniec.awk b/sys/contrib/ngatm/netnatm/msg/geniec.awk new file mode 100644 index 000000000000..d0620825178f --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/geniec.awk @@ -0,0 +1,110 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# $Begemot: libunimsg/netnatm/msg/geniec.awk,v 1.4 2003/10/10 14:50:05 hbb Exp $ +# +# Generate table for IE parsing. +# +# This function is called before the first line +# +function begin() { + for(i = 0; i < 256; i++) { + for(j = 0; j < 4; j++) { + decl[i,j] = "" + } + } +} + +# +# This function is called after the last line. +# +function end() { + print "" + print "const struct iedecl *uni_ietable[256][4] = {" + for(i = 0; i < 256; i++) { + printf "\t{" + for(j = 0; j < 4; j++) { + if(decl[i,j] == "") { + printf " NULL," + } else { + printf " &%s,", decl[i,j] + } + } + printf " }, /* 0x%02x */\n", i + } + print "};" +} + +# +# This function is called just when the first information element was found +# +function first_element() { + print "/* This file was created automatically" + print " * Source file: " id + print " */" + print "" +} + +# +# This is called, when the information element is defaulted (there is +# only the name and the coding scheme +# +function element_default() { + print "" + print "static const struct iedecl decl_" coding "_" ie " = {" + print "\tUNIFL_DEFAULT," + print "\t0," + print "\t(uni_print_f)NULL," + print "\t(uni_check_f)NULL," + print "\t(uni_encode_f)NULL," + print "\t(uni_decode_f)NULL" + print "};" + decl[number,ncoding] = "decl_" coding "_" ie +} + +# +# This is found for a real, non-default IE +# +function element() { + print "" + print "static void uni_ie_print_" coding "_" ie "(struct uni_ie_" ie " *, struct unicx *);" + print "static int uni_ie_check_" coding "_" ie "(struct uni_ie_" ie " *, struct unicx *);" + print "static int uni_ie_encode_" coding "_" ie "(struct uni_msg *, struct uni_ie_" ie " *, struct unicx *);" + print "static int uni_ie_decode_" coding "_" ie "(struct uni_ie_" ie " *, struct uni_msg *, u_int, struct unicx *);" + print "" + print "static struct iedecl decl_" coding "_" ie " = {" + if(access) print "\tUNIFL_ACCESS," + else print "\t0," + print "\t" len "," + print "\t(uni_print_f)uni_ie_print_" coding "_" ie "," + print "\t(uni_check_f)uni_ie_check_" coding "_" ie "," + print "\t(uni_encode_f)uni_ie_encode_" coding "_" ie "," + print "\t(uni_decode_f)uni_ie_decode_" coding "_" ie "" + print "};" + decl[number,ncoding] = "decl_" coding "_" ie +} diff --git a/sys/contrib/ngatm/netnatm/msg/genieh.awk b/sys/contrib/ngatm/netnatm/msg/genieh.awk new file mode 100644 index 000000000000..7120d7b9a020 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/genieh.awk @@ -0,0 +1,61 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# $Begemot: libunimsg/netnatm/msg/genieh.awk,v 1.4 2004/07/08 08:22:03 brandt Exp $ +# +# Generate IE header file +# +function begin() { +} + +function first_element() { + print "/* This file was created automatically" + print " * Source file: " id + print " */" + print "" + print "#ifndef _NETNATM_MSG_UNI_IE_H_" + print "#define _NETNATM_MSG_UNI_IE_H_" + print "" + print "union uni_ieall {" + print " struct uni_iehdr h;" +} + +function end() { + print "};" + print "" + print "#endif" +} + +function element_default() { +} + +function element() { + if(ie in u) return + u[ie] = 1 + print " struct uni_ie_" ie " " ie ";" +} diff --git a/sys/contrib/ngatm/netnatm/msg/genmsgc.awk b/sys/contrib/ngatm/netnatm/msg/genmsgc.awk new file mode 100644 index 000000000000..ffd69ac5fc69 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/genmsgc.awk @@ -0,0 +1,274 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# $Begemot: libunimsg/netnatm/msg/genmsgc.awk,v 1.6 2004/07/08 08:22:04 brandt Exp $ +# +# Generate message functions. +# +function begin() { +} + +function first_entry() { + print "/* This file was created automatically" + print " * Source file: " id + print " */" + print "" + print "#include <sys/types.h>" + print "#include <sys/param.h>" + print "" + print "#ifdef _KERNEL" + print "#include <sys/libkern.h>" + print "#else" + print "#include <string.h>" + print "#endif" + print "#include <netnatm/unimsg.h>" + print "#include <netnatm/msg/unistruct.h>" + print "#include <netnatm/msg/unimsglib.h>" + print "#include <netnatm/msg/priv.h>" + print "#include <netnatm/msg/privmsg.c>" +} + +function end() { + print "" + print "const struct msgdecl *uni_msgtable[256] = {" + for(i = 0; i < 256; i++) { + if(decl[i] == "") { + printf "\t&decl_unknown," + } else { + printf "\t&%s,", decl[i] + } + printf "\t/* 0x%02x */\n", i + } + print "};" +} + +function start_message() { +} + +function end_message() { + gen_print() + gen_check() + gen_encode() + gen_decode() + gen_reg() +} + +function gen_print() { + print "" + print "static void" + print "print_" msg "(struct uni_" msg " *msg, struct unicx *cx)" + print "{" + if(msgrep) { + print "\tu_int i;" + print "" + } + for(i = 0; i < cnt; i++) { + ie = iename[i] + uie = toupper(iename[i]) + if(ierep[i]) { + print "\tif(msg->" ie "_repeat.h.present & UNI_IE_PRESENT)" + print "\t\tuni_print_ie_internal(UNI_IE_REPEAT, (union uni_ieall *)&msg->" ie "_repeat, cx);" + } + if(ienum[i] == "-") { + print "\tif(msg->" ie ".h.present & UNI_IE_PRESENT)" + print "\t\tuni_print_ie_internal(UNI_IE_" uie ", (union uni_ieall *)&msg->" ie ", cx);" + } else { + print "\tfor(i = 0; i < " ienum[i] "; i++)" + print "\t\tif(msg->" ie "[i].h.present & UNI_IE_PRESENT)" + print "\t\t\tuni_print_ie_internal(UNI_IE_" uie ", (union uni_ieall *)&msg->" ie "[i], cx);" + } + } + print "}" +} + +function gen_check() { + print "" + print "static int" + print "check_" msg "(struct uni_" msg " *m, struct unicx *cx)" + print "{" + print "\tint ret = 0;" + if(msgrep) { + print "\tu_int i;" + } + print "" + for(i = 0; i < cnt; i++) { + ie = iename[i] + if(ierep[i]) { + if(iecond[i] == "1") { + print "\tret |= uni_check_ie(UNI_IE_REPEAT, (union uni_ieall *)&m->" ie "_repeat, cx);" + } else { + print "\tif(!(" iecond[i] "))" + print "\t\tret |= IE_ISPRESENT(m->" ie "_repeat);" + print "\telse" + print "\t\tret |= uni_check_ie(UNI_IE_REPEAT, (union uni_ieall *)&m->" ie "_repeat, cx);" + } + } + if(ienum[i] == "-") { + if(iecond[i] == "1") { + print "\tret |= uni_check_ie(UNI_IE_" toupper(ie) ", (union uni_ieall *)&m->" ie ", cx);" + } else { + print "\tif(!(" iecond[i] "))" + print "\t\tret |= IE_ISPRESENT(m->" ie ");" + print "\telse" + print "\t\tret |= uni_check_ie(UNI_IE_" toupper(ie) ", (union uni_ieall *)&m->" ie ", cx);" + } + } else { + print "\tfor(i = 0; i < " ienum[i]" ; i++) {" + if(iecond[i] == "1") { + print "\t\tret |= uni_check_ie(UNI_IE_" toupper(ie) ", (union uni_ieall *)&m->" ie "[i], cx);" + } else { + print "\t\tif(!(" iecond[i] "))" + print "\t\t\tret |= IE_ISPRESENT(m->" ie "[i]);" + print "\t\telse" + print "\t\t\tret |= uni_check_ie(UNI_IE_" toupper(ie) ", (union uni_ieall *)&m->" ie "[i], cx);" + } + print "\t}" + } + } + print "" + print "\treturn ret;" + print "}" +} + +function gen_encode() { + print "" + print "static int" + print "encode_" msg "(struct uni_msg *msg, struct uni_" msg " *p, struct unicx *cx)" + print "{" + print "\tu_int mlen;" + if(msgrep) { + print "\tu_int i;" + } + print "" + print "\tif(uni_encode_msg_hdr(msg, &p->hdr, UNI_" toupper(msg) ", cx, &mlen))" + print "\t\treturn (-2);" + print "" + for(i = 0; i < cnt; i++) { + ie = iename[i] + if(ierep[i]) { + print "\tif((p->" ie "_repeat.h.present & UNI_IE_PRESENT) &&" + print "\t uni_encode_ie(UNI_IE_" toupper(ie) ", msg, (union uni_ieall *)&p->" ie "_repeat, cx))" + print "\t\treturn (0x10000000 + UNI_IE_" toupper(ie) ");" + } + if(ienum[i] == "-") { + print "\tif((p->" ie ".h.present & UNI_IE_PRESENT) &&" + print "\t uni_encode_ie(UNI_IE_" toupper(ie) ", msg, (union uni_ieall *)&p->" ie ", cx))" + print "\t\treturn (UNI_IE_" toupper(ie) ");" + } else { + print "\tfor(i = 0; i < " ienum[i] "; i++)" + print "\t\tif((p->" ie "[i].h.present & UNI_IE_PRESENT) &&" + print "\t\t uni_encode_ie(UNI_IE_" toupper(ie) ", msg, (union uni_ieall *)&p->" ie "[i], cx))" + print "\t\treturn ((i << 16) + UNI_IE_" toupper(ie) ");" + } + } + print "" + print "\tmsg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8;" + print "\tmsg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0;" + print "" + print "\treturn (0);" + print "}" +} + +function gen_decode() { + print "" + print "static int" + print "decode_" msg "(struct uni_" msg " *out, struct uni_msg *msg," + print " enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen," + print " struct unicx *cx)" + print "{" + if (msgrep) { + print " u_int i;" + print "" + } + print " switch (ie) {" + + rep=0 + for (i = 0; i < cnt; i++) { + ie = iename[i] + print "" + print " case UNI_IE_" toupper(ie) ":" + if (iecond[i] != "1") { + print " if (!(" iecond[i] "))" + print " return (DEC_ILL);" + } + if (ierep[i]) { + rep=1 + print " if (IE_ISPRESENT(cx->repeat))" + print " out->" ie "_repeat = cx->repeat;" + } + if (ienum[i] == "-") { + print " out->" ie ".h = *hdr;" + print " if (hdr->present & UNI_IE_ERROR)" + print " return (DEC_ERR);" + print " if(uni_decode_ie_body(UNI_IE_"toupper(ie)", (union uni_ieall *)&out->"ie", msg, ielen, cx))" + print " return (DEC_ERR);" + + } else { + print " for(i = 0; i < " ienum[i] "; i++)" + print " if (!IE_ISPRESENT(out->" ie "[i])) {" + print " out->" ie "[i].h = *hdr;" + print " if (hdr->present & UNI_IE_ERROR)" + print " return (DEC_ERR);" + print " if(uni_decode_ie_body(UNI_IE_"toupper(ie)", (union uni_ieall *)&out->"ie"[i], msg, ielen, cx))" + print " return (DEC_ERR);" + print " break;" + print " }" + } + print " break;" + } + if(rep) { + print "" + print " case UNI_IE_REPEAT:" + print " cx->repeat.h = *hdr;" + print " if (hdr->present & UNI_IE_ERROR)" + print " return (DEC_ERR);" + print " if (uni_decode_ie_body(UNI_IE_REPEAT, (union uni_ieall *)&cx->repeat, msg, ielen, cx))" + print " return (DEC_ERR);" + print " break;" + } + + print "" + print " default:" + print " return (DEC_ILL);" + print " }" + print " return (DEC_OK);" + print "}" +} + +function gen_reg() { + print "" + print "static const struct msgdecl decl_" msg " = {" + print "\t0," + print "\t\"" msg "\"," + print "\t(uni_msg_print_f)print_" msg "," + print "\t(uni_msg_check_f)check_" msg "," + print "\t(uni_msg_encode_f)encode_" msg "," + print "\t(uni_msg_decode_f)decode_" msg + print "};" + decl[code] = "decl_" msg +} diff --git a/sys/contrib/ngatm/netnatm/msg/genmsgh.awk b/sys/contrib/ngatm/netnatm/msg/genmsgh.awk new file mode 100644 index 000000000000..8705b31e1e30 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/genmsgh.awk @@ -0,0 +1,80 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# $Begemot: libunimsg/netnatm/msg/genmsgh.awk,v 1.4 2004/07/08 08:22:04 brandt Exp $ +# +# Generate message header +# +function begin() { +} + +function first_entry() { + print "/* This file was created automatically" + print " * Source file: " id + print " */" + print "" + print "#ifndef _NETNATM_MSG_UNI_MSG_H_" + print "#define _NETNATM_MSG_UNI_MSG_H_" +} + +function end() { + print "" + print "union uni_msgall {" + print "\tstruct uni_msghdr\thdr;" + for(i = 0; i < mcnt; i++) { + m = messages[i] + if(msgcond[i] == "") { + print "\tstruct uni_" m "\t" m ";" + } else { + print "\tstruct uni_" m "\t" m ";\t/* " msgcond[i] " */" + } + } + print "};" + print "" + print "#endif" +} + +function start_message() { +} + +function end_message() { + print "" + print "struct uni_" msg " {" + print "\tstruct uni_msghdr\thdr;" + for(i = 0; i < cnt; i++) { + if(ierep[i]) { + print "\tstruct uni_ie_repeat\t" iename[i] "_repeat;" + } + if(ienum[i] != "-") { + print "\tstruct uni_ie_" iename[i] "\t" iename[i] "[" ienum[i] "];" + } else { + print "\tstruct uni_ie_" iename[i] "\t" iename[i] ";" + } + } + print "};" +} diff --git a/sys/contrib/ngatm/netnatm/msg/ie.def b/sys/contrib/ngatm/netnatm/msg/ie.def new file mode 100644 index 000000000000..fbeabe87a84c --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/ie.def @@ -0,0 +1,84 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# $Begemot: libunimsg/netnatm/msg/ie.def,v 1.4 2003/09/29 10:47:18 hbb Exp $ +# +# Define information elements --- no content definition +# +######################################################################### +element cause 0x08 itu 34 +element cause 0x08 net 34 +element callstate 0x14 itu 5 +element facility 0x1c itu UNI_FACILITY_MAXAPDU+1+4 q2932 +element notify 0x27 itu UNI_NOTIFY_MAXLEN+4 +element eetd 0x42 itu 11 +element eetd 0x42 net 13 +element conned 0x4c itu 25 file=addr +element connedsub 0x4d itu 25 access file=addr +element epref 0x54 itu 7 +element epstate 0x55 itu 5 +element aal 0x58 itu 21 access +element traffic 0x59 itu 30 +element traffic 0x59 net +element connid 0x5a itu 9 +element qos 0x5c itu 6 +element qos 0x5c net 6 +element bhli 0x5d itu 13 access +element bearer 0x5e itu 7 +element blli 0x5f itu 17 access +element lshift 0x60 itu 5 0 file=shift +element nlshift 0x61 itu 5 0 file=shift +element scompl 0x62 itu 5 !pnni +element repeat 0x63 itu 5 +element calling 0x6c itu 26 file=addr +element callingsub 0x6d itu 25 access file=addr +element called 0x70 itu 25 file=addr +element calledsub 0x71 itu 25 access file=addr +element tns 0x78 itu 9 +element tns 0x78 net +element restart 0x79 itu 5 +element uu 0x7e itu UNI_UU_MAXLEN+4 access !pnni +element git 0x7f net 33 +element mintraffic 0x81 itu 20 file=traffic +element mintraffic 0x81 net +element atraffic 0x82 itu 30 file=traffic +element atraffic 0x82 net +element abrsetup 0x84 net 36 file=abr +element report 0x89 itu 5 +element called_soft 0xe0 net 11 file=soft pnni +element crankback 0xe1 net 72 pnni +element dtl 0xe2 net UNI_DTL_LOGNP_SIZE*UNI_DTL_MAXNUM+6 pnni +element calling_soft 0xe3 net 10 file=soft pnni +element abradd 0xe4 net 14 file=abr +element lij_callid 0xe8 net 9 file=lij !pnni +element lij_param 0xe9 net 5 file=lij !pnni +element lij_seqno 0xea net 8 file=lij !pnni +element cscope 0xeb net 6 +element exqos 0xec net 25 +element mdcr 0xf0 net 13 file=traffic +element unrec 0xfe itu 128 diff --git a/sys/contrib/ngatm/netnatm/msg/msg.def b/sys/contrib/ngatm/netnatm/msg/msg.def new file mode 100644 index 000000000000..41453ec6a5c4 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/msg.def @@ -0,0 +1,582 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# $Begemot: libunimsg/netnatm/msg/msg.def,v 1.4 2003/09/29 10:47:18 hbb Exp $ +# +# Define message contents +# +######################################################################### +# +# ALERTING message +# +# References: +# Q.2931 8, 17* +# ...A4 4, 11* +# Q.2957 3 +# Q.2971 6 +# UNI4.0 5 +# PNNI1.0 177...178, 184* +# +# Notes: +# N-ISDN compatiblity not implemented. +# +start alerting 0x01 + connid - !pnni + epref + notify + git UNI_NUM_IE_GIT + uu - !pnni + report - !pnni + unrec +end + +######################################################################### +# +# CALL PROCEEDING message +# +# References: +# Q.2931 9, 18* +# Q.2971 6 +# UNI4.0 5 +# PNNI1.0 178 +# +# Notes: +# N-ISDN compatiblity not implemented. +# +start call_proc 0x02 + connid + epref + notify - !pnni + unrec +end + +######################################################################### +# +# CONNECT message +# +# References: +# Q.2931 p. 10, 19* +# ...A4 6, 12* +# Q.2932.1 p. 17 +# Q.2951 p. 30 +# Q.2957 p. 4 +# Q.2962 p. 3 +# Q.2971 p. 7 +# UNI4.0 p. 5-6, 61, 68, 77 +# PNNI1.0 pp. 178...179, 184...185* +# +# Notes: +# N-ISDN compatiblity not implemented. +# +start connect 0x07 + aal + blli + connid - !pnni + epref + notify + conned + connedsub + eetd + git UNI_NUM_IE_GIT + uu - !pnni + traffic + exqos + facility - q2932 + abrsetup + abradd + called_soft - pnni + report - !pnni + unrec +end + +######################################################################### +# +# CONNECT ACKNOWLEDGE message +# +# References: +# Q.2931 11 +# +start connect_ack 0x0f !pnni + notify + unrec +end + +######################################################################### +# +# RELEASE message +# +# References: +# Q.2931 p. 11, 22* +# Q.2932.1 p. 18 +# Q.2957 p. 4 +# Q.2962 p. 3 +# UNI4.0 p. 6 +# PNNI1.0 pp. 179...180, 185...186* +# +# Notes: +# N-ISDN compatiblity not implemented. +# +start release 0x4d + cause 2 + notify + git UNI_NUM_IE_GIT + uu - !pnni + facility - q2932 + crankback - pnni + unrec +end + +######################################################################### +# +# RELEASE COMPLETE message +# +# References: +# Q.2931 p. 12 +# UNI4.0 p. 6 +# PNNI1.0 p. 180 +# +start release_compl 0x5a + cause 2 + git UNI_NUM_IE_GIT !pnni + uu - !pnni + crankback - pnni + unrec +end + +######################################################################### +# +# SETUP message +# +# References: +# Q.2931 13-14, 23-24* +# ...A4 7-9, 13-16* +# Q.2957 5 +# Q.2962 3 +# Q.2971 7 +# UNI4.0 6-7, 43, 57*, 60-61, 68-69, 78 +# PNNI1.0 180...182, 186* +# af-cs-0147.000 +# +# Notes: +# +start setup 0x05 + aal + traffic + bearer + bhli + blli UNI_NUM_IE_BLLI/R + called + calledsub UNI_NUM_IE_CALLEDSUB + calling + callingsub UNI_NUM_IE_CALLINGSUB + connid + qos + eetd + notify + scompl - !pnni + tns UNI_NUM_IE_TNS + epref + atraffic + mintraffic + uu - !pnni + git UNI_NUM_IE_GIT + lij_callid - !pnni + lij_param - !pnni + lij_seqno - !pnni + exqos + abrsetup + abradd + cscope + calling_soft - pnni + called_soft - pnni + dtl UNI_NUM_IE_DTL/R pnni + report - !pnni + mdcr + unrec +end + +######################################################################### +# +# STATUS message +# +# References: +# Q.2931 p. 14 +# Q.2971 p. 8 +# PNNI1.0 p. 182 +# +start status 0x7d + callstate + cause + epref + epstate + unrec +end + +######################################################################### +# +# STATUS ENQUIRY message +# +# References: +# Q.2931 p. 15 +# Q.2971 p. 8 +# PNNI1.0 pp. 182...183 +# +start status_enq 0x75 + epref + unrec +end + +######################################################################### +# +# NOTIFY message +# +# References: +# Q.2931 p. 15 +# Q.2971 p. 8 +# PNNI1.0 p. 183 +# +start notify 0x6e + notify + epref + unrec +end + +######################################################################### +# +# RESTART message +# +# References: +# Q.2931 p. 26 +# UNI4.0 p. 7 +# PNNI1.0 pp. 186...187 +# +start restart 0x46 + connid + restart + unrec +end + +######################################################################### +# +# RESTART ACKNOWLEDGE message +# +# References: +# Q.2931 p. 26 +# UNI4.0 p. 7 +# PNNI1.0 p. 187 +# +start restart_ack 0x4e + connid + restart + unrec +end + +######################################################################### +# +# ADD PARTY message +# +# References: +# Q.2971 10, 47 +# UNI4.0 39, 43-44 +# PNNI1.0 188...189 +# +# Notes: +# +start add_party 0x80 + aal + bhli + blli + called + calledsub UNI_NUM_IE_CALLEDSUB + calling + callingsub UNI_NUM_IE_CALLINGSUB + scompl - !pnni + tns UNI_NUM_IE_TNS + epref + notify + eetd + uu - !pnni + git UNI_NUM_IE_GIT + lij_seqno - !pnni + calling_soft - pnni + called_soft - pnni + dtl UNI_NUM_IE_DTL/R pnni + unrec +end + +######################################################################### +# +# ADD PARTY ACKNOWLEDGE message +# +# References: +# Q.2971 10, 42, 47 +# UNI4.0 39 +# PNNI1.0 189 +# +# Notes: +# +start add_party_ack 0x81 + epref + aal + blli + notify + eetd + conned + connedsub + uu - !pnni + git UNI_NUM_IE_GIT + called_soft - pnni + unrec +end + +######################################################################### +# +# PARTY ALERTING message +# +# References: +# Q.2971 12, 49 +# UNI4.0 39 +# PNNI1.0 189...190 +# +# Notes: +# +start party_alerting 0x85 + epref + notify + uu - !pnni + git UNI_NUM_IE_GIT + unrec +end + +######################################################################### +# +# ADD PARTY REJECT message +# +# References: +# Q.2971 12, 48 +# UNI4.0 40 +# PNNI1.0 190 +# +# Notes: +# +start add_party_rej 0x82 + cause + epref + uu - !pnni + git UNI_NUM_IE_GIT + crankback - pnni + unrec +end + +######################################################################### +# +# DROP PARTY message +# +# References: +# Q.2971 13, 48 +# UNI4.0 40 +# PNNI1.0 191 +# +# Notes: +# +start drop_party 0x83 + cause + epref + notify + uu - !pnni + git UNI_NUM_IE_GIT + unrec +end + +######################################################################### +# +# DROP PARTY ACKNOWLEDGE message +# +# References: +# Q.2971 13, 49 +# UNI4.0 40 +# PNNI1.0 191 +# +# Notes: +# +start drop_party_ack 0x84 + epref + cause + uu - !pnni + git UNI_NUM_IE_GIT + unrec +end + +######################################################################### +# +# LEAF SETUP REQUEST message +# +# References: +# UNI4.0 45...46 +# +# Notes: +# +start leaf_setup_req 0x91 !pnni + tns UNI_NUM_IE_TNS + calling + callingsub UNI_NUM_IE_CALLINGSUB + called + calledsub UNI_NUM_IE_CALLEDSUB + lij_callid + lij_seqno + unrec +end + +######################################################################### +# +# LEAF SETUP FAIL message +# +# References: +# UNI4.0 45...46 +# +# Notes: +# +start leaf_setup_fail 0x90 !pnni + cause + called + calledsub + lij_seqno + tns UNI_NUM_IE_TNS + unrec +end + +######################################################################### +# +# CO-BI SETUP message +# +# References: +# Q.2932.1 16 +# +# Notes: +# +start cobisetup 0x15 !pnni&&q2932 + facility + called + calledsub + calling + notify + unrec +end + +######################################################################### +# +# FACILITY message +# +# References: +# Q.2932.1 14...15 +# +# Notes: +# +start facility 0x62 !pnni&&q2932 + facility + called + calledsub + calling + notify + unrec +end + +######################################################################### +# +# MODIFY REQUEST message +# +# References: +# Q.2963.1 p. 6 +# Q.2963.4 p. 4 +# UNI4.0-MFY p. 3 +# +start modify_req 0x88 !pnni + traffic + atraffic + mintraffic + notify + git UNI_NUM_IE_GIT + unrec +end + +######################################################################### +# +# MODIFY ACKNOWLEDGE message +# +# References: +# Q.2963.1 p.6 +# Q.2963.3 p.5 +# UNI4.0-MFY p.3 +# +start modify_ack 0x89 !pnni + report + traffic + notify + git UNI_NUM_IE_GIT + unrec +end + +######################################################################### +# +# MODIFY REJECT message +# +# References: +# Q.2963 p.6 +# UNI4.0-MFY p.3 +# +start modify_rej 0x8a !pnni + cause + notify + git UNI_NUM_IE_GIT + unrec +end + +######################################################################### +# +# CONNECTION AVAILABLE message +# +# References: +# Q.2931A4 9...10 +# Q.2963 p.6 +# UNI4.0-MFY p.3 +# +start conn_avail 0x8b !pnni + notify + git UNI_NUM_IE_GIT + report + unrec +end + +######################################################################### +# +# UNKNOWN message +# +start unknown 0x100 + epref + unrec +end diff --git a/sys/contrib/ngatm/netnatm/msg/parseie.awk b/sys/contrib/ngatm/netnatm/msg/parseie.awk new file mode 100644 index 000000000000..14bd0f876978 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/parseie.awk @@ -0,0 +1,150 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# $Begemot: libunimsg/netnatm/msg/parseie.awk,v 1.3 2003/09/19 11:58:15 hbb Exp $ +# +# Parse the IE definition file +# +match($0, "Begemot:")!=0 { + gsub("^[^$]*", "") + gsub("[^$]*$", "") + id = $0 + next +} + +/^#/ { + next +} +NF == 0 { + next +} + +BEGIN { + iecnt = 0 + id = " * ???" + begin() +} + +END { + end() +} + +# +# Syntax is: +# element <name> <code> <coding> [<maxlen> [<options>*]] +# +$1=="element" { + if(iecnt == 0) first_element() + if(NF < 4) { + error("Bad number of args: " $0) + } + ie = $2 + file = $2 + number = parse_hex($3) + coding = $4 + if(coding == "itu") { + ncoding = 0 + } else if(coding == "net") { + ncoding = 3 + } else { + error("bad coding " coding) + } + if(NF == 4) { + element_default() + file="" + } else { + len = $5 + parse_options() + element() + } + ies[iecnt] = ie + codings[iecnt] = coding + files[iecnt] = file + iecnt++ + next +} + +{ + error("Bad line: " $0) +} + +function parse_options() { + access = 0 + cond = "" + for(i = 6; i <= NF; i++) { + if($i == "access") { + access = 1 + } else if($i == "-") { + } else if(index($i, "file=") == 1) { + file=substr($i, 6) + } else { + if(cond != "") { + error("Too many conditions: "$0) + } + cond = $i + } + } +} + +function parse_hex(str, n) +{ + n = 0 + if(substr(str,1,2) != "0x") { + error("bad hex number" str) + } + for(i = 3; i <= length(str); i++) { + c = substr(str,i,1) + if(match(c,"[0-9]") != 0) { + n = 16 * n + c + } else if(match(c,"[a-f]")) { + if(c == "a") n = 16 * n + 10 + if(c == "b") n = 16 * n + 11 + if(c == "c") n = 16 * n + 12 + if(c == "d") n = 16 * n + 13 + if(c == "e") n = 16 * n + 14 + if(c == "f") n = 16 * n + 15 + } else if(match(c,"[A-F]")) { + if(c == "A") n = 16 * n + 10 + if(c == "B") n = 16 * n + 11 + if(c == "C") n = 16 * n + 12 + if(c == "D") n = 16 * n + 13 + if(c == "E") n = 16 * n + 14 + if(c == "F") n = 16 * n + 15 + } else { + error("bad hex digit '" c "'") + } + } + return n +} + +# function error(str) +# { +# print "error:" str >"/dev/stderr" +# exit 1 +# } + diff --git a/sys/contrib/ngatm/netnatm/msg/parsemsg.awk b/sys/contrib/ngatm/netnatm/msg/parsemsg.awk new file mode 100644 index 000000000000..ff13874d4509 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/parsemsg.awk @@ -0,0 +1,138 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# $Begemot: libunimsg/netnatm/msg/parsemsg.awk,v 1.3 2003/09/19 11:58:15 hbb Exp $ +# +# Parse the message definition file +# +match($0, "Begemot:")!=0 { + gsub("^[^$]*", "") + gsub("[^$]*$", "") + id = $0 + next +} + +/^#/ { + next +} +NF == 0 { + next +} +BEGIN { + state=0 + id = " * ???" + mcnt=0 + begin() +} +END { + end() +} + +state==0 && $1=="start" { + if(NF < 3) error("bad number of fields in message start "$0) + state = 1 + msg = $2 + code = parse_hex($3) + messages[mcnt] = msg + msgcond[mcnt] = $4 + msgrep = 0 + msgrepie = 0 + cnt = 0 + if(mcnt == 0) first_entry() + start_message() + next +} + +state==1 && $1=="end" { + state=0 + mcnt++ + end_message() + next +} +state==1 { + iename[cnt]=$1 + if($2 == "") $2="-" + if(match($2, "[A-Za-z][A-Za-z0-9_]*/R") == 1) { + ienum[cnt]=substr($2, 1, length($2)-2) + ierep[cnt]=1 + msgrepie=1 + } else { + ierep[cnt]=0 + ienum[cnt]=$2 + } + if(ienum[cnt] != "-") msgrep = 1 + if($3 == "" || $3 == "-") { + $3 = "1" + } else { + gsub("[a-zA-Z][a-zA-Z0-9]*", "cx->&", $3) + } + iecond[cnt] = $3 + cnt++ + next +} + +{ + error("bad line: "$0) +} + +function parse_hex(str, n) +{ + n = 0 + if(substr(str,1,2) != "0x") { + error("bad hex number" str) + } + for(i = 3; i <= length(str); i++) { + c = substr(str,i,1) + if(match(c,"[0-9]") != 0) { + n = 16 * n + c + } else if(match(c,"[a-f]")) { + if(c == "a") n = 16 * n + 10 + if(c == "b") n = 16 * n + 11 + if(c == "c") n = 16 * n + 12 + if(c == "d") n = 16 * n + 13 + if(c == "e") n = 16 * n + 14 + if(c == "f") n = 16 * n + 15 + } else if(match(c,"[A-F]")) { + if(c == "A") n = 16 * n + 10 + if(c == "B") n = 16 * n + 11 + if(c == "C") n = 16 * n + 12 + if(c == "D") n = 16 * n + 13 + if(c == "E") n = 16 * n + 14 + if(c == "F") n = 16 * n + 15 + } else { + error("bad hex digit '" c "'") + } + } + return n +} + +function error(str) +{ + print "error:" str >"/dev/stderr" + exit 1 +} diff --git a/sys/contrib/ngatm/netnatm/msg/priv.h b/sys/contrib/ngatm/netnatm/msg/priv.h new file mode 100644 index 000000000000..aa13fc467d46 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/priv.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/msg/priv.h,v 1.4 2003/10/10 14:50:05 hbb Exp $ + * + * Private definitions for the IE code file. + */ +#ifndef unimsg_priv_h +#define unimsg_priv_h + +#ifdef _KERNEL +#include <sys/systm.h> +#include <machine/stdarg.h> +#define PANIC(X) panic X +#else +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#define PANIC(X) abort() +#endif + +/* + * Define a structure for the declaration of information elements. + * For each coding scheme a quadrupel of check, print, encode and + * decode functions must be defined. A structure of the same format + * is used for messages. + */ +typedef void (*uni_print_f)(const union uni_ieall *, struct unicx *); +typedef int (*uni_check_f)(union uni_ieall *, struct unicx *); +typedef int (*uni_encode_f)(struct uni_msg *, union uni_ieall *, + struct unicx *); +typedef int (*uni_decode_f)(union uni_ieall *, struct uni_msg *, u_int, + struct unicx *); + +typedef void (*uni_msg_print_f)(const union uni_msgall *, struct unicx *); +typedef int (*uni_msg_check_f)(struct uni_all *, struct unicx *); +typedef int (*uni_msg_encode_f)(struct uni_msg *, union uni_msgall *, + struct unicx *); +typedef int (*uni_msg_decode_f)(union uni_msgall *, struct uni_msg *, + enum uni_ietype, struct uni_iehdr *, u_int, struct unicx *); + +struct iedecl { + u_int flags; /* information element flags */ + u_int maxlen; /* maximum size */ + uni_print_f print; + uni_check_f check; + uni_encode_f encode; + uni_decode_f decode; +}; + +struct msgdecl { + u_int flags; + const char *name; + uni_msg_print_f print; + uni_msg_check_f check; + uni_msg_encode_f encode; + uni_msg_decode_f decode; +}; + +enum { + UNIFL_DEFAULT = 0x0001, + UNIFL_ACCESS = 0x0002, +}; + +extern const struct iedecl *uni_ietable[256][4]; +extern const struct msgdecl *uni_msgtable[256]; + +/* + * Need to check range here because declaring a variable as a enum does not + * guarantee that the values will be legal. + */ +#define GET_IEDECL(IE, CODING) \ +({ \ + const struct iedecl *_decl = NULL; \ + \ + if((CODING) <= 3 && (IE) <= 255) \ + if((_decl = uni_ietable[IE][CODING]) != NULL) \ + if((_decl->flags & UNIFL_DEFAULT) != 0) \ + if((_decl = uni_ietable[IE][0]) == NULL) \ + PANIC(("IE %02x,%02x -- no default", CODING,IE));\ + _decl; \ +}) + + +enum { + DEC_OK, + DEC_ILL, + DEC_ERR, +}; + +void uni_print_ie_internal(enum uni_ietype, const union uni_ieall *, + struct unicx *); + +#endif diff --git a/sys/contrib/ngatm/netnatm/msg/privmsg.c b/sys/contrib/ngatm/netnatm/msg/privmsg.c new file mode 100644 index 000000000000..76a7f69aa3c6 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/privmsg.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/msg/privmsg.c,v 1.8 2003/10/10 14:50:05 hbb Exp $ + * + * Private definitions for the MSG code file. + * + * This file is included at the begin of the automatically generated + * uni_msg.c. + */ + +/* + * Decode a UNI message header. + * Return values: + * 0 - ok + * -1 - ignore message (proto, length, CR error) + */ +int +uni_decode_head(struct uni_msg *msg, struct uni_all *out, + struct unicx *cx __unused) +{ + u_int mlen; + + cx->errcnt = 0; + (void)memset(out, 0, sizeof(struct uni_all)); + + if(uni_msg_len(msg) < 9) + return -1; /* Q.2931 5.6.2 */ + if(cx->pnni) { + if(*msg->b_rptr++ != PNNI_PROTO) + return -1; /* Q.2931 5.6.1 */ + } else { + if(*msg->b_rptr++ != UNI_PROTO) + return -1; /* Q.2931 5.6.1 */ + } + if(*msg->b_rptr++ != 3) + return -1; /* Q.2931 5.6.3.1 */ + + out->u.hdr.cref.flag = (*msg->b_rptr & 0x80) ? 1 : 0; + out->u.hdr.cref.cref = (*msg->b_rptr++ & 0x7f) << 16; + out->u.hdr.cref.cref |= *msg->b_rptr++ << 8; + out->u.hdr.cref.cref |= *msg->b_rptr++; + + out->mtype = *msg->b_rptr++; + + /* + * Be not too piggy about this byte + */ + switch(*msg->b_rptr & 0x13) { + + case 0x00: case 0x01: case 0x02: case 0x03: + out->u.hdr.act = UNI_MSGACT_DEFAULT; + break; + + case 0x10: case 0x11: case 0x12: + out->u.hdr.act = *msg->b_rptr & 0x3; + break; + + case 0x13: /* Q.2931 5.7.1 */ + out->u.hdr.act = UNI_MSGACT_REPORT; + break; + } + if(cx->pnni && (*msg->b_rptr & 0x08)) + out->u.hdr.pass = 1; + else + out->u.hdr.pass = 0; + + msg->b_rptr++; + + mlen = *msg->b_rptr++ << 8; + mlen |= *msg->b_rptr++; + + /* + * If the message is longer than the indicated length + * shorten it. If it is shorter, probably one of the IE + * decoders will break, but we should proceed. 5.5.6.5 + */ +#if 0 + if(uni_msg_len(msg) > mlen) + msg->b_wptr = msg->b_rptr + mlen; +#endif + + return 0; +} + +static int +uni_decode_body_internal(enum uni_msgtype mtype, struct uni_msg *msg, + union uni_msgall *out, struct unicx *cx) +{ + enum uni_ietype ietype; + struct uni_iehdr hdr; + u_int ielen; + const struct iedecl *iedecl; + int err = 0, ret; + u_char *end; + + cx->ielast = (enum uni_ietype)0; + cx->repeat.h.present = 0; + + while (uni_msg_len(msg) != 0) { + if (uni_decode_ie_hdr(&ietype, &hdr, msg, cx, &ielen)) { + /* + * Short header. Set the ielen to an impossible size. + * Then we should bump out in the error handling below. + * We should have at least an IE type here. + */ + ielen = 0xffffffff; + } +#ifdef DTRACE + printf("IE %x\n", ietype); +#endif + + if ((iedecl = GET_IEDECL(ietype, hdr.coding)) == NULL || + ietype == UNI_IE_UNREC) { + /* + * entirly unknown IE. Check the length and skip it. + * Q.2931 5.6.8.1 + */ + if (ielen > uni_msg_len(msg)) + msg->b_rptr = msg->b_wptr; + else + msg->b_rptr += ielen; + (void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_UNK); + err = -1; + continue; + } +#ifdef DTRACE + printf("IE %x known\n", ietype); +#endif + if (ielen > iedecl->maxlen - 4 || ielen > uni_msg_len(msg)) { + /* + * Information element too long -> content error. + * Let the decoding routine set the error flag and + * return DEC_ERR. + * Q.2931 5.6.8.2 + */ +#if 0 + /* + * It is not clear how to best handle this error. + */ + if (ielen > iedecl->maxlen - 4) + ielen = iedecl->maxlen - 4; +#endif + + if (ielen > uni_msg_len(msg)) + ielen = uni_msg_len(msg); + + hdr.present |= UNI_IE_ERROR; + +#ifdef DTRACE + printf("IE %x length too large\n", ietype); +#endif + } + +#ifdef DTRACE + else + printf("IE %x length ok\n", ietype); +#endif + end = msg->b_rptr + ielen; + ret = uni_msgtable[mtype]->decode(out, msg, ietype, + &hdr, ielen, cx); + msg->b_rptr = end; + +#ifdef DTRACE + printf("IE %x ret %d\n", ietype, ret); +#endif + + switch (ret) { + + case DEC_OK: /* ok */ + break; + + case DEC_ILL: /* illegal IE */ + /* + * Unexpected but recognized. + * Q.2931 5.6.8.3 + */ + (void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_UNK); + err = -1; + break; + + case DEC_ERR: /* bad IE */ + if (iedecl->flags & UNIFL_ACCESS) + /* this may be wrong: 5.6.8.2 */ + (void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_ACC); + else + (void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_BAD); + err = -1; + break; + + default: + PANIC(("bad decode return")); + } + cx->ielast = ietype; + if (ietype != UNI_IE_REPEAT) + cx->repeat.h.present = 0; + } + return err; +} + +/* + * Decode the body of a message. The header is assumed to be decoded + * already and out->hdr is filled in. Only information elements remain. + */ +int +uni_decode_body(struct uni_msg *msg, struct uni_all *out, struct unicx *cx) +{ + cx->errcnt = 0; + if (out->mtype >= 256) + return (-1); + if (uni_msgtable[out->mtype] == NULL) + return (-1); + return (uni_decode_body_internal(out->mtype, msg, &out->u, cx)); +} + + +/* + * Decode a uni message + */ +int +uni_decode(struct uni_msg *msg, struct uni_all *out, struct unicx *cx) +{ + cx->errcnt = 0; + if (uni_decode_head(msg, out, cx)) + return (-1); + if (uni_decode_body(msg, out, cx)) + return (-2); + return (0); +} + +int +uni_encode(struct uni_msg *msg, struct uni_all *in, struct unicx *cx) +{ + if (in->mtype >= 256) + return (-1); + if (uni_msgtable[in->mtype] == NULL) + return (-3); + + return ((uni_msgtable[in->mtype]->encode)(msg, &in->u, cx)); +} + +/* + * Doesn't belong here + */ +void +uni_initcx(struct unicx *cx) +{ + memset(cx, 0, sizeof(struct unicx)); + cx->tabsiz = 4; +} diff --git a/sys/contrib/ngatm/netnatm/msg/traffic.c b/sys/contrib/ngatm/netnatm/msg/traffic.c new file mode 100644 index 000000000000..acaffdbbe7d4 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/traffic.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/msg/traffic.c,v 1.4 2004/07/08 08:22:05 brandt Exp $ + * + * Traffic classification + */ + +#include <netnatm/unimsg.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#ifdef _KERNEL +#include <sys/systm.h> +#else +#include <stdio.h> +#endif + +/* + * Try to set the parameters for the CPCS from the parameters of the + * connection. + */ +enum { + T_CBR23 = 100, T_nrtVBR2_6_UBR12, T_rtVBR236, T_rtVBR2_6 +}; + +static const u_int fmask = UNI_TRAFFIC_FPCR0_P | UNI_TRAFFIC_FPCR1_P | + UNI_TRAFFIC_FSCR0_P | UNI_TRAFFIC_FSCR1_P | UNI_TRAFFIC_FMBS0_P | + UNI_TRAFFIC_FMBS1_P | UNI_TRAFFIC_FABR1_P; +static const u_int bmask = UNI_TRAFFIC_BPCR0_P | UNI_TRAFFIC_BPCR1_P | + UNI_TRAFFIC_BSCR0_P | UNI_TRAFFIC_BSCR1_P | UNI_TRAFFIC_BMBS0_P | + UNI_TRAFFIC_BMBS1_P | UNI_TRAFFIC_BABR1_P; + +static const u_int fcbr3 = UNI_TRAFFIC_FPCR0_P | UNI_TRAFFIC_FPCR1_P; +static const u_int bcbr3 = UNI_TRAFFIC_BPCR0_P | UNI_TRAFFIC_BPCR1_P; +static const u_int fvbr16 = UNI_TRAFFIC_FPCR1_P | UNI_TRAFFIC_FSCR1_P | + UNI_TRAFFIC_FMBS1_P; +static const u_int bvbr16 = UNI_TRAFFIC_BPCR1_P | UNI_TRAFFIC_BSCR1_P | + UNI_TRAFFIC_BMBS1_P; +static const u_int fvbr23 = UNI_TRAFFIC_FPCR1_P | UNI_TRAFFIC_FSCR0_P | + UNI_TRAFFIC_FMBS0_P; +static const u_int bvbr23 = UNI_TRAFFIC_BPCR1_P | UNI_TRAFFIC_BSCR0_P | + UNI_TRAFFIC_BMBS0_P; +static const u_int fvbr4 = UNI_TRAFFIC_FPCR0_P | UNI_TRAFFIC_FPCR1_P; +static const u_int bvbr4 = UNI_TRAFFIC_BPCR0_P | UNI_TRAFFIC_BPCR1_P; + +int +uni_classify_traffic(const struct uni_ie_bearer *bearer, + const struct uni_ie_traffic *traffic, + enum uni_traffic_class *fclass, enum uni_traffic_class *bclass, + char *ebuf, size_t ebufsiz) +{ + u_int tclass; + u_int ft, bt, be, ftag, btag; + + /* classify */ + switch (bearer->bclass) { + + case UNI_BEARER_A: + if (!(bearer->h.present & UNI_BEARER_ATC_P)) { + tclass = T_CBR23; + break; + } + switch (bearer->atc) { + + case UNI_BEARER_ATC_CBR1: + tclass = UNI_TRAFFIC_CBR1; + break; + + default: + snprintf(ebuf, ebufsiz, "bad ATC=%#02x for BCOB-A", + bearer->atc); + return (-1); + } + break; + + case UNI_BEARER_C: + if (!(bearer->h.present & UNI_BEARER_ATC_P)) { + tclass = T_nrtVBR2_6_UBR12; + break; + } + switch (bearer->atc) { + + case UNI_BEARER_ATC_VBR1: + tclass = UNI_TRAFFIC_rtVBR1; + break; + + case UNI_BEARER_ATC_VBR: + tclass = T_rtVBR236; + break; + + case UNI_BEARER_ATC_NVBR1: + tclass = UNI_TRAFFIC_nrtVBR1; + break; + + case UNI_BEARER_ATC_ABR: + tclass = UNI_TRAFFIC_ABR; + break; + + default: + snprintf(ebuf, ebufsiz, "bad ATC=%#02x for BCOB-C", + bearer->atc); + return (-1); + } + break; + + case UNI_BEARER_X: + if (!(bearer->h.present & UNI_BEARER_ATC_P)) { + tclass = T_nrtVBR2_6_UBR12; + break; + } + switch (bearer->atc) { + + case UNI_BEARER_ATC_CBR1: + tclass = UNI_TRAFFIC_CBR1; + break; + + case UNI_BEARER_ATC_CBR: + case UNI_BEARER_ATCX_4: + case UNI_BEARER_ATCX_6: + tclass = T_CBR23; + break; + + case UNI_BEARER_ATC_VBR1: + tclass = UNI_TRAFFIC_rtVBR1; + break; + + case UNI_BEARER_ATCX_1: + case UNI_BEARER_ATC_VBR: + tclass = T_rtVBR2_6; + break; + + case UNI_BEARER_ATC_NVBR1: + tclass = UNI_TRAFFIC_nrtVBR1; + break; + + case UNI_BEARER_ATCX_0: + case UNI_BEARER_ATCX_2: + case UNI_BEARER_ATCX_8: + case UNI_BEARER_ATC_NVBR: + tclass = T_nrtVBR2_6_UBR12; + break; + + case UNI_BEARER_ATC_ABR: + tclass = UNI_TRAFFIC_ABR; + break; + + default: + snprintf(ebuf, ebufsiz, "bad ATC=%#02x for BCOB-X", + bearer->atc); + return (-1); + } + break; + + case UNI_BEARER_TVP: + snprintf(ebuf, ebufsiz, "unsupported bearer class tVP"); + return (-1); + + default: + snprintf(ebuf, ebufsiz, "bad bearer class %#02x", + bearer->bclass); + return (-1); + } + + /* + * Now traffic IE + */ + ft = traffic->h.present & fmask; + bt = traffic->h.present & bmask; + be = traffic->h.present & UNI_TRAFFIC_BEST_P; + ftag = (traffic->h.present & UNI_TRAFFIC_MOPT_P) && traffic->t.ftag; + btag = (traffic->h.present & UNI_TRAFFIC_MOPT_P) && traffic->t.btag; + +#define NOBE(C) \ + if (be) { \ + snprintf(ebuf, ebufsiz, "illegal BE for " C); \ + return (-1); \ + } + +#define NOFT(C) \ + if (ftag) { \ + snprintf(ebuf, ebufsiz, "illegal forward tag in " C); \ + return (-1); \ + } + +#define NOBT(C) \ + if (btag) { \ + snprintf(ebuf, ebufsiz, "illegal backward tag in " C); \ + return (-1); \ + } + +#define FBAD(C) do { \ + snprintf(ebuf, ebufsiz, "bad forward CRs for " C); \ + return (-1); \ + } while (0) + +#define BBAD(C) do { \ + snprintf(ebuf, ebufsiz, "bad backward CRs for " C); \ + return (-1); \ + } while (0) + + switch (tclass) { + + case UNI_TRAFFIC_CBR1: + NOBE("CBR.1"); + if (ft != UNI_TRAFFIC_FPCR1_P) + FBAD("CBR.1"); + NOFT("CBR.1"); + if (bt != UNI_TRAFFIC_BPCR1_P) + BBAD("CBR.1"); + NOBT("CBR.1"); + *fclass = *bclass = UNI_TRAFFIC_CBR1; + break; + + case T_CBR23: + NOBE("CBR.2/3"); + if (ft == UNI_TRAFFIC_FPCR0_P) { + *fclass = UNI_TRAFFIC_CBR2; + NOFT("CBR.2"); + } else if (ft == fcbr3) { + *fclass = UNI_TRAFFIC_CBR3; + if (!ftag) { + snprintf(ebuf, ebufsiz, "need forward tagging for CBR.3"); + return (-1); + } + } else + FBAD("CBR.2/3"); + if (bt == UNI_TRAFFIC_BPCR0_P) { + *bclass = UNI_TRAFFIC_CBR2; + NOBT("CBR.2"); + } else if (bt == bcbr3) { + *bclass = UNI_TRAFFIC_CBR3; + if (!btag) { + snprintf(ebuf, ebufsiz, "need backward tagging for CBR.3"); + return (-1); + } + } else + BBAD("CBR.2/3"); + break; + + case UNI_TRAFFIC_rtVBR1: + NOBE("rtVBR.1"); + if (ft != fvbr16) + FBAD("rtVBR.1"); + NOFT("rtVBR.1"); + if (bt != bvbr16) + BBAD("rtVBR.1"); + NOBT("rtVBR.1"); + *fclass = *bclass = UNI_TRAFFIC_rtVBR1; + break; + + case T_rtVBR236: + NOBE("rtVBR.2/3/6"); + if (ft == fvbr23) { + if (ftag) + *fclass = UNI_TRAFFIC_rtVBR3; + else + *fclass = UNI_TRAFFIC_rtVBR2; + } else if (ft == fvbr16) { + *fclass = UNI_TRAFFIC_rtVBR6; + NOFT("rtVBR.6"); + } else + FBAD("rtVBR.2/3/6"); + if (bt == bvbr23) { + if (btag) + *bclass = UNI_TRAFFIC_rtVBR3; + else + *bclass = UNI_TRAFFIC_rtVBR2; + } else if (bt == bvbr16) { + *bclass = UNI_TRAFFIC_rtVBR6; + NOBT("rtVBR.6"); + } else + BBAD("rtVBR.2/3/6"); + break; + + case T_rtVBR2_6: + NOBE("rtVBR.2-6"); + if (ft == fvbr23) { + if (ftag) + *fclass = UNI_TRAFFIC_rtVBR3; + else + *fclass = UNI_TRAFFIC_rtVBR2; + } else if (ft == fvbr4) { + *fclass = UNI_TRAFFIC_rtVBR4; + } else if (ft == UNI_TRAFFIC_FPCR1_P) { + *fclass = UNI_TRAFFIC_rtVBR5; + NOFT("rtVBR.5"); + } else if (ft == fvbr16) { + *fclass = UNI_TRAFFIC_rtVBR6; + NOFT("rtVBR.6"); + } else + FBAD("rtVBR.2-6"); + if (bt == bvbr23) { + if (btag) + *bclass = UNI_TRAFFIC_rtVBR3; + else + *bclass = UNI_TRAFFIC_rtVBR2; + } else if (bt == bvbr4) { + *bclass = UNI_TRAFFIC_rtVBR4; + } else if (bt == UNI_TRAFFIC_BPCR1_P) { + *bclass = UNI_TRAFFIC_rtVBR5; + NOBT("rtVBR.5"); + } else if (bt == bvbr16) { + *bclass = UNI_TRAFFIC_rtVBR6; + NOBT("rtVBR.6"); + } else + BBAD("rtVBR.2-6"); + break; + + case UNI_TRAFFIC_nrtVBR1: + NOBE("nrtVBR.1"); + if (ft != fvbr16) + FBAD("nrtVBR.1"); + NOFT("nrtVBR.1"); + if (bt != bvbr16) + BBAD("nrtVBR.1"); + NOBT("nrtVBR.1"); + *fclass = *bclass = UNI_TRAFFIC_nrtVBR1; + break; + + case T_nrtVBR2_6_UBR12: + if (be) { + if (ft != UNI_TRAFFIC_FPCR1_P) + FBAD("UBR.1/2"); + if (bt != UNI_TRAFFIC_BPCR1_P) + BBAD("UBR.1/2"); + if (ftag) + *fclass = UNI_TRAFFIC_UBR2; + else + *fclass = UNI_TRAFFIC_UBR1; + if (btag) + *bclass = UNI_TRAFFIC_UBR2; + else + *bclass = UNI_TRAFFIC_UBR1; + break; + } + if (ft == fvbr23) { + if (ftag) + *fclass = UNI_TRAFFIC_nrtVBR3; + else + *fclass = UNI_TRAFFIC_nrtVBR2; + } else if (ft == fvbr4) { + *fclass = UNI_TRAFFIC_nrtVBR4; + } else if (ft == UNI_TRAFFIC_FPCR1_P) { + *fclass = UNI_TRAFFIC_nrtVBR5; + NOFT("nrtVBR.5"); + } else if (ft == fvbr16) { + *fclass = UNI_TRAFFIC_nrtVBR6; + NOFT("nrtVBR.6"); + } else + FBAD("nrtVBR.2-6"); + if (bt == bvbr23) { + if (btag) + *bclass = UNI_TRAFFIC_nrtVBR3; + else + *bclass = UNI_TRAFFIC_nrtVBR2; + } else if (bt == bvbr4) { + *bclass = UNI_TRAFFIC_nrtVBR4; + } else if (bt == UNI_TRAFFIC_BPCR1_P) { + *bclass = UNI_TRAFFIC_nrtVBR5; + NOBT("nrtVBR.5"); + } else if (bt == bvbr16) { + *bclass = UNI_TRAFFIC_nrtVBR6; + NOBT("nrtVBR.6"); + } else + BBAD("nrtVBR.2-6"); + break; + + case UNI_TRAFFIC_ABR: + NOBE("ABR"); + if (ft != UNI_TRAFFIC_FPCR1_P) + FBAD("ABR"); + if (bt != UNI_TRAFFIC_BPCR1_P) + BBAD("ABR"); + NOFT("ABR"); + NOBT("ABR"); + *fclass = *bclass = UNI_TRAFFIC_ABR; + break; + } + + return (0); +} diff --git a/sys/contrib/ngatm/netnatm/msg/uni_config.h b/sys/contrib/ngatm/netnatm/msg/uni_config.h new file mode 100644 index 000000000000..e53f59b8395c --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/uni_config.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/msg/uni_config.h,v 1.3 2003/09/19 11:58:15 hbb Exp $ + */ +#ifndef _uni_uni_config_h_ +#define _uni_uni_config_h_ + +enum { + /* maximum number of reported error IEs */ + UNI_MAX_ERRIE = 50, + + /* maximum number of Generic Identifier Transport IE's per message */ + UNI_NUM_IE_GIT = 3, + + /* maximum number of BLLI's in SETUP */ + UNI_NUM_IE_BLLI = 3, + + /* maximum number of CALLEDSUB's */ + UNI_NUM_IE_CALLEDSUB = 2, + + /* maximum number of CALLINGSUB's */ + UNI_NUM_IE_CALLINGSUB = 2, + + /* maximum number of TNS's */ + UNI_NUM_IE_TNS = 4, + + /* maximum length of TNS name */ + UNI_TNS_MAXLEN = 4, + + /* maximum info size in user-to-user signalling IE */ + UNI_UU_MAXLEN = 128, + + /* maximum length of address */ + UNI_ADDR_MAXLEN = 20, + + /* maximum length of subaddress */ + UNI_SUBADDR_MAXLEN = 20, + + /* maximum number of DTLs */ + UNI_NUM_IE_DTL = 10, + /* maximum number of identifiers in DTL */ + UNI_DTL_MAXNUM = 20, +}; +#endif diff --git a/sys/contrib/ngatm/netnatm/msg/uni_hdr.h b/sys/contrib/ngatm/netnatm/msg/uni_hdr.h new file mode 100644 index 000000000000..c9a30f12be5d --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/uni_hdr.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/msg/uni_hdr.h,v 1.6 2004/07/08 08:22:05 brandt Exp $ + */ +#ifndef _NETNATM_MSG_UNI_HDR_H_ +#define _NETNATM_MSG_UNI_HDR_H_ + +#include <sys/types.h> +#ifdef _KERNEL +#include <sys/stdint.h> +#else +#include <stdint.h> +#endif + +#include <netnatm/msg/uni_config.h> + +enum { + UNI_PROTO = 0x09, /* protocol discriminator */ + PNNI_PROTO = 0xf0, /* PNNI protocol discriminator */ +}; + +/* + * Message types + */ +enum uni_msgtype { + UNI_UNKNOWN = 0x100,/* unknown message */ + + UNI_ALERTING = 0x01, /* alerting */ + UNI_CALL_PROC = 0x02, /* call proceeding */ + UNI_SETUP = 0x05, /* setup */ + UNI_CONNECT = 0x07, /* connect */ + UNI_CONNECT_ACK = 0x0f, /* connect ack */ + + UNI_RESTART = 0x46, /* restart */ + UNI_RELEASE = 0x4d, /* release */ + UNI_RESTART_ACK = 0x4e, /* restart acknowledgement */ + UNI_RELEASE_COMPL = 0x5a, /* release complete */ + + UNI_NOTIFY = 0x6e, /* notify user */ + UNI_STATUS_ENQ = 0x75, /* status enquiry */ + UNI_STATUS = 0x7d, /* status */ + + UNI_ADD_PARTY = 0x80, /* add party */ + UNI_ADD_PARTY_ACK = 0x81, /* add party acknowledgement */ + UNI_ADD_PARTY_REJ = 0x82, /* add party reject */ + UNI_DROP_PARTY = 0x83, /* drop party */ + UNI_DROP_PARTY_ACK = 0x84, /* drop party acknowledgement */ + UNI_PARTY_ALERTING = 0x85, /* party alerting */ + + UNI_LEAF_SETUP_FAIL = 0x90, /* leaf setup failed */ + UNI_LEAF_SETUP_REQ = 0x91, /* leaf setup request */ + + UNI_COBISETUP = 0x15, /* Q.2932 COBI-setup */ + UNI_FACILITY = 0x62, /* Q.2932 facility */ + + UNI_MODIFY_REQ = 0x88, /* Q.2963 Modify request */ + UNI_MODIFY_ACK = 0x89, /* Q.2963 Modify acknowledgement */ + UNI_MODIFY_REJ = 0x8a, /* Q.2963 Modify reject */ + UNI_CONN_AVAIL = 0x8b, /* Q.2963 Connection available */ +}; + +/* + * Information element types + */ +enum uni_ietype { + UNI_IE_CAUSE = 0x08, /* cause */ + UNI_IE_CALLSTATE = 0x14, /* call state */ + UNI_IE_FACILITY = 0x1C, /* Q.2932 facility IE */ + UNI_IE_NOTIFY = 0x27, /* UNI4.0 notify */ + UNI_IE_EETD = 0x42, /* UNI4.0 end-to-end transit delay */ + UNI_IE_CONNED = 0x4c, /* UNI4.0/Q.2951 connected address */ + UNI_IE_CONNEDSUB = 0x4d, /* UNI4.0/Q.2951 connected subaddress */ + UNI_IE_EPREF = 0x54, /* endpoint reference */ + UNI_IE_EPSTATE = 0x55, /* enpoint state */ + UNI_IE_AAL = 0x58, /* ATM adaptation layer parameters */ + UNI_IE_TRAFFIC = 0x59, /* ATM traffic descriptor */ + UNI_IE_CONNID = 0x5a, /* connection identifier */ + UNI_IE_QOS = 0x5c, /* quality of service parameter */ + UNI_IE_BHLI = 0x5d, /* broadband higher layer information */ + UNI_IE_BEARER = 0x5e, /* broadband bearer capability */ + UNI_IE_BLLI = 0x5f, /* broadband lower layer information */ + UNI_IE_LSHIFT = 0x60, /* broadband locking shift */ + UNI_IE_NLSHIFT = 0x61, /* broadband non-locking shift */ + UNI_IE_SCOMPL = 0x62, /* broadband sending complete */ + UNI_IE_REPEAT = 0x63, /* broadband repeat indicator */ + UNI_IE_CALLING = 0x6c, /* calling party number */ + UNI_IE_CALLINGSUB = 0x6d, /* calling party subaddress */ + UNI_IE_CALLED = 0x70, /* called party number */ + UNI_IE_CALLEDSUB = 0x71, /* called party subaddress */ + UNI_IE_TNS = 0x78, /* transit network selection */ + UNI_IE_RESTART = 0x79, /* restart indicator */ + UNI_IE_UU = 0x7e, /* UNI4.0/Q.2957 user-to-user info */ + UNI_IE_GIT = 0x7f, /* UNI4.0 generic identifier transport*/ + UNI_IE_MINTRAFFIC = 0x81, /* Q.2962 minimum traffic desc */ + UNI_IE_ATRAFFIC = 0x82, /* Q.2962 alternate traffic desc */ + UNI_IE_ABRSETUP = 0x84, /* UNI4.0 ABR setup parameters */ + UNI_IE_REPORT = 0x89, /* Q.2963 broadband report type */ + UNI_IE_CALLED_SOFT = 0xe0, /* PNNI Calling party soft PVPC */ + UNI_IE_CRANKBACK = 0xe1, /* PNNI Crankback */ + UNI_IE_DTL = 0xe2, /* PNNI designated transit list */ + UNI_IE_CALLING_SOFT = 0xe3, /* PNNI Called party soft PVPC */ + UNI_IE_ABRADD = 0xe4, /* UNI4.0 ABR additional parameters */ + UNI_IE_LIJ_CALLID = 0xe8, /* UNI4.0 LIF call identifier */ + UNI_IE_LIJ_PARAM = 0xe9, /* UNI4.0 LIF parameters */ + UNI_IE_LIJ_SEQNO = 0xea, /* UNI4.0 LIF sequence number */ + UNI_IE_CSCOPE = 0xeb, /* UNI4.0 connection scope selection */ + UNI_IE_EXQOS = 0xec, /* UNI4.0 extended QoS parameters */ + UNI_IE_MDCR = 0xf0, /* UNI4.0+ Minimum desired call rate */ + UNI_IE_UNREC = 0xfe, +}; + +enum uni_coding { + UNI_CODING_ITU = 0x0, + UNI_CODING_NET = 0x3, +}; + +enum uni_msgact { + UNI_MSGACT_CLEAR = 0x0, + UNI_MSGACT_IGNORE = 0x1, + UNI_MSGACT_REPORT = 0x2, + + UNI_MSGACT_DEFAULT = 0x4 +}; + +enum uni_ieact { + UNI_IEACT_CLEAR = 0x00, /* clear call */ + UNI_IEACT_IGNORE = 0x01, /* ignore IE and proceed */ + UNI_IEACT_REPORT = 0x02, /* ignore IE, report and proceed */ + UNI_IEACT_MSG_IGNORE = 0x05, /* ignore message */ + UNI_IEACT_MSG_REPORT = 0x06, /* ignore message and report */ + + UNI_IEACT_DEFAULT = 0x08 +}; + +struct uni_cref { + u_int flag; + u_int cref; +}; + +/* + * Message header. + */ +struct uni_msghdr { + struct uni_cref cref; + enum uni_msgact act; /* action indicator */ + u_int pass:1; /* PNNI pass along request */ +}; + +enum { + CREF_GLOBAL = 0, + CREF_DUMMY = 0x7fffff, +}; + +/* + * General information element header. + */ +struct uni_iehdr { + enum uni_coding coding; /* coding standard */ + enum uni_ieact act; /* action indicator */ + u_int pass : 1; /* PNNI pass along request */ + u_int present; /* which optional elements are present */ +#define UNI_IE_EMPTY 0x80000000 +#define UNI_IE_PRESENT 0x40000000 +#define UNI_IE_ERROR 0x20000000 +#define UNI_IE_XXX 0x10000000 +#define UNI_IE_MASK 0xf0000000 +}; + +#define IE_ISPRESENT(IE) \ + (((IE).h.present & (UNI_IE_PRESENT|UNI_IE_EMPTY)) == UNI_IE_PRESENT) +#define IE_SETPRESENT(IE) \ + ((IE).h.present = ((IE).h.present & ~UNI_IE_MASK) | \ + UNI_IE_PRESENT) + +#define IE_ADDPRESENT(IE) \ + ((IE).h.present = ((IE).h.present & ~UNI_IE_EMPTY) | \ + UNI_IE_PRESENT) + +#define IE_ISEMPTY(IE) \ + (((IE).h.present & UNI_IE_MASK) == (UNI_IE_PRESENT | UNI_IE_EMPTY)) +#define IE_SETEMPTY(IE) \ + ((IE).h.present = ((IE).h.present & ~UNI_IE_MASK) | \ + UNI_IE_EMPTY | UNI_IE_PRESENT) + +#define IE_ISERROR(IE) \ + (((IE).h.present & UNI_IE_MASK) == (UNI_IE_PRESENT | UNI_IE_ERROR)) +#define IE_SETERROR(IE) \ + ((IE).h.present = ((IE).h.present & ~UNI_IE_MASK) | \ + UNI_IE_ERROR | UNI_IE_PRESENT) + +#define IE_ISGOOD(IE) \ + (((IE).h.present & UNI_IE_MASK) == (UNI_IE_PRESENT)) + +#endif diff --git a/sys/contrib/ngatm/netnatm/msg/uni_ie.c b/sys/contrib/ngatm/netnatm/msg/uni_ie.c new file mode 100644 index 000000000000..e4b8310d88d9 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/uni_ie.c @@ -0,0 +1,7166 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/msg/uni_ie.c,v 1.16 2005/05/23 12:06:30 brandt_h Exp $ + * + * Private definitions for the IE code file. + * + * This file includes the table generated automatically. + */ + +#include <sys/types.h> +#include <sys/param.h> + +#ifdef _KERNEL +#include <sys/libkern.h> +#else +#include <string.h> +#endif +#include <netnatm/unimsg.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#include <netnatm/msg/uniprint.h> +#include <netnatm/msg/priv.h> + +#define UNUSED(_p) do { (void)(_p); } while (0) + +/* + * Define internal functions. + */ +#define DEF_IE_PRINT(Coding, IE) \ + void uni_ie_print_##Coding##_##IE(struct uni_ie_##IE *ie, struct unicx *cx) + +#define DEF_IE_CHECK(Coding, IE) \ + int uni_ie_check_##Coding##_##IE(struct uni_ie_##IE *ie, struct unicx *cx) + +#define DEF_IE_ENCODE(Coding, IE) \ + int uni_ie_encode_##Coding##_##IE(struct uni_msg *msg, struct uni_ie_##IE *ie, struct unicx *cx) + +#define DEF_IE_DECODE(Coding, IE) \ + int uni_ie_decode_##Coding##_##IE(struct uni_ie_##IE *ie, struct uni_msg *msg, u_int ielen, struct unicx *cx) + +/* + * This structure is used to define value->string mappings. MKT() is used + * to generate a table entry. EOT() to end the table. + */ +#define MKT(V,N) { #N, V } +#define EOT() { NULL, 0 } + +/* library internal functions */ +static void uni_entry(const char *, struct unicx *); +static int uni_print_iehdr(const char *, struct uni_iehdr *h, struct unicx *); +static void uni_print_ieend(struct unicx *); +static void uni_putc(int, struct unicx *); + + +/* + * Encoding + */ +#define APP_BYTE(M, B) do { \ + *(M)->b_wptr++ = (B); \ + } while (0) +#define APP_16BIT(M, B) do { \ + u_int _v = (B); \ + *(M)->b_wptr++ = _v >> 8; \ + *(M)->b_wptr++ = _v; \ + } while (0) +#define APP_24BIT(M, B) do { \ + u_int _v = (B); \ + *(M)->b_wptr++ = _v >> 16; \ + *(M)->b_wptr++ = _v >> 8; \ + *(M)->b_wptr++ = _v; \ + } while (0) +#define APP_32BIT(M, B) do { \ + u_int _v = (B); \ + *(M)->b_wptr++ = _v >> 24; \ + *(M)->b_wptr++ = _v >> 16; \ + *(M)->b_wptr++ = _v >> 8; \ + *(M)->b_wptr++ = _v; \ + } while (0) +#define APP_BUF(M, B, L) do { \ + (void)memcpy((M)->b_wptr, (B), (L)); \ + (M)->b_wptr += (L); \ + } while (0) + +#define APP_SUB_BYTE(M, T, B) do { APP_BYTE(M, T); APP_BYTE(M, B); } while (0) +#define APP_SUB_16BIT(M, T, B) do { APP_BYTE(M, T); APP_16BIT(M, B); } while (0) +#define APP_SUB_24BIT(M, T, B) do { APP_BYTE(M, T); APP_24BIT(M, B); } while (0) +#define APP_SUB_32BIT(M, T, B) do { APP_BYTE(M, T); APP_32BIT(M, B); } while (0) + +#define APP_OPT(M, F, P, T) do { \ + if ((F) & (P)) \ + APP_BYTE((M), (T)); \ + } while (0) +#define APP_OPT_BYTE(M, F, P, T, B) do { \ + if ((F) & (P)) \ + APP_SUB_BYTE((M), (T), (B)); \ + } while (0) +#define APP_OPT_16BIT(M, F, P, T, B) do { \ + if ((F) & (P)) \ + APP_SUB_16BIT((M), (T), (B)); \ + } while (0) +#define APP_OPT_24BIT(M, F, P, T, B) do { \ + if ((F) & (P)) \ + APP_SUB_24BIT((M), (T), (B)); \ + } while (0) + +#define START_IE(TYPE,CODE,LEN) \ + u_int ielen; \ + \ + if (uni_check_ie(CODE, (union uni_ieall *)ie, cx)) \ + return (-1); \ + if (uni_encode_ie_hdr(msg, CODE, &ie->h, (LEN), cx)) \ + return (0); \ + \ + ielen = msg->b_wptr - msg->b_rptr - 2; + +#define START_IE2(TYPE,CODE,LEN,REALCODE) \ + u_int ielen; \ + \ + if (uni_check_ie(CODE, (union uni_ieall *)ie, cx)) \ + return (-1); \ + if (uni_encode_ie_hdr(msg, REALCODE, &ie->h, (LEN), cx)) \ + return (0); \ + \ + ielen = msg->b_wptr - msg->b_rptr - 2; + +#define SET_IE_LEN(M) do { \ + (M)->b_buf[ielen + 0] = \ + (((M)->b_wptr - (M)->b_rptr) - ielen - 2) >> 8; \ + (M)->b_buf[ielen + 1] = \ + (((M)->b_wptr - (M)->b_rptr) - ielen - 2) >> 0; \ + } while (0) + + +/***********************************************************************/ +/* + * Decoding + */ +#define IE_START(ERR) \ + if (IE_ISPRESENT(*ie)) \ + return (0); \ + if (ielen == 0) { \ + IE_SETEMPTY(*ie); \ + return (0); \ + } + +#define IE_END(IE) \ + IE_SETPRESENT(*ie); \ + if (uni_check_ie(UNI_IE_##IE, (union uni_ieall *)ie, cx) == 0) \ + return (0); \ + rej: \ + ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT; \ + return (1); + +#define DEC_GETF3(ID, F, P) \ + case UNI_##ID##_ID: \ + if (ielen < 3) \ + goto rej; \ + ielen -= 3; \ + if (!(P & UNI_##ID##_P)) { \ + P |= UNI_##ID##_P; \ + ie->F = *msg->b_rptr++ << 16; \ + ie->F |= *msg->b_rptr++ << 8; \ + ie->F |= *msg->b_rptr++; \ + } else \ + msg->b_rptr += 3; \ + break; + +#define DEC_GETF1(ID, F, P) \ + case UNI_##ID##_ID: \ + if (ielen < 1) \ + goto rej; \ + ielen--; \ + if (!(P & UNI_##ID##_P)) { \ + P |= UNI_##ID##_P; \ + ie->F = *msg->b_rptr++; \ + } else \ + msg->b_rptr++; \ + break; + + +#define PRINT_NPREFIX (sizeof(((struct unicx *)0)->prefix) / \ + sizeof(((struct unicx *)0)->prefix[0])) + +/* + * This is rather here than in privmsg.c because we need the APP macros. + */ +int +uni_encode_msg_hdr(struct uni_msg *msg, struct uni_msghdr *h, + enum uni_msgtype type, struct unicx *cx, int *mlen) +{ + u_char byte; + + (void)uni_msg_ensure(msg, 9); + + APP_BYTE(msg, cx->pnni ? PNNI_PROTO : UNI_PROTO); + APP_BYTE(msg, 3); + if(h->cref.cref >= 1<<23) + return -1; + APP_24BIT(msg, h->cref.cref | (h->cref.flag ? 0x800000 : 0)); + APP_BYTE(msg, type); + + byte = 0x80; + if(h->act != UNI_MSGACT_DEFAULT) + byte |= 0x10 | (h->act & 3); + if(cx->pnni && h->pass) + byte |= 0x08; + APP_BYTE(msg, byte); + + *mlen = msg->b_wptr - msg->b_rptr; + APP_16BIT(msg, 0); + + return 0; +} + +/* + * Initialize printing. This must be called by all printing routines + * that are exported to the user. + */ +void +uni_print_init(char *buf, size_t bufsiz, struct unicx *cx) +{ + if (cx->dont_init) + return; + + cx->indent = 0; + cx->nprefix = 0; + cx->doindent = 0; + if (cx->tabsiz == 0) + cx->tabsiz = 4; + cx->buf = buf; + cx->bufsiz = bufsiz; +} + +/* + * Append a character to the buffer if there is still space + */ +static void +uni_putc(int c, struct unicx *cx) +{ + if(cx->bufsiz > 1) { + *cx->buf++ = c; + cx->bufsiz--; + *cx->buf = '\0'; + } +} + +void +uni_printf(struct unicx *cx, const char *fmt, ...) +{ + u_int n; + va_list ap; + + if(cx->bufsiz > 1) { + va_start(ap, fmt); + n = vsnprintf(cx->buf, cx->bufsiz, fmt, ap); + va_end(ap); + if(n > 0) { + if(n < cx->bufsiz) { + cx->bufsiz -= n; + cx->buf += n; + } else { + cx->buf += cx->bufsiz - 1; + cx->bufsiz = 1; + } + } + *cx->buf = '\0'; + } +} + +/* + * Print mode: + * 0 - print all into one line, fully prefixed + * 1 - print on multiple lines, full prefixed, but equal level + * entries on one line + * 2 - like 2, but only partial prefixed + * 3 - like 1, but each entry onto a new line + * 4 - like 2 + 3 + */ + +/* + * If we are in multiline mode, end the current line and set the + * flag, that we need indentation. But prevent double new lines. + */ +void +uni_print_eol(struct unicx *cx) +{ + if (cx->multiline) { + if (!cx->doindent) { + uni_putc('\n', cx); + cx->doindent = 1; + } + } +} + +/* + * New entry. Do the prefixing, indentation and spacing. + */ +static void +doprefix(struct unicx *cx, const char *s) +{ + u_int i; + + if(cx->multiline == 0) { + uni_putc(' ', cx); + for(i = 0; i < cx->nprefix; i++) + if(cx->prefix[i]) + uni_printf(cx, "%s.", cx->prefix[i]); + } else if(cx->multiline == 1) { + if(cx->doindent) { + uni_printf(cx, "%*s", cx->indent * cx->tabsiz, ""); + cx->doindent = 0; + } else + uni_putc(' ', cx); + for(i = 0; i < cx->nprefix; i++) + if(cx->prefix[i]) + uni_printf(cx, "%s.", cx->prefix[i]); + } else if(cx->multiline == 2) { + if(cx->doindent) { + uni_printf(cx, "%*s", cx->indent * cx->tabsiz, ""); + cx->doindent = 0; + } else + uni_putc(' ', cx); + } else if(cx->multiline == 3) { + if(cx->doindent) + cx->doindent = 0; + else + uni_putc('\n', cx); + uni_printf(cx, "%*s", cx->indent * cx->tabsiz, ""); + for(i = 0; i < cx->nprefix; i++) + if(cx->prefix[i]) + uni_printf(cx, "%s.", cx->prefix[i]); + } else if(cx->multiline == 4) { + if(cx->doindent) + cx->doindent = 0; + else + uni_putc('\n', cx); + uni_printf(cx, "%*s", cx->indent * cx->tabsiz, ""); + } + uni_printf(cx, "%s", s); +} +static void +uni_entry(const char *s, struct unicx *cx) +{ + doprefix(cx, s); + uni_putc('=', cx); +} +void +uni_print_flag(const char *s, struct unicx *cx) +{ + doprefix(cx, s); +} + + +/* + * Start a deeper level of indendation. If multiline is in effect, + * we end the current line. + */ +void +uni_print_push_prefix(const char *prefix, struct unicx *cx) +{ + if (cx->nprefix < PRINT_NPREFIX) + cx->prefix[cx->nprefix++] = prefix; +} +void +uni_print_pop_prefix(struct unicx *cx) +{ + if (cx->nprefix > 0) + cx->nprefix--; +} + +void +uni_print_tbl(const char *entry, u_int val, const struct uni_print_tbl *tbl, + struct unicx *cx) +{ + if (entry) + uni_entry(entry, cx); + while (tbl->name) { + if (tbl->val == val) { + uni_printf(cx, "%s", tbl->name); + return; + } + tbl++; + } + uni_printf(cx, "ERROR(0x%x)", val); +} + +void +uni_print_entry(struct unicx *cx, const char *e, const char *fmt, ...) +{ + u_int n; + va_list ap; + + uni_entry(e, cx); + + if (cx->bufsiz > 1) { + va_start(ap, fmt); + n = vsnprintf(cx->buf, cx->bufsiz, fmt, ap); + va_end(ap); + if (n > 0) { + if (n < cx->bufsiz) { + cx->bufsiz -= n; + cx->buf += n; + } else { + cx->buf += cx->bufsiz - 1; + cx->bufsiz = 1; + } + } + *cx->buf = '\0'; + } +} + +/**********************************************************************/ +/* + * Printing information elements. + */ +static int +uni_print_iehdr(const char *name, struct uni_iehdr *h, struct unicx *cx) +{ + static const struct uni_print_tbl act_tab[] = { + MKT(UNI_IEACT_CLEAR, clear), + MKT(UNI_IEACT_IGNORE, ignore), + MKT(UNI_IEACT_REPORT, report), + MKT(UNI_IEACT_MSG_IGNORE, ignore-msg), + MKT(UNI_IEACT_MSG_REPORT, report-msg), + MKT(UNI_IEACT_DEFAULT, default), + EOT() + }; + static const struct uni_print_tbl cod_tab[] = { + MKT(UNI_CODING_ITU, itut), + MKT(UNI_CODING_NET, atmf), + EOT() + }; + + uni_print_entry(cx, name, "("); + uni_print_tbl(NULL, h->act, act_tab, cx); + uni_putc(',', cx); + uni_print_tbl(NULL, h->coding, cod_tab, cx); + if(cx->pnni && h->pass) + uni_printf(cx, ",pass"); + if(IE_ISEMPTY(*(struct uni_ie_aal *)h)) { + uni_printf(cx, ",empty)"); + uni_print_eol(cx); + return 1; + } + if(IE_ISERROR(*(struct uni_ie_aal *)h)) { + uni_printf(cx, ",error)"); + uni_print_eol(cx); + return 1; + } + + uni_putc(')', cx); + + uni_print_push_prefix(name, cx); + uni_print_eol(cx); + cx->indent++; + + return 0; +} + +static void +uni_print_ieend(struct unicx *cx) +{ + uni_print_pop_prefix(cx); + uni_print_eol(cx); + cx->indent--; +} + +void +uni_print_ie_internal(enum uni_ietype code, const union uni_ieall *ie, + struct unicx *cx) +{ + const struct iedecl *iedecl; + + if((iedecl = GET_IEDECL(code, ie->h.coding)) != NULL) + (*iedecl->print)(ie, cx); +} + +void +uni_print_ie(char *buf, size_t size, enum uni_ietype code, + const union uni_ieall *ie, struct unicx *cx) +{ + uni_print_init(buf, size, cx); + uni_print_ie_internal(code, ie, cx); +} + +int +uni_check_ie(enum uni_ietype code, union uni_ieall *ie, struct unicx *cx) +{ + const struct iedecl *iedecl = GET_IEDECL(code, ie->h.coding); + + if (iedecl != NULL) + return (iedecl->check(ie, cx)); + else + return (-1); +} + +/* + * Decode a information element header. + * Returns -1 if the message is too short. + * Strip the header from the message. + * The header is stripped, even if it is too short. + */ +int +uni_decode_ie_hdr(enum uni_ietype *ietype, struct uni_iehdr *hdr, + struct uni_msg *msg, struct unicx *cx, u_int *ielen) +{ + u_int len; + + *ietype = (enum uni_ietype)0; + *ielen = 0; + hdr->present = 0; + hdr->coding = UNI_CODING_ITU; + hdr->act = UNI_IEACT_DEFAULT; + + if ((len = uni_msg_len(msg)) == 0) + return (-1); + + *ietype = *msg->b_rptr++; + + if (--len == 0) + return (-1); + + hdr->coding = (*msg->b_rptr >> 5) & 3; + hdr->present = 0; + + switch (*msg->b_rptr & 0x17) { + + case 0x10: case 0x11: case 0x12: + case 0x15: case 0x16: + hdr->act = *msg->b_rptr & 0x7; + break; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + hdr->act = UNI_IEACT_DEFAULT; + break; + + default: + /* Q.2931 5.7.2 last sentence */ + hdr->act = UNI_IEACT_REPORT; + break; + } + if (cx->pnni && (*msg->b_rptr & 0x08)) + hdr->pass = 1; + else + hdr->pass = 0; + msg->b_rptr++; + + if (--len == 0) { + hdr->present = UNI_IE_ERROR | UNI_IE_PRESENT; + return (-1); + } + + if (len < 2) { + msg->b_rptr += len; + hdr->present = UNI_IE_ERROR | UNI_IE_PRESENT; + return (-1); + } + + *ielen = *msg->b_rptr++ << 8; + *ielen |= *msg->b_rptr++; + + return (0); +} + +/* + * Decode the body of an information element. + */ +int +uni_decode_ie_body(enum uni_ietype ietype, union uni_ieall *ie, + struct uni_msg *msg, u_int ielen, struct unicx *cx) +{ + const struct iedecl *iedecl; + u_char *end; + int ret; + + if (ielen > uni_msg_len(msg)) { + /* + * Information element too long -> content error. + * Q.2931 5.6.8.2 + */ + msg->b_rptr = msg->b_wptr; + ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT; + return (-1); + } + + if ((iedecl = GET_IEDECL(ietype, ie->h.coding)) == NULL) { + /* + * entirly unknown IE. + * Q.2931 5.6.8.1 + */ + msg->b_rptr += ielen; + ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT; + return (-1); + } + + if (ielen > iedecl->maxlen) { + /* + * Information element too long -> content error. + * Q.2931 5.6.8.2 + */ + msg->b_rptr += iedecl->maxlen; + ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT; + return (-1); + } + + end = msg->b_rptr + ielen; + ret = (*iedecl->decode)(ie, msg, ielen, cx); + msg->b_rptr = end; + + return (ret); +} + +int +uni_encode_ie(enum uni_ietype code, struct uni_msg *msg, union uni_ieall *ie, + struct unicx *cx) +{ + const struct iedecl *iedecl = GET_IEDECL(code, ie->h.coding); + + if (iedecl == NULL) + return (-1); + return (iedecl->encode(msg, ie, cx)); +} + +int +uni_encode_ie_hdr(struct uni_msg *msg, enum uni_ietype type, + struct uni_iehdr *h, u_int len, struct unicx *cx) +{ + u_char byte; + + (void)uni_msg_ensure(msg, 4 + len); + *msg->b_wptr++ = type; + + byte = 0x80 | (h->coding << 5); + if(h->act != UNI_IEACT_DEFAULT) + byte |= 0x10 | (h->act & 7); + if(cx->pnni) + byte |= h->pass << 3; + *msg->b_wptr++ = byte; + + if(h->present & UNI_IE_EMPTY) { + *msg->b_wptr++ = 0; + *msg->b_wptr++ = 4; + return -1; + } + *msg->b_wptr++ = 0; + *msg->b_wptr++ = 0; + + return 0; +} + +/* + * Printing messages. + */ +static void +uni_print_cref_internal(const struct uni_cref *cref, struct unicx *cx) +{ + uni_print_entry(cx, "cref", "%d.", cref->flag); + if (cref->cref == CREF_GLOBAL) + uni_printf(cx, "GLOBAL"); + else if (cref->cref == CREF_DUMMY) + uni_printf(cx, "DUMMY"); + else + uni_printf(cx, "%d", cref->cref); +} +void +uni_print_cref(char *str, size_t len, const struct uni_cref *cref, + struct unicx *cx) +{ + uni_print_init(str, len, cx); + uni_print_cref_internal(cref, cx); +} + +static void +uni_print_msghdr_internal(const struct uni_msghdr *hdr, struct unicx *cx) +{ + static const struct uni_print_tbl tab[] = { + MKT(UNI_MSGACT_CLEAR, clear), + MKT(UNI_MSGACT_IGNORE, ignore), + MKT(UNI_MSGACT_REPORT, report), + MKT(UNI_MSGACT_DEFAULT, default), + EOT() + }; + + uni_print_cref_internal(&hdr->cref, cx); + uni_print_tbl("act", hdr->act, tab, cx); + if (cx->pnni) + uni_print_entry(cx, "pass", "%s", hdr->pass ? "yes" : "no"); +} + +void +uni_print_msghdr(char *str, size_t len, const struct uni_msghdr *hdr, + struct unicx *cx) +{ + uni_print_init(str, len, cx); + uni_print_msghdr_internal(hdr, cx); +} + + +static void +uni_print_internal(const struct uni_all *msg, struct unicx *cx) +{ + uni_entry("mtype", cx); + if(msg->mtype >= 256 || uni_msgtable[msg->mtype] == NULL) { + uni_printf(cx, "0x%02x(ERROR)", msg->mtype); + } else { + uni_printf(cx, "%s", uni_msgtable[msg->mtype]->name); + uni_print_msghdr_internal(&msg->u.hdr, cx); + cx->indent++; + uni_print_eol(cx); + (*uni_msgtable[msg->mtype]->print)(&msg->u, cx); + cx->indent--; + } + + if(cx->multiline == 0) + uni_printf(cx, "\n"); +} + +void +uni_print(char *buf, size_t size, const struct uni_all *all, struct unicx *cx) +{ + uni_print_init(buf, size, cx); + uni_print_internal(all, cx); +} + +static void +uni_print_msg_internal(u_int mtype, const union uni_msgall *msg, + struct unicx *cx) +{ + + uni_entry("mtype", cx); + if (mtype >= 256 || uni_msgtable[mtype] == NULL) { + uni_printf(cx, "0x%02x(ERROR)", mtype); + } else { + uni_printf(cx, "%s", uni_msgtable[mtype]->name); + uni_print_msghdr_internal(&msg->hdr, cx); + cx->indent++; + uni_print_eol(cx); + (*uni_msgtable[mtype]->print)(msg, cx); + cx->indent--; + } + + if(cx->multiline == 0) + uni_printf(cx, "\n"); +} + +void +uni_print_msg(char *buf, size_t size, u_int mtype, const union uni_msgall *all, + struct unicx *cx) +{ + uni_print_init(buf, size, cx); + uni_print_msg_internal(mtype, all, cx); +} + +void +uni_print_cx(char *buf, size_t size, struct unicx *cx) +{ + static const char *acttab[] = { + "clr", /* 0x00 */ + "ign", /* 0x01 */ + "rep", /* 0x02 */ + "x03", /* 0x03 */ + "x04", /* 0x04 */ + "mig", /* 0x05 */ + "mrp", /* 0x06 */ + "x07", /* 0x07 */ + "def", /* 0x08 */ + }; + + static const char *errtab[] = { + [UNI_IERR_UNK] = "unk", /* unknown IE */ + [UNI_IERR_LEN] = "len", /* length error */ + [UNI_IERR_BAD] = "bad", /* content error */ + [UNI_IERR_ACC] = "acc", /* access element discarded */ + [UNI_IERR_MIS] = "mis", /* missing IE */ + }; + + u_int i; + + uni_print_init(buf, size, cx); + + uni_printf(cx, "q2932 %d\n", cx->q2932); + uni_printf(cx, "pnni %d\n", cx->pnni); + uni_printf(cx, "git_hard %d\n", cx->git_hard); + uni_printf(cx, "bearer_hard %d\n", cx->bearer_hard); + uni_printf(cx, "cause_hard %d\n", cx->cause_hard); + + uni_printf(cx, "multiline %d\n", cx->multiline); + uni_printf(cx, "tabsiz %d\n", cx->tabsiz); + + uni_printf(cx, "errcnt %d (", cx->errcnt); + for(i = 0; i < cx->errcnt; i++) { + uni_printf(cx, "%02x[%s,%s%s]", cx->err[i].ie, + errtab[cx->err[i].err], acttab[cx->err[i].act], + cx->err[i].man ? ",M" : ""); + if(i != cx->errcnt - 1) + uni_putc(' ', cx); + } + uni_printf(cx, ")\n"); +} + +#include <netnatm/msg/uni_ietab.h> + +/********************************************************************* + * + * Cause + * + * References for this IE are: + * + * Q.2931 pp. 69 (just a pointer to Q.2610) + * Q.2610 (this is a small diff to Q.850) + * Q.850 !! + * UNI4.0 pp. 15 + * PNNI1.0 p. 198 + * + * ITU-T and NET coding for different values. + */ +static const struct causetab { + const char *str; + enum uni_diag diag; +} itu_causes[128] = { + +#define D(NAME,VAL,DIAG,STD,STR) [UNI_CAUSE_##NAME] = { STR, UNI_DIAG_##DIAG }, +#define N(NAME,VAL,DIAG,STD,STR) + +UNI_DECLARE_CAUSE_VALUES + +#undef D +#undef N + +}, net_causes[128] = { + +#define D(NAME,VAL,DIAG,STD,STR) +#define N(NAME,VAL,DIAG,STD,STR) [UNI_CAUSE_##NAME] = { STR, UNI_DIAG_##DIAG }, + +UNI_DECLARE_CAUSE_VALUES + +#undef D +#undef N + +}; + +enum uni_diag +uni_diag(enum uni_cause cause, enum uni_coding code) +{ + if ((int)cause >= 128) + return (UNI_DIAG_NONE); + + if (code == UNI_CODING_NET) + if (net_causes[cause].str != NULL) + return (net_causes[cause].diag); + if (itu_causes[cause].str != NULL) + return (itu_causes[cause].diag); + return (UNI_DIAG_NONE); +} + +/**********************************************************************/ + +static void +print_cause(struct unicx *cx, struct uni_ie_cause *ie, + const struct causetab *tab1, const struct causetab *tab2) +{ + static const struct uni_print_tbl loc_tbl[] = { + MKT(UNI_CAUSE_LOC_USER, user), + MKT(UNI_CAUSE_LOC_PRIVLOC, priv-net:loc-user), + MKT(UNI_CAUSE_LOC_PUBLOC, pub-net:loc-user), + MKT(UNI_CAUSE_LOC_TRANSIT, transit-net), + MKT(UNI_CAUSE_LOC_PUBREM, pub-net:rem-user), + MKT(UNI_CAUSE_LOC_PRIVREM, priv-net:rem-user), + MKT(UNI_CAUSE_LOC_INTERNAT, int-net), + MKT(UNI_CAUSE_LOC_BEYOND, beyond), + EOT() + }; + static const struct uni_print_tbl pu_tbl[] = { + MKT(UNI_CAUSE_PU_PROVIDER, provider), + MKT(UNI_CAUSE_PU_USER, user), + EOT() + }; + static const struct uni_print_tbl na_tbl[] = { + MKT(UNI_CAUSE_NA_NORMAL, normal), + MKT(UNI_CAUSE_NA_ABNORMAL, abnormal), + EOT() + }; + static const struct uni_print_tbl cond_tbl[] = { + MKT(UNI_CAUSE_COND_UNKNOWN, unknown), + MKT(UNI_CAUSE_COND_PERM, permanent), + MKT(UNI_CAUSE_COND_TRANS, transient), + EOT() + }; + static const struct uni_print_tbl rej_tbl[] = { + MKT(UNI_CAUSE_REASON_USER, user), + MKT(UNI_CAUSE_REASON_IEMISS, ie-missing), + MKT(UNI_CAUSE_REASON_IESUFF, ie-not-suff), + EOT() + }; + char buf[100], *s; + u_int i; + + if (uni_print_iehdr("cause", &ie->h, cx)) + return; + + if ((int)ie->cause < 128 && tab1[ie->cause].str) + strcpy(buf, tab1[ie->cause].str); + else if ((int)ie->cause < 128 && tab2 != NULL && tab2[ie->cause].str != NULL) + strcpy(buf, tab2[ie->cause].str); + else { + sprintf(buf, "UNKNOWN-%u", ie->cause); + } + + for (s = buf; *s != '\0'; s++) + if (*s == ' ') + *s = '_'; + uni_print_entry(cx, "cause", "%s", buf); + + uni_print_tbl("loc", ie->loc, loc_tbl, cx); + + if (ie->h.present & UNI_CAUSE_COND_P) { + uni_print_tbl("pu", ie->u.cond.pu, pu_tbl, cx); + uni_print_tbl("na", ie->u.cond.na, na_tbl, cx); + uni_print_tbl("condition", ie->u.cond.cond, cond_tbl, cx); + } + if (ie->h.present & UNI_CAUSE_REJ_P) { + uni_print_tbl("reject", ie->u.rej.reason, rej_tbl, cx); + } + if (ie->h.present & UNI_CAUSE_REJ_USER_P) { + uni_print_entry(cx, "user", "%u", ie->u.rej.user); + } + if (ie->h.present & UNI_CAUSE_REJ_IE_P) { + uni_print_entry(cx, "ie", "%u", ie->u.rej.ie); + } + if (ie->h.present & UNI_CAUSE_IE_P) { + uni_print_entry(cx, "ie", "("); + for (i = 0; i < ie->u.ie.len; i++) { + if (i) + uni_putc(',', cx); + uni_printf(cx, "0x%02x", ie->u.ie.ie[i]); + } + uni_putc(')', cx); + } + if (ie->h.present & UNI_CAUSE_TRAFFIC_P) { + uni_print_entry(cx, "traffic", "("); + for (i = 0; i < ie->u.traffic.len; i++) { + if (i) + uni_putc(',', cx); + uni_printf(cx, "0x%02x", ie->u.traffic.traffic[i]); + } + uni_putc(')', cx); + } + if (ie->h.present & UNI_CAUSE_VPCI_P) { + uni_print_entry(cx, "vpci", "(%u,%u)", ie->u.vpci.vpci, ie->u.vpci.vci); + } + if (ie->h.present & UNI_CAUSE_MTYPE_P) { + uni_print_entry(cx, "mtype", "%u", ie->u.mtype); + } + if (ie->h.present & UNI_CAUSE_TIMER_P) { + for (i = 0, s = buf; i < 3; i++) { + if (ie->u.timer[i] < ' ') { + *s++ = '^'; + *s++ = ie->u.timer[i] + '@'; + } else if (ie->u.timer[i] <= '~') + *s++ = ie->u.timer[i]; + else { + *s++ = '\\'; + *s++ = ie->u.timer[i] / 0100 + '0'; + *s++ = (ie->u.timer[i] % 0100) / 010 + '0'; + *s++ = ie->u.timer[i] % 010 + '0'; + } + } + *s++ = '\0'; + uni_print_entry(cx, "timer", "\"%s\"", buf); + } + if (ie->h.present & UNI_CAUSE_TNS_P) { + uni_print_eol(cx); + uni_print_ie_internal(UNI_IE_TNS, (union uni_ieall *)&ie->u.tns, cx); + } + if (ie->h.present & UNI_CAUSE_NUMBER_P) { + uni_print_eol(cx); + uni_print_ie_internal(UNI_IE_CALLED, (union uni_ieall *)&ie->u.number, cx); + } + if (ie->h.present & UNI_CAUSE_ATTR_P) { + uni_print_entry(cx, "attr", "("); + for (i = 0; i < ie->u.attr.nattr; i++) { + uni_printf(cx, "(%u", ie->u.attr.attr[i][0]); + if (!(ie->u.attr.attr[i][0] & 0x80)) { + uni_printf(cx, ",%u", ie->u.attr.attr[i][1]); + if (!(ie->u.attr.attr[i][1] & 0x80)) + uni_printf(cx, ",%u", + ie->u.attr.attr[i][2]); + } + uni_putc(')', cx); + } + } + + uni_print_ieend(cx); +} + +DEF_IE_PRINT(itu, cause) +{ + print_cause(cx, ie, itu_causes, NULL); +} +DEF_IE_PRINT(net, cause) +{ + print_cause(cx, ie, net_causes, itu_causes); +} + +const char * +uni_ie_cause2str(enum uni_coding coding, u_int cause) +{ + if (cause < 128) { + if (coding == UNI_CODING_ITU) + return (itu_causes[cause].str); + if (coding == UNI_CODING_NET) { + if (net_causes[cause].str != NULL) + return (net_causes[cause].str); + return (itu_causes[cause].str); + } + } + return (NULL); +} + +/**********************************************************************/ + +static int +check_cause(struct uni_ie_cause *ie, struct unicx *cx, + const struct causetab *tab1, const struct causetab *tab2) +{ + static const u_int mask = + UNI_CAUSE_COND_P | UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_USER_P | + UNI_CAUSE_REJ_IE_P | UNI_CAUSE_IE_P | UNI_CAUSE_TRAFFIC_P | + UNI_CAUSE_VPCI_P | UNI_CAUSE_MTYPE_P | UNI_CAUSE_TIMER_P | + UNI_CAUSE_TNS_P | UNI_CAUSE_NUMBER_P | UNI_CAUSE_ATTR_P | + UNI_CAUSE_PARAM_P; + + const struct causetab *ptr; + + if ((int)ie->cause >= 128) + return (-1); + + switch (ie->loc) { + default: + return (-1); + + case UNI_CAUSE_LOC_USER: + case UNI_CAUSE_LOC_PRIVLOC: + case UNI_CAUSE_LOC_PUBLOC: + case UNI_CAUSE_LOC_TRANSIT: + case UNI_CAUSE_LOC_PUBREM: + case UNI_CAUSE_LOC_PRIVREM: + case UNI_CAUSE_LOC_INTERNAT: + case UNI_CAUSE_LOC_BEYOND: + break; + } + + if (tab1[ie->cause].str != NULL) + ptr = &tab1[ie->cause]; + else if (tab2 != NULL && tab2[ie->cause].str != NULL) + ptr = &tab2[ie->cause]; + else + return (cx->cause_hard ? -1 : 0); + + switch (ptr->diag) { + + case UNI_DIAG_NONE: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + break; + } + break; + + case UNI_DIAG_COND: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_COND_P: + break; + } + break; + + case UNI_DIAG_REJ: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_REJ_P: + case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_USER_P: + case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_IE_P: + break; + } + break; + + case UNI_DIAG_CRATE: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_TRAFFIC_P: + break; + } + break; + + case UNI_DIAG_IE: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_IE_P: + break; + } + break; + + case UNI_DIAG_CHANID: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_VPCI_P: + break; + } + break; + + case UNI_DIAG_MTYPE: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_MTYPE_P: + break; + } + break; + + case UNI_DIAG_TIMER: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_TIMER_P: + break; + } + break; + + case UNI_DIAG_TNS: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_TNS_P: + break; + } + break; + + case UNI_DIAG_NUMBER: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_NUMBER_P: + break; + } + break; + + case UNI_DIAG_ATTR: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_ATTR_P: + break; + } + break; + + case UNI_DIAG_PARAM: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_PARAM_P: + break; + } + break; + } + + if (ie->h.present & UNI_CAUSE_COND_P) { + switch (ie->u.cond.pu) { + default: + return (-1); + + case UNI_CAUSE_PU_PROVIDER: + case UNI_CAUSE_PU_USER: + break; + } + switch (ie->u.cond.na) { + default: + return (-1); + + case UNI_CAUSE_NA_NORMAL: + case UNI_CAUSE_NA_ABNORMAL: + break; + } + switch (ie->u.cond.cond) { + default: + return (-1); + + case UNI_CAUSE_COND_UNKNOWN: + case UNI_CAUSE_COND_PERM: + case UNI_CAUSE_COND_TRANS: + break; + } + } + if (ie->h.present & UNI_CAUSE_REJ_P) { + switch (ie->u.rej.reason) { + default: + return (-1); + + case UNI_CAUSE_REASON_USER: + switch (ie->h.present & mask) { + default: + return (-1); + + case UNI_CAUSE_REJ_P: + case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_USER_P: + break; + } + break; + + case UNI_CAUSE_REASON_IEMISS: + case UNI_CAUSE_REASON_IESUFF: + switch (ie->h.present & mask) { + default: + return (-1); + + case UNI_CAUSE_REJ_P: + case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_IE_P: + break; + } + break; + } + } + if (ie->h.present & UNI_CAUSE_IE_P) { + if (ie->u.ie.len == 0 || ie->u.ie.len > UNI_CAUSE_IE_N) + return (-1); + } + if (ie->h.present & UNI_CAUSE_TRAFFIC_P) { + if (ie->u.traffic.len == 0 || + ie->u.traffic.len > UNI_CAUSE_TRAFFIC_N) + return (-1); + } + + if (ie->h.present & UNI_CAUSE_TNS_P) { + if (uni_check_ie(UNI_IE_TNS, (union uni_ieall *)&ie->u.tns, cx)) + return (-1); + } + if (ie->h.present & UNI_CAUSE_NUMBER_P) { + if(uni_check_ie(UNI_IE_CALLED, (union uni_ieall *)&ie->u.number, cx)) + return (-1); + } + if (ie->h.present & UNI_CAUSE_ATTR_P) { + if(ie->u.attr.nattr > UNI_CAUSE_ATTR_N || ie->u.attr.nattr == 0) + return (-1); + } + if (ie->h.present & UNI_CAUSE_PARAM_P) { + UNUSED(cx); + } + + return (0); +} + +DEF_IE_CHECK(itu, cause) +{ + return (check_cause(ie, cx, itu_causes, NULL)); +} +DEF_IE_CHECK(net, cause) +{ + return (check_cause(ie, cx, net_causes, itu_causes)); +} +/**********************************************************************/ + +static int +encode_cause(struct uni_msg *msg, struct uni_ie_cause *ie, struct unicx *cx) +{ + u_int i; + + START_IE(cause, UNI_IE_CAUSE, 30); + + if (IE_ISERROR(*ie)) { + APP_BYTE(msg, 0x00 | ie->loc); + } else { + APP_BYTE(msg, 0x80 | ie->loc); + } + APP_BYTE(msg, 0x80 | ie->cause); + + if (ie->h.present & UNI_CAUSE_COND_P) + APP_BYTE(msg, 0x80 | (ie->u.cond.pu << 3) | + (ie->u.cond.na << 2) | ie->u.cond.cond); + + else if (ie->h.present & UNI_CAUSE_REJ_P) { + APP_BYTE(msg, 0x80 | (ie->u.rej.reason << 2) | ie->u.rej.cond); + if (ie->h.present & UNI_CAUSE_REJ_USER_P) + APP_BYTE(msg, ie->u.rej.user); + else if (ie->h.present & UNI_CAUSE_REJ_IE_P) + APP_BYTE(msg, ie->u.rej.ie); + + } else if(ie->h.present & UNI_CAUSE_IE_P) + APP_BUF(msg, ie->u.ie.ie, ie->u.ie.len); + + else if (ie->h.present & UNI_CAUSE_TRAFFIC_P) + APP_BUF(msg, ie->u.traffic.traffic, ie->u.traffic.len); + + else if (ie->h.present & UNI_CAUSE_VPCI_P) { + APP_BYTE(msg, (ie->u.vpci.vpci >> 8)); + APP_BYTE(msg, (ie->u.vpci.vpci >> 0)); + APP_BYTE(msg, (ie->u.vpci.vci >> 8)); + APP_BYTE(msg, (ie->u.vpci.vci >> 0)); + + } else if (ie->h.present & UNI_CAUSE_MTYPE_P) + APP_BYTE(msg, ie->u.mtype); + + else if (ie->h.present & UNI_CAUSE_TIMER_P) { + APP_BYTE(msg, ie->u.timer[0]); + APP_BYTE(msg, ie->u.timer[1]); + APP_BYTE(msg, ie->u.timer[2]); + + } else if (ie->h.present & UNI_CAUSE_TNS_P) + uni_encode_ie(UNI_IE_TNS, msg, + (union uni_ieall *)&ie->u.tns, cx); + + else if (ie->h.present & UNI_CAUSE_NUMBER_P) + uni_encode_ie(UNI_IE_CALLED, msg, + (union uni_ieall *)&ie->u.number, cx); + + else if (ie->h.present & UNI_CAUSE_ATTR_P) { + for (i = 0; i < ie->u.attr.nattr; i++) { + APP_BYTE(msg, ie->u.attr.attr[i][0]); + if (!ie->u.attr.attr[i][0]) { + APP_BYTE(msg, ie->u.attr.attr[i][1]); + if (!ie->u.attr.attr[i][1]) + APP_BYTE(msg, ie->u.attr.attr[i][2]); + } + } + } else if (ie->h.present & UNI_CAUSE_PARAM_P) + APP_BYTE(msg, ie->u.param); + + SET_IE_LEN(msg); + + return (0); +} + +DEF_IE_ENCODE(itu, cause) +{ + return encode_cause(msg, ie, cx); +} +DEF_IE_ENCODE(net, cause) +{ + return encode_cause(msg, ie, cx); +} + +/**********************************************************************/ + +static int +decode_cause(struct uni_ie_cause *ie, struct uni_msg *msg, u_int ielen, + struct unicx *cx, const struct causetab *tab1, const struct causetab *tab2) +{ + u_char c; + const struct causetab *ptr; + enum uni_ietype ietype; + u_int xielen; + + IE_START(;); + + if(ielen < 2 || ielen > 30) + goto rej; + + c = *msg->b_rptr++; + ielen--; + if(!(c & 0x80)) + goto rej; + ie->loc = c & 0xf; + + c = *msg->b_rptr++; + ielen--; + if(!(c & 0x80)) + goto rej; + ie->cause = c & 0x7f; + + if(tab1[ie->cause].str != NULL) + ptr = &tab1[ie->cause]; + else if(tab2 != NULL && tab2[ie->cause].str != NULL) + ptr = &tab2[ie->cause]; + else { + ptr = NULL; + ielen = 0; /* ignore diags */ + } + + if(ielen) { + switch(ptr->diag) { + + case UNI_DIAG_NONE: + break; + + case UNI_DIAG_COND: + if(ielen < 1) + goto rej; + c = *msg->b_rptr++; + ielen--; + + ie->h.present |= UNI_CAUSE_COND_P; + ie->u.cond.pu = (c >> 3) & 1; + ie->u.cond.na = (c >> 2) & 1; + ie->u.cond.cond = c & 3; + + if(!(c & 0x80)) + goto rej; + break; + + case UNI_DIAG_REJ: + if(ielen < 1) + goto rej; + c = *msg->b_rptr++; + ielen--; + + ie->h.present |= UNI_CAUSE_REJ_P; + ie->u.rej.reason = (c >> 2) & 0x1f; + ie->u.rej.cond = c & 3; + + if(!(c & 0x80)) + goto rej; + + if(ielen > 0) { + c = *msg->b_rptr++; + ielen--; + + switch(ie->u.rej.reason) { + + case UNI_CAUSE_REASON_USER: + ie->h.present |= UNI_CAUSE_REJ_USER_P; + ie->u.rej.user = c; + break; + + case UNI_CAUSE_REASON_IEMISS: + case UNI_CAUSE_REASON_IESUFF: + ie->h.present |= UNI_CAUSE_REJ_IE_P; + ie->u.rej.ie = c; + break; + } + } + break; + + case UNI_DIAG_CRATE: + ie->h.present |= UNI_CAUSE_TRAFFIC_P; + while(ielen && ie->u.traffic.len < UNI_CAUSE_TRAFFIC_N) { + ie->u.traffic.traffic[ie->u.traffic.len++] = + *msg->b_rptr++; + ielen--; + } + break; + + case UNI_DIAG_IE: + ie->h.present |= UNI_CAUSE_IE_P; + while(ielen && ie->u.ie.len < UNI_CAUSE_IE_N) { + ie->u.ie.ie[ie->u.ie.len++] = *msg->b_rptr++; + ielen--; + } + break; + + case UNI_DIAG_CHANID: + if(ielen < 4) + break; + ie->h.present |= UNI_CAUSE_VPCI_P; + ie->u.vpci.vpci = *msg->b_rptr++ << 8; + ie->u.vpci.vpci |= *msg->b_rptr++; + ie->u.vpci.vci = *msg->b_rptr++ << 8; + ie->u.vpci.vci |= *msg->b_rptr++; + ielen -= 4; + break; + + case UNI_DIAG_MTYPE: + ie->h.present |= UNI_CAUSE_MTYPE_P; + ie->u.mtype = *msg->b_rptr++; + ielen--; + break; + + case UNI_DIAG_TIMER: + if(ielen < 3) + break; + ie->h.present |= UNI_CAUSE_TIMER_P; + ie->u.timer[0] = *msg->b_rptr++; + ie->u.timer[1] = *msg->b_rptr++; + ie->u.timer[2] = *msg->b_rptr++; + ielen -= 3; + break; + + case UNI_DIAG_TNS: + if(ielen < 4) + break; + if(uni_decode_ie_hdr(&ietype, &ie->u.tns.h, msg, cx, &xielen)) + break; + if(ietype != UNI_IE_TNS) + break; + if(uni_decode_ie_body(ietype, + (union uni_ieall *)&ie->u.tns, msg, xielen, cx)) + break; + ie->h.present |= UNI_CAUSE_TNS_P; + break; + + case UNI_DIAG_NUMBER: + if(ielen < 4) + break; + if(uni_decode_ie_hdr(&ietype, &ie->u.number.h, msg, cx, &xielen)) + break; + if(ietype != UNI_IE_CALLED) + break; + if(uni_decode_ie_body(ietype, + (union uni_ieall *)&ie->u.number, msg, xielen, cx)) + break; + ie->h.present |= UNI_CAUSE_NUMBER_P; + break; + + case UNI_DIAG_ATTR: + ie->h.present |= UNI_CAUSE_ATTR_P; + while(ielen > 0 && ie->u.attr.nattr < UNI_CAUSE_ATTR_N) { + c = *msg->b_rptr++; + ie->u.attr.attr[ie->u.attr.nattr][0] = c; + ielen--; + if(ielen > 0 && !(c & 0x80)) { + c = *msg->b_rptr++; + ie->u.attr.attr[ie->u.attr.nattr][1] = c; + ielen--; + if(ielen > 0 && !(c & 0x80)) { + c = *msg->b_rptr++; + ie->u.attr.attr[ie->u.attr.nattr][2] = c; + ielen--; + } + } + } + break; + + case UNI_DIAG_PARAM: + ie->h.present |= UNI_CAUSE_PARAM_P; + ie->u.param = *msg->b_rptr++; + ielen--; + break; + } + } + + IE_END(CAUSE); +} + +DEF_IE_DECODE(itu, cause) +{ + return decode_cause(ie, msg, ielen, cx, itu_causes, NULL); +} +DEF_IE_DECODE(net, cause) +{ + return decode_cause(ie, msg, ielen, cx, net_causes, itu_causes); +} + +/********************************************************************* + * + * Callstate + * + * References for this IE are: + * + * Q.2931 pp. 59...60 + * UNI4.0 pp. 14 + * + * Only ITU-T coding allowed. + */ +DEF_IE_PRINT(itu, callstate) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_CALLSTATE_U0, U0/N0/REST0), + MKT(UNI_CALLSTATE_U1, U1/N1), + MKT(UNI_CALLSTATE_U3, U3/N3), + MKT(UNI_CALLSTATE_U4, U4/N4), + MKT(UNI_CALLSTATE_U6, U6/N6), + MKT(UNI_CALLSTATE_U7, U7/N7), + MKT(UNI_CALLSTATE_U8, U8/N8), + MKT(UNI_CALLSTATE_U9, U9/N9), + MKT(UNI_CALLSTATE_U10, U10/N10), + MKT(UNI_CALLSTATE_U11, U11/N11), + MKT(UNI_CALLSTATE_U12, U12/N12), + MKT(UNI_CALLSTATE_REST1,REST1), + MKT(UNI_CALLSTATE_REST2,REST2), + MKT(UNI_CALLSTATE_U13, U13/N13), + MKT(UNI_CALLSTATE_U14, U14/N14), + EOT() + }; + + if(uni_print_iehdr("callstate", &ie->h, cx)) + return; + uni_print_tbl("state", ie->state, tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, callstate) +{ + UNUSED(cx); + + switch(ie->state) { + default: + return -1; + + case UNI_CALLSTATE_U0: + case UNI_CALLSTATE_U1: + case UNI_CALLSTATE_U3: + case UNI_CALLSTATE_U4: + case UNI_CALLSTATE_U6: + case UNI_CALLSTATE_U7: + case UNI_CALLSTATE_U8: + case UNI_CALLSTATE_U9: + case UNI_CALLSTATE_U10: + case UNI_CALLSTATE_U11: + case UNI_CALLSTATE_U12: + case UNI_CALLSTATE_REST1: + case UNI_CALLSTATE_REST2: + case UNI_CALLSTATE_U13: + case UNI_CALLSTATE_U14: + break; + } + + return 0; +} + +DEF_IE_ENCODE(itu, callstate) +{ + START_IE(callstate, UNI_IE_CALLSTATE, 1); + + APP_BYTE(msg, ie->state); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, callstate) +{ + IE_START(;); + + if(ielen != 1) + goto rej; + + ie->state = *msg->b_rptr++ & 0x3f; + ielen--; + + IE_END(CALLSTATE); +} + +/********************************************************************* + * + * Facility Information. + * + * References for this IE are: + * + * Q.2932.1 + * + * The standard allows only ROSE as protocol. We allow everything up to the + * maximum size. + * + * Only ITU-T coding allowed. + */ +DEF_IE_PRINT(itu, facility) +{ + u_int i; + + if(uni_print_iehdr("facility", &ie->h, cx)) + return; + + if(ie->proto == UNI_FACILITY_ROSE) + uni_print_entry(cx, "proto", "rose"); + else + uni_print_entry(cx, "proto", "0x%02x", ie->proto); + + uni_print_entry(cx, "len", "%u", ie->len); + uni_print_entry(cx, "info", "("); + for(i = 0; i < ie->len; i++) + uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->apdu[i]); + uni_printf(cx, ")"); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, facility) +{ + UNUSED(cx); + + if(ie->len > UNI_FACILITY_MAXAPDU) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, facility) +{ + START_IE(facility, UNI_IE_FACILITY, 1 + ie->len); + + APP_BYTE(msg, ie->proto | 0x80); + APP_BUF(msg, ie->apdu, ie->len); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, facility) +{ + u_char c; + + IE_START(;); + + if(ielen > UNI_FACILITY_MAXAPDU + 1 || ielen < 1) + goto rej; + + ie->proto = (c = *msg->b_rptr++) & 0x1f; + ielen--; + if((c & 0xe0) != 0x80) + goto rej; + + ie->len = ielen; + ielen = 0; + (void)memcpy(ie->apdu, msg->b_rptr, ie->len); + msg->b_rptr += ie->len; + + IE_END(FACILITY); +} + +/********************************************************************* + * + * Notification Indicator + * + * References for this IE are: + * + * Q.2931 p. 76 + * UNI4.0 p. 17 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, notify) +{ + u_int i; + + if(uni_print_iehdr("notify", &ie->h, cx)) + return; + uni_print_entry(cx, "len", "%u", ie->len); + uni_print_entry(cx, "info", "("); + for(i = 0; i < ie->len; i++) + uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->notify[i]); + uni_printf(cx, ")"); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, notify) +{ + UNUSED(cx); + + if(ie->len > UNI_NOTIFY_MAXLEN) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, notify) +{ + START_IE(notify, UNI_IE_NOTIFY, ie->len); + + APP_BUF(msg, ie->notify, ie->len); + if (IE_ISERROR(*ie)) { + /* make it too long */ + u_int i = ie->len; + + while (i < UNI_NOTIFY_MAXLEN + 1) { + APP_BYTE(msg, 0x00); + i++; + } + } + + SET_IE_LEN(msg); + return (0); +} + +DEF_IE_DECODE(itu, notify) +{ + IE_START(;); + + if (ielen > UNI_NOTIFY_MAXLEN || ielen < 1) + goto rej; + + ie->len = ielen; + ielen = 0; + (void)memcpy(ie->notify, msg->b_rptr, ie->len); + msg->b_rptr += ie->len; + + IE_END(NOTIFY); +} + +/********************************************************************* + * + * End-to-end transit delay. + * + * References for this IE are: + * + * Q.2931 pp. 70...71 + * UNI4.0 pp. 69...70 + * PNNI1.0 pp. 198...200 + * + * Not clear, whether the new indicator should be used with NET coding or + * not. + * + * Only ITU-T coding allowed. + */ + +static void +print_eetd(struct uni_ie_eetd *ie, struct unicx *cx) +{ + if (uni_print_iehdr("eetd", &ie->h, cx)) + return; + + if (ie->h.present & UNI_EETD_CUM_P) + uni_print_entry(cx, "cum", "%u", ie->cumulative); + if (ie->h.present & UNI_EETD_MAX_P) { + if (ie->maximum == UNI_EETD_ANYMAX) + uni_print_entry(cx, "max", "any"); + else + uni_print_entry(cx, "max", "%u", ie->maximum); + } + if (ie->h.present & UNI_EETD_PCTD_P) + uni_print_entry(cx, "pnni_cum", "%u", ie->pctd); + if (ie->h.present & UNI_EETD_PMTD_P) + uni_print_entry(cx, "pnni_max", "%u", ie->pmtd); + if (ie->h.present & UNI_EETD_NET_P) + uni_print_flag("netgen", cx); + + uni_print_ieend(cx); +} +DEF_IE_PRINT(itu, eetd) +{ + print_eetd(ie, cx); +} +DEF_IE_PRINT(net, eetd) +{ + print_eetd(ie, cx); +} + +DEF_IE_CHECK(itu, eetd) +{ + + UNUSED(cx); + + if (!(ie->h.present & UNI_EETD_CUM_P)) + return (-1); + if (ie->h.present & (UNI_EETD_PMTD_P | UNI_EETD_PCTD_P)) + return (-1); + return (0); +} + +DEF_IE_CHECK(net, eetd) +{ + + if (!cx->pnni) { + if (!(ie->h.present & UNI_EETD_CUM_P)) + return (-1); + if (ie->h.present & (UNI_EETD_PMTD_P | UNI_EETD_PCTD_P)) + return (-1); + } else { + if (ie->h.present & UNI_EETD_MAX_P) + return (-1); + if ((ie->h.present & UNI_EETD_CUM_P) && + (ie->h.present & UNI_EETD_PCTD_P)) + return (-1); + } + return (0); +} + +DEF_IE_ENCODE(itu, eetd) +{ + START_IE(eetd, UNI_IE_EETD, 9); + + if (ie->h.present & UNI_EETD_CUM_P) { + APP_BYTE(msg, UNI_EETD_CTD_ID); + APP_16BIT(msg, ie->cumulative); + } + if (ie->h.present & UNI_EETD_MAX_P) { + APP_BYTE(msg, UNI_EETD_MTD_ID); + APP_16BIT(msg, ie->maximum); + } + if (ie->h.present & UNI_EETD_PMTD_P) { + APP_BYTE(msg, UNI_EETD_PMTD_ID); + APP_24BIT(msg, ie->pmtd); + } + if (ie->h.present & UNI_EETD_PCTD_P) { + APP_BYTE(msg, UNI_EETD_PCTD_ID); + APP_24BIT(msg, ie->pctd); + } + if (ie->h.present & UNI_EETD_NET_P) { + APP_BYTE(msg, UNI_EETD_NET_ID); + } + + SET_IE_LEN(msg); + return (0); +} + +DEF_IE_ENCODE(net, eetd) +{ + return (uni_ie_encode_itu_eetd(msg, ie, cx)); +} + +DEF_IE_DECODE(itu, eetd) +{ + IE_START(;); + + while (ielen > 0) { + switch (ielen--, *msg->b_rptr++) { + + case UNI_EETD_CTD_ID: + if (ielen < 2) + goto rej; + ie->h.present |= UNI_EETD_CUM_P; + ie->cumulative = *msg->b_rptr++ << 8; + ie->cumulative |= *msg->b_rptr++; + ielen -= 2; + break; + + case UNI_EETD_MTD_ID: + if (ielen < 2) + goto rej; + ie->h.present |= UNI_EETD_MAX_P; + ie->maximum = *msg->b_rptr++ << 8; + ie->maximum |= *msg->b_rptr++; + ielen -= 2; + break; + + case UNI_EETD_PCTD_ID: + if (ielen < 3) + goto rej; + ie->h.present |= UNI_EETD_PCTD_P; + ie->pctd = *msg->b_rptr++ << 16; + ie->pctd |= *msg->b_rptr++ << 8; + ie->pctd |= *msg->b_rptr++; + ielen -= 3; + break; + + case UNI_EETD_PMTD_ID: + if (ielen < 3) + goto rej; + ie->h.present |= UNI_EETD_PMTD_P; + ie->pmtd = *msg->b_rptr++ << 16; + ie->pmtd |= *msg->b_rptr++ << 8; + ie->pmtd |= *msg->b_rptr++; + ielen -= 3; + break; + + case UNI_EETD_NET_ID: + ie->h.present |= UNI_EETD_NET_P; + break; + + default: + goto rej; + } + } + + IE_END(EETD); +} +DEF_IE_DECODE(net, eetd) +{ + return (uni_ie_decode_itu_eetd(ie, msg, ielen, cx)); +} + +/********************************************************************* + * + * Called address + * Called subaddress + * Calling address + * Calling subaddress + * Connected address + * Connected subaddress + * + * References for this IE are: + * + * Q.2931 pp. 60...68 + * ...A4 pp. 27...36 + * UNI4.0 pp. 14...15 + * Q.2951 pp. 28...40 + * + * It is assumed, that the coding of the addr arrays is ok. + * + * Only ITU-T coding allowed. + */ + +static const struct uni_print_tbl screen_tbl[] = { + MKT(UNI_ADDR_SCREEN_NOT, no), + MKT(UNI_ADDR_SCREEN_PASSED, passed), + MKT(UNI_ADDR_SCREEN_FAILED, failed), + MKT(UNI_ADDR_SCREEN_NET, network), + EOT() +}; +static const struct uni_print_tbl pres_tbl[] = { + MKT(UNI_ADDR_PRES, allowed), + MKT(UNI_ADDR_RESTRICT, restricted), + MKT(UNI_ADDR_NONUMBER, no-number), + EOT() +}; + + +static void +print_addr(struct unicx *cx, struct uni_addr *addr) +{ + static const struct uni_print_tbl plan_tbl[] = { + MKT(UNI_ADDR_UNKNOWN, unknown), + MKT(UNI_ADDR_E164, E164), + MKT(UNI_ADDR_ATME, ATME), + MKT(UNI_ADDR_DATA, data), + MKT(UNI_ADDR_PRIVATE, private), + EOT() + }; + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_ADDR_UNKNOWN, unknown), + MKT(UNI_ADDR_INTERNATIONAL, international), + MKT(UNI_ADDR_NATIONAL, national), + MKT(UNI_ADDR_NETWORK, network), + MKT(UNI_ADDR_SUBSCR, subscriber), + MKT(UNI_ADDR_ABBR, abbreviated), + EOT() + }; + u_int i; + + uni_print_entry(cx, "addr", "("); + uni_print_tbl(NULL, addr->type, type_tbl, cx); + uni_putc(',', cx); + uni_print_tbl(NULL, addr->plan, plan_tbl, cx); + uni_putc(',', cx); + if(addr->plan == UNI_ADDR_E164) { + uni_putc('"', cx); + for(i = 0; i < addr->len; i++) { + if(addr->addr[i] < ' ') + uni_printf(cx, "^%c", addr->addr[i] + '@'); + else if(addr->addr[i] <= '~') + uni_putc(addr->addr[i], cx); + else + uni_printf(cx, "\\%03o", addr->addr[i]); + } + uni_putc('"', cx); + + } else if(addr->plan == UNI_ADDR_ATME) { + for(i = 0; i < addr->len; i++) + uni_printf(cx, "%02x", addr->addr[i]); + } + uni_putc(')', cx); +} + +static void +print_addrsub(struct unicx *cx, struct uni_subaddr *addr) +{ + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_SUBADDR_NSAP, NSAP), + MKT(UNI_SUBADDR_ATME, ATME), + MKT(UNI_SUBADDR_USER, USER), + EOT() + }; + u_int i; + + uni_print_entry(cx, "addr", "("); + uni_print_tbl(NULL, addr->type, type_tbl, cx); + uni_putc(',', cx); + + for(i = 0; i < addr->len; i++) + uni_printf(cx, "%02x", addr->addr[i]); + + uni_putc(')', cx); +} + +static int +check_addr(struct uni_addr *addr) +{ + u_int i; + + switch(addr->plan) { + default: + return -1; + + case UNI_ADDR_E164: + if(addr->type != UNI_ADDR_INTERNATIONAL) + return -1; + if(addr->len > 15 || addr->len == 0) + return -1; + for(i = 0; i < addr->len; i++) + if(addr->addr[i] == 0 || (addr->addr[i] & 0x80)) + return -1; + break; + + case UNI_ADDR_ATME: + if(addr->type != UNI_ADDR_UNKNOWN) + return -1; + if(addr->len != 20) + return -1; + break; + } + + return 0; +} + +static int +check_subaddr(struct uni_subaddr *addr) +{ + switch(addr->type) { + default: + return -1; + + case UNI_SUBADDR_NSAP: + if(addr->len != 20) + return -1; + break; + + case UNI_SUBADDR_ATME: + if(addr->len > 20) + return -1; + break; + } + return 0; +} + +static int +check_screen(enum uni_addr_screen screen, enum uni_addr_pres pres) +{ + switch(pres) { + default: + return -1; + + case UNI_ADDR_PRES: + case UNI_ADDR_RESTRICT: + case UNI_ADDR_NONUMBER: + break; + } + switch(screen) { + default: + return -1; + + case UNI_ADDR_SCREEN_NOT: + case UNI_ADDR_SCREEN_PASSED: + case UNI_ADDR_SCREEN_FAILED: + case UNI_ADDR_SCREEN_NET: + break; + } + + return 0; +} + +static void +encode_addr(struct uni_msg *msg, struct uni_addr *addr, u_int flag, + enum uni_addr_screen screen, enum uni_addr_pres pres, int err) +{ + u_char ext = err ? 0x00 : 0x80; + + if (flag) { + APP_BYTE(msg, (addr->type << 4) | addr->plan); + APP_BYTE(msg, ext | (pres << 5) | (screen)); + } else { + APP_BYTE(msg, ext | (addr->type << 4) | addr->plan); + } + APP_BUF(msg, addr->addr, addr->len); +} + +static void +encode_subaddr(struct uni_msg *msg, struct uni_subaddr *addr) +{ + APP_BYTE(msg, 0x80|(addr->type<<4)); + APP_BUF(msg, addr->addr, addr->len); +} + +static int +decode_addr(struct uni_addr *addr, u_int ielen, struct uni_msg *msg, u_int plan) +{ + addr->plan = plan & 0xf; + addr->type = (plan >> 4) & 0x7; + + switch(addr->plan) { + + case UNI_ADDR_E164: + if(ielen > 15 || ielen == 0) + return -1; + addr->addr[ielen] = 0; + break; + + case UNI_ADDR_ATME: + if(ielen != 20) + return -1; + break; + + default: + return -1; + } + (void)memcpy(addr->addr, msg->b_rptr, ielen); + addr->len = ielen; + msg->b_rptr += ielen; + + return 0; +} + +static int +decode_subaddr(struct uni_subaddr *addr, u_int ielen, struct uni_msg *msg, + u_int type) +{ + switch(addr->type = (type >> 4) & 0x7) { + + case UNI_SUBADDR_NSAP: + if(ielen == 0 || ielen > 20) + return -1; + break; + + case UNI_SUBADDR_ATME: + if(ielen != 20) + return -1; + break; + + default: + return -1; + } + if(!(type & 0x80)) + return -1; + if((type & 0x7) != 0) + return -1; + + addr->len = ielen; + (void)memcpy(addr->addr, msg->b_rptr, ielen); + msg->b_rptr += ielen; + + return 0; +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, called) +{ + if (uni_print_iehdr("called", &ie->h, cx)) + return; + print_addr(cx, &ie->addr); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, called) +{ + UNUSED(cx); + + if (check_addr(&ie->addr)) + return (-1); + return (0); +} + +DEF_IE_ENCODE(itu, called) +{ + START_IE(called, UNI_IE_CALLED, 21); + encode_addr(msg, &ie->addr, 0, 0, 0, IE_ISERROR(*ie)); + SET_IE_LEN(msg); + return (0); +} + +DEF_IE_DECODE(itu, called) +{ + u_char c; + IE_START(;); + + if (ielen > 21 || ielen < 1) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + if (!(c & 0x80)) + goto rej; + + if (decode_addr(&ie->addr, ielen, msg, c)) + goto rej; + + IE_END(CALLED); +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, calledsub) +{ + if(uni_print_iehdr("calledsub", &ie->h, cx)) + return; + print_addrsub(cx, &ie->addr); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, calledsub) +{ + UNUSED(cx); + + if(check_subaddr(&ie->addr)) + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, calledsub) +{ + START_IE(calledsub, UNI_IE_CALLEDSUB, 21); + encode_subaddr(msg, &ie->addr); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, calledsub) +{ + u_char c; + + IE_START(;); + + if(ielen > 21) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + if(decode_subaddr(&ie->addr, ielen, msg, c)) + goto rej; + + IE_END(CALLEDSUB); +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, calling) +{ + if(uni_print_iehdr("calling", &ie->h, cx)) + return; + print_addr(cx, &ie->addr); + + if(ie->h.present & UNI_CALLING_SCREEN_P) { + uni_print_tbl("screening", ie->screen, screen_tbl, cx); + uni_print_tbl("presentation", ie->pres, pres_tbl, cx); + } + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, calling) +{ + UNUSED(cx); + + if(check_addr(&ie->addr)) + return -1; + + if(ie->h.present & UNI_CALLING_SCREEN_P) + if(check_screen(ie->screen, ie->pres)) + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, calling) +{ + START_IE(calling, UNI_IE_CALLING, 22); + encode_addr(msg, &ie->addr, ie->h.present & UNI_CALLING_SCREEN_P, ie->screen, ie->pres, IE_ISERROR(*ie)); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, calling) +{ + u_char c, plan; + + IE_START(;); + + if(ielen > 22 || ielen < 1) + goto rej; + + plan = *msg->b_rptr++; + ielen--; + + if(!(plan & 0x80)) { + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + + ie->h.present |= UNI_CALLING_SCREEN_P; + ie->pres = (c >> 5) & 0x3; + ie->screen = c & 0x3; + + if(!(c & 0x80)) + goto rej; + } + + if(decode_addr(&ie->addr, ielen, msg, plan)) + goto rej; + + IE_END(CALLING); +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, callingsub) +{ + if(uni_print_iehdr("callingsub", &ie->h, cx)) + return; + print_addrsub(cx, &ie->addr); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, callingsub) +{ + UNUSED(cx); + + if(check_subaddr(&ie->addr)) + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, callingsub) +{ + START_IE(callingsub, UNI_IE_CALLINGSUB, 21); + encode_subaddr(msg, &ie->addr); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, callingsub) +{ + u_char c; + + IE_START(;); + + if(ielen > 21) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + if(decode_subaddr(&ie->addr, ielen, msg, c)) + goto rej; + + IE_END(CALLINGSUB); +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, conned) +{ + if(uni_print_iehdr("conned", &ie->h, cx)) + return; + print_addr(cx, &ie->addr); + + if(ie->h.present & UNI_CONNED_SCREEN_P) { + uni_print_tbl("screening", ie->screen, screen_tbl, cx); + uni_print_tbl("presentation", ie->pres, pres_tbl, cx); + } + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, conned) +{ + UNUSED(cx); + + if(check_addr(&ie->addr)) + return -1; + + if(ie->h.present & UNI_CONNED_SCREEN_P) + if(check_screen(ie->screen, ie->pres)) + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, conned) +{ + START_IE(conned, UNI_IE_CONNED, 22); + encode_addr(msg, &ie->addr, ie->h.present & UNI_CONNED_SCREEN_P, ie->screen, ie->pres, IE_ISERROR(*ie)); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, conned) +{ + u_char c, plan; + + IE_START(;); + + if(ielen > 22 || ielen < 1) + goto rej; + + plan = *msg->b_rptr++; + ielen--; + + if(!(plan & 0x80)) { + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + + ie->h.present |= UNI_CONNED_SCREEN_P; + ie->pres = (c >> 5) & 0x3; + ie->screen = c & 0x3; + + if(!(c & 0x80)) + goto rej; + } + + if(decode_addr(&ie->addr, ielen, msg, plan)) + goto rej; + + IE_END(CONNED); +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, connedsub) +{ + if(uni_print_iehdr("connedsub", &ie->h, cx)) + return; + print_addrsub(cx, &ie->addr); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, connedsub) +{ + UNUSED(cx); + + if(check_subaddr(&ie->addr)) + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, connedsub) +{ + START_IE(connedsub, UNI_IE_CONNEDSUB, 21); + encode_subaddr(msg, &ie->addr); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, connedsub) +{ + u_char c; + + IE_START(;); + + if(ielen > 21) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + if(decode_subaddr(&ie->addr, ielen, msg, c)) + goto rej; + + IE_END(CONNEDSUB); +} + +/********************************************************************* + * + * Endpoint reference. + * + * References for this IE are: + * + * Q.2971 p. 14 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, epref) +{ + if(uni_print_iehdr("epref", &ie->h, cx)) + return; + uni_print_entry(cx, "epref", "(%u,%u)", ie->flag, ie->epref); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, epref) +{ + UNUSED(cx); + + if(ie->epref >= (2<<15)) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, epref) +{ + START_IE(epref, UNI_IE_EPREF, 3); + + if (IE_ISERROR(*ie)) + APP_BYTE(msg, 0xff); + else + APP_BYTE(msg, 0); + APP_BYTE(msg, (ie->flag << 7) | ((ie->epref >> 8) & 0x7f)); + APP_BYTE(msg, (ie->epref & 0xff)); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, epref) +{ + u_char c; + + IE_START(;); + + if(ielen != 3) + goto rej; + if(*msg->b_rptr++ != 0) + goto rej; + + c = *msg->b_rptr++; + ie->flag = (c & 0x80) ? 1 : 0; + ie->epref = (c & 0x7f) << 8; + ie->epref |= *msg->b_rptr++; + + IE_END(EPREF); +} + +/********************************************************************* + * + * Endpoint state. + * + * References for this IE are: + * + * Q.2971 pp. 14...15 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, epstate) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_EPSTATE_NULL, null), + MKT(UNI_EPSTATE_ADD_INIT, add-initiated), + MKT(UNI_EPSTATE_ALERT_DLVD, alerting-delivered), + MKT(UNI_EPSTATE_ADD_RCVD, add-received), + MKT(UNI_EPSTATE_ALERT_RCVD, alerting-received), + MKT(UNI_EPSTATE_ACTIVE, active), + MKT(UNI_EPSTATE_DROP_INIT, drop-initiated), + MKT(UNI_EPSTATE_DROP_RCVD, drop-received), + EOT() + }; + + if(uni_print_iehdr("epstate", &ie->h, cx)) + return; + uni_print_tbl("state", ie->state, tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, epstate) +{ + UNUSED(cx); + + switch(ie->state) { + default: + return -1; + + case UNI_EPSTATE_NULL: + case UNI_EPSTATE_ADD_INIT: + case UNI_EPSTATE_ALERT_DLVD: + case UNI_EPSTATE_ADD_RCVD: + case UNI_EPSTATE_ALERT_RCVD: + case UNI_EPSTATE_DROP_INIT: + case UNI_EPSTATE_DROP_RCVD: + case UNI_EPSTATE_ACTIVE: + break; + } + + return 0; +} + +DEF_IE_ENCODE(itu, epstate) +{ + START_IE(epstate, UNI_IE_EPSTATE, 1); + + APP_BYTE(msg, ie->state); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, epstate) +{ + IE_START(;); + + if(ielen != 1) + goto rej; + + ie->state = *msg->b_rptr++ & 0x3f; + + IE_END(EPSTATE); +} + +/********************************************************************* + * + * ATM adaptation layer parameters + * + * References for this IE are: + * + * Q.2931 pp. 43...49 + * Q.2931 Amd 2 + * UNI4.0 p. 9 + * + * UNI4.0 states, that AAL2 is not supported. However we keep it. No + * parameters are associated with AAL2. + * + * Amd2 not checked. XXX + * + * Only ITU-T coding allowed. + */ +DEF_IE_PRINT(itu, aal) +{ + static const struct uni_print_tbl aal_tbl[] = { + MKT(UNI_AAL_0, VOICE), + MKT(UNI_AAL_1, 1), + MKT(UNI_AAL_2, 2), + MKT(UNI_AAL_4, 3/4), + MKT(UNI_AAL_5, 5), + MKT(UNI_AAL_USER, USER), + EOT() + }; + static const struct uni_print_tbl subtype_tbl[] = { + MKT(UNI_AAL1_SUB_NULL, null), + MKT(UNI_AAL1_SUB_VOICE, voice), + MKT(UNI_AAL1_SUB_CIRCUIT, circuit), + MKT(UNI_AAL1_SUB_HQAUDIO, hqaudio), + MKT(UNI_AAL1_SUB_VIDEO, video), + EOT() + }; + static const struct uni_print_tbl cbr_rate_tbl[] = { + MKT(UNI_AAL1_CBR_64, 64), + MKT(UNI_AAL1_CBR_1544, 1544(DS1)), + MKT(UNI_AAL1_CBR_6312, 6312(DS2)), + MKT(UNI_AAL1_CBR_32064, 32064), + MKT(UNI_AAL1_CBR_44736, 44736(DS3)), + MKT(UNI_AAL1_CBR_97728, 97728), + MKT(UNI_AAL1_CBR_2048, 2048(E1)), + MKT(UNI_AAL1_CBR_8448, 8448(E2)), + MKT(UNI_AAL1_CBR_34368, 34368(E3)), + MKT(UNI_AAL1_CBR_139264, 139264), + MKT(UNI_AAL1_CBR_N64, Nx64), + MKT(UNI_AAL1_CBR_N8, Nx8), + EOT() + }; + static const struct uni_print_tbl screc_tbl[] = { + MKT(UNI_AAL1_SCREC_NULL, null), + MKT(UNI_AAL1_SCREC_SRTS, srts), + MKT(UNI_AAL1_SCREC_ACLK, aclk), + EOT() + }; + static const struct uni_print_tbl ecm_tbl[] = { + MKT(UNI_AAL1_ECM_NULL, null), + MKT(UNI_AAL1_ECM_LOSS, loss), + MKT(UNI_AAL1_ECM_DELAY, delay), + EOT() + }; + static const struct uni_print_tbl sscs_tbl[] = { + MKT(UNI_AAL_SSCS_NULL, null), + MKT(UNI_AAL_SSCS_SSCOPA, sscopa), + MKT(UNI_AAL_SSCS_SSCOPU, sscopu), + MKT(UNI_AAL_SSCS_FRAME, frame), + EOT() + }; + + if(uni_print_iehdr("aal", &ie->h, cx)) + return; + uni_print_tbl("type", ie->type, aal_tbl, cx); + + switch(ie->type) { + + case UNI_AAL_0: + uni_print_push_prefix("0", cx); + cx->indent++; + break; + + case UNI_AAL_2: + uni_print_push_prefix("2", cx); + cx->indent++; + break; + + case UNI_AAL_1: + uni_print_push_prefix("1", cx); + cx->indent++; + uni_print_tbl("subtype", ie->u.aal1.subtype, subtype_tbl, cx); + uni_print_tbl("cbr_rate", ie->u.aal1.cbr_rate, cbr_rate_tbl, cx); + if(ie->h.present & UNI_AAL1_MULT_P) + uni_print_entry(cx, "mult", "%u", ie->u.aal1.mult); + if(ie->h.present & UNI_AAL1_SCREC_P) + uni_print_tbl("screc", ie->u.aal1.screc, screc_tbl, cx); + if(ie->h.present & UNI_AAL1_ECM_P) + uni_print_tbl("ecm", ie->u.aal1.ecm, ecm_tbl, cx); + if(ie->h.present & UNI_AAL1_BSIZE_P) + uni_print_entry(cx, "bsize", "%u", ie->u.aal1.bsize); + if(ie->h.present & UNI_AAL1_PART_P) + uni_print_entry(cx, "part", "%u", ie->u.aal1.part); + break; + + case UNI_AAL_4: + uni_print_push_prefix("4", cx); + cx->indent++; + if(ie->h.present & UNI_AAL4_CPCS_P) + uni_print_entry(cx, "cpcs", "(%u,%u)", ie->u.aal4.fwd_cpcs, + ie->u.aal4.bwd_cpcs); + if(ie->h.present & UNI_AAL4_MID_P) + uni_print_entry(cx, "mid", "(%u,%u)", ie->u.aal4.mid_low, + ie->u.aal4.mid_high); + if(ie->h.present & UNI_AAL4_SSCS_P) + uni_print_tbl("sscs", ie->u.aal4.sscs, sscs_tbl, cx); + break; + + case UNI_AAL_5: + uni_print_push_prefix("5", cx); + cx->indent++; + if(ie->h.present & UNI_AAL5_CPCS_P) + uni_print_entry(cx, "cpcs", "(%u,%u)", ie->u.aal5.fwd_cpcs, + ie->u.aal5.bwd_cpcs); + if(ie->h.present & UNI_AAL5_SSCS_P) + uni_print_tbl("sscs", ie->u.aal5.sscs, sscs_tbl, cx); + break; + + case UNI_AAL_USER: + uni_print_push_prefix("user", cx); + cx->indent++; + if(ie->u.aalu.len > 4) { + uni_print_entry(cx, "info", "ERROR(len=%u)", ie->u.aalu.len); + } else { + u_int i; + + uni_print_entry(cx, "info", "("); + for(i = 0; i < ie->u.aalu.len; i++) + uni_printf(cx, "%s%u", !i?"":",", ie->u.aalu.user[i]); + uni_printf(cx, ")"); + } + break; + } + cx->indent--; + uni_print_pop_prefix(cx); + uni_print_eol(cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, aal) +{ + UNUSED(cx); + + if(ie->type == UNI_AAL_0) { + ; + } else if(ie->type == UNI_AAL_1) { + switch(ie->u.aal1.subtype) { + + default: + return -1; + + case UNI_AAL1_SUB_NULL: + case UNI_AAL1_SUB_VOICE: + case UNI_AAL1_SUB_CIRCUIT: + case UNI_AAL1_SUB_HQAUDIO: + case UNI_AAL1_SUB_VIDEO: + break; + } + switch(ie->u.aal1.cbr_rate) { + + default: + return -1; + + case UNI_AAL1_CBR_64: + case UNI_AAL1_CBR_1544: + case UNI_AAL1_CBR_6312: + case UNI_AAL1_CBR_32064: + case UNI_AAL1_CBR_44736: + case UNI_AAL1_CBR_97728: + case UNI_AAL1_CBR_2048: + case UNI_AAL1_CBR_8448: + case UNI_AAL1_CBR_34368: + case UNI_AAL1_CBR_139264: + if((ie->h.present & UNI_AAL1_MULT_P)) + return -1; + break; + + case UNI_AAL1_CBR_N64: + if(!(ie->h.present & UNI_AAL1_MULT_P)) + return -1; + if(ie->u.aal1.mult < 2) + return -1; + break; + + case UNI_AAL1_CBR_N8: + if(!(ie->h.present & UNI_AAL1_MULT_P)) + return -1; + if(ie->u.aal1.mult == 0 || ie->u.aal1.mult > 7) + return -1; + break; + } + if(ie->h.present & UNI_AAL1_SCREC_P) { + switch(ie->u.aal1.screc) { + + default: + return -1; + + case UNI_AAL1_SCREC_NULL: + case UNI_AAL1_SCREC_SRTS: + case UNI_AAL1_SCREC_ACLK: + break; + } + } + if(ie->h.present & UNI_AAL1_ECM_P) { + switch(ie->u.aal1.ecm) { + + default: + return -1; + + case UNI_AAL1_ECM_NULL: + case UNI_AAL1_ECM_LOSS: + case UNI_AAL1_ECM_DELAY: + break; + } + } + if(ie->h.present & UNI_AAL1_BSIZE_P) { + if(ie->u.aal1.bsize == 0) + return -1; + } + if(ie->h.present & UNI_AAL1_PART_P) { + if(ie->u.aal1.part == 0 || ie->u.aal1.part > 47) + return -1; + } + + } else if(ie->type == UNI_AAL_2) { + ; + + } else if(ie->type == UNI_AAL_4) { + if(ie->h.present & UNI_AAL4_MID_P) { + if(ie->u.aal4.mid_low >= 1024) + return -1; + if(ie->u.aal4.mid_high >= 1024) + return -1; + if(ie->u.aal4.mid_low > ie->u.aal4.mid_high) + return -1; + } + if(ie->h.present & UNI_AAL4_SSCS_P) { + switch(ie->u.aal4.sscs) { + + default: + return -1; + + case UNI_AAL_SSCS_NULL: + case UNI_AAL_SSCS_SSCOPA: + case UNI_AAL_SSCS_SSCOPU: + case UNI_AAL_SSCS_FRAME: + break; + } + } + + } else if(ie->type == UNI_AAL_5) { + if(ie->h.present & UNI_AAL5_SSCS_P) { + switch(ie->u.aal5.sscs) { + + default: + return -1; + + case UNI_AAL_SSCS_NULL: + case UNI_AAL_SSCS_SSCOPA: + case UNI_AAL_SSCS_SSCOPU: + case UNI_AAL_SSCS_FRAME: + break; + } + } + + } else if(ie->type == UNI_AAL_USER) { + if(ie->u.aalu.len > 4) + return -1; + + } else + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, aal) +{ + START_IE(aal, UNI_IE_AAL, 16); + + APP_BYTE(msg, ie->type); + switch(ie->type) { + + case UNI_AAL_0: + break; + + case UNI_AAL_1: + APP_SUB_BYTE(msg, + UNI_AAL_SUB_ID, ie->u.aal1.subtype); + APP_SUB_BYTE(msg, + UNI_AAL_CBR_ID, ie->u.aal1.cbr_rate); + APP_OPT_16BIT(msg, ie->h.present, UNI_AAL1_MULT_P, + UNI_AAL_MULT_ID, ie->u.aal1.mult); + APP_OPT_BYTE(msg, ie->h.present, UNI_AAL1_SCREC_P, + UNI_AAL_SCREC_ID, ie->u.aal1.screc); + APP_OPT_BYTE(msg, ie->h.present, UNI_AAL1_ECM_P, + UNI_AAL_ECM_ID, ie->u.aal1.ecm); + APP_OPT_16BIT(msg, ie->h.present, UNI_AAL1_BSIZE_P, + UNI_AAL_BSIZE_ID, ie->u.aal1.bsize); + APP_OPT_BYTE(msg, ie->h.present, UNI_AAL1_PART_P, + UNI_AAL_PART_ID, ie->u.aal1.part); + break; + + case UNI_AAL_2: + break; + + case UNI_AAL_4: + if(ie->h.present & UNI_AAL4_CPCS_P) { + APP_SUB_16BIT(msg, + UNI_AAL_FWDCPCS_ID, ie->u.aal4.fwd_cpcs); + APP_SUB_16BIT(msg, + UNI_AAL_BWDCPCS_ID, ie->u.aal4.bwd_cpcs); + } + if(ie->h.present & UNI_AAL4_MID_P) { + APP_BYTE(msg, UNI_AAL_MID_ID); + APP_16BIT(msg, ie->u.aal4.mid_low); + APP_16BIT(msg, ie->u.aal4.mid_high); + } + APP_OPT_BYTE(msg, ie->h.present, UNI_AAL4_SSCS_P, + UNI_AAL_SSCS_ID, ie->u.aal4.sscs); + break; + + case UNI_AAL_5: + if(ie->h.present & UNI_AAL5_CPCS_P) { + APP_SUB_16BIT(msg, + UNI_AAL_FWDCPCS_ID, ie->u.aal5.fwd_cpcs); + APP_SUB_16BIT(msg, + UNI_AAL_BWDCPCS_ID, ie->u.aal5.bwd_cpcs); + } + APP_OPT_BYTE(msg, ie->h.present, UNI_AAL5_SSCS_P, + UNI_AAL_SSCS_ID, ie->u.aal5.sscs); + break; + + case UNI_AAL_USER: + APP_BUF(msg, ie->u.aalu.user, ie->u.aalu.len); + break; + + default: + return -1; + } + + SET_IE_LEN(msg); + return 0; +} + +/* + * XXX What should we do with multiple subtype occurences? Ignore + * or reject. Currently we reject. + */ +static int +decode_aal_1(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen) +{ + int subtype_p, cbr_p; + + subtype_p = cbr_p = 0; + + while(ielen-- > 0) { + switch(*msg->b_rptr++) { + + case UNI_AAL_SUB_ID: + if(ielen == 0 || subtype_p) + return -1; + ielen--; + subtype_p = 1; + ie->u.aal1.subtype = *msg->b_rptr++; + break; + + case UNI_AAL_CBR_ID: + if(ielen == 0 || cbr_p) + return -1; + ielen--; + cbr_p = 1; + ie->u.aal1.cbr_rate = *msg->b_rptr++; + break; + + case UNI_AAL_MULT_ID: + if(ielen < 2 || (ie->h.present & UNI_AAL1_MULT_P)) + return -1; + ielen -= 2; + ie->h.present |= UNI_AAL1_MULT_P; + ie->u.aal1.mult = *msg->b_rptr++ << 8; + ie->u.aal1.mult |= *msg->b_rptr++; + break; + + case UNI_AAL_SCREC_ID: + if(ielen == 0 || (ie->h.present & UNI_AAL1_SCREC_P)) + return -1; + ielen--; + ie->h.present |= UNI_AAL1_SCREC_P; + ie->u.aal1.screc = *msg->b_rptr++; + break; + + case UNI_AAL_ECM_ID: + if(ielen == 0 || (ie->h.present & UNI_AAL1_ECM_P)) + return -1; + ielen--; + ie->h.present |= UNI_AAL1_ECM_P; + ie->u.aal1.ecm = *msg->b_rptr++; + break; + + case UNI_AAL_BSIZE_ID: + if(ielen < 2 || (ie->h.present & UNI_AAL1_BSIZE_P)) + return -1; + ielen -= 2; + ie->h.present |= UNI_AAL1_BSIZE_P; + ie->u.aal1.bsize = *msg->b_rptr++ << 8; + ie->u.aal1.bsize |= *msg->b_rptr++; + break; + + case UNI_AAL_PART_ID: + if(ielen == 0 || (ie->h.present & UNI_AAL1_PART_P)) + return -1; + ielen--; + ie->h.present |= UNI_AAL1_PART_P; + ie->u.aal1.part = *msg->b_rptr++; + break; + + default: + return -1; + } + } + if(!subtype_p || !cbr_p) + return -1; + + return 0; +} + +static int +decode_aal_4(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen) +{ + int fcpcs_p, bcpcs_p; + + fcpcs_p = bcpcs_p = 0; + + while(ielen-- > 0) { + switch(*msg->b_rptr++) { + + case UNI_AAL_FWDCPCS_ID: + if(ielen < 2 || fcpcs_p) + return -1; + ielen -= 2; + fcpcs_p = 1; + ie->u.aal4.fwd_cpcs = *msg->b_rptr++ << 8; + ie->u.aal4.fwd_cpcs |= *msg->b_rptr++; + break; + + case UNI_AAL_BWDCPCS_ID: + if(ielen < 2 || bcpcs_p) + return -1; + ielen -= 2; + bcpcs_p = 1; + ie->u.aal4.bwd_cpcs = *msg->b_rptr++ << 8; + ie->u.aal4.bwd_cpcs |= *msg->b_rptr++; + break; + + case UNI_AAL_MID_ID: + if(ielen < 4 || (ie->h.present & UNI_AAL4_MID_P)) + return -1; + ielen -= 4; + ie->h.present |= UNI_AAL4_MID_P; + ie->u.aal4.mid_low = *msg->b_rptr++ << 8; + ie->u.aal4.mid_low |= *msg->b_rptr++; + ie->u.aal4.mid_high = *msg->b_rptr++ << 8; + ie->u.aal4.mid_high |= *msg->b_rptr++; + break; + + case UNI_AAL_SSCS_ID: + if(ielen == 0 || (ie->h.present & UNI_AAL4_SSCS_P)) + return -1; + ielen--; + ie->h.present |= UNI_AAL4_SSCS_P; + ie->u.aal4.sscs = *msg->b_rptr++; + break; + + default: + return -1; + } + } + + if(fcpcs_p ^ bcpcs_p) + return -1; + if(fcpcs_p) + ie->h.present |= UNI_AAL4_CPCS_P; + + return 0; +} + +static int +decode_aal_5(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen) +{ + int fcpcs_p, bcpcs_p; + + fcpcs_p = bcpcs_p = 0; + + while(ielen-- > 0) { + switch(*msg->b_rptr++) { + + case UNI_AAL_FWDCPCS_ID: + if(ielen < 2 || fcpcs_p) + return -1; + ielen -= 2; + fcpcs_p = 1; + ie->u.aal5.fwd_cpcs = *msg->b_rptr++ << 8; + ie->u.aal5.fwd_cpcs |= *msg->b_rptr++; + break; + + case UNI_AAL_BWDCPCS_ID: + if(ielen < 2 || bcpcs_p) + return -1; + ielen -= 2; + bcpcs_p = 1; + ie->u.aal5.bwd_cpcs = *msg->b_rptr++ << 8; + ie->u.aal5.bwd_cpcs |= *msg->b_rptr++; + break; + + case UNI_AAL_SSCS_ID: + if(ielen == 0 || (ie->h.present & UNI_AAL5_SSCS_P)) + return -1; + ielen--; + ie->h.present |= UNI_AAL5_SSCS_P; + ie->u.aal5.sscs = *msg->b_rptr++; + break; + + default: + return -1; + } + } + + if(fcpcs_p ^ bcpcs_p) + return -1; + if(fcpcs_p) + ie->h.present |= UNI_AAL5_CPCS_P; + + return 0; +} + +static int +decode_aal_user(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen) +{ + if(ielen > 4) + return -1; + + ie->u.aalu.len = 0; + while(ielen--) + ie->u.aalu.user[ie->u.aalu.len++] = *msg->b_rptr++; + + return 0; +} + +DEF_IE_DECODE(itu, aal) +{ + u_char c; + + IE_START(DISC_ACC_ERR(AAL)); + + if(ielen < 1 || ielen > 21) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + switch(c) { + + case UNI_AAL_0: + ie->type = c; + break; + + case UNI_AAL_1: + ie->type = c; + if(decode_aal_1(ie, msg, ielen)) + goto rej; + break; + + case UNI_AAL_2: + ie->type = c; + break; + + case UNI_AAL_4: + ie->type = c; + if(decode_aal_4(ie, msg, ielen)) + goto rej; + break; + + case UNI_AAL_5: + ie->type = c; + if(decode_aal_5(ie, msg, ielen)) + goto rej; + break; + + case UNI_AAL_USER: + ie->type = c; + if(decode_aal_user(ie, msg, ielen)) + goto rej; + break; + + default: + goto rej; + } + + IE_END(AAL); +} + +/********************************************************************* + * + * Traffic descriptor. + * Alternate traffic descriptor. + * Minimum traffic descriptor. + * + * References for this IE are: + * + * Q.2931 pp. 49...51 + * Q.2961 + * Q.2962 + * UNI4.0 pp. 9...10, 106...109 + * + * The Q.s specify the coding. UNI4.0 adds frame discard and best-effort. + * Appendix in UNI4.0 lists the allowed combinations. + * + * PCR0 PCR1 SCR/MBS0 SCR/MBS1 BE TAG FDISC ABR + * 1 CBR.1 - Y - - - N Y/N - + * 2 CBR.2 - Y - - - N Y/N - (*) + * 3 CBR.3 Y Y - - - Y Y/N - (*) + * 4 rt-VBR.1 - Y - Y - N Y/N - + * 5 rt-VBR.2 - Y Y - - N Y/N - + * 6 rt-VBR.3 - Y Y - - Y Y/N - + * 7 rt-VBR.4 Y Y - - - Y/N Y/N - (*) + * 8 rt-VBR.5 - Y - - - N Y/N - (*) + * 9 rt-VBR.6 - Y - Y - N Y/N - (*) + * 10 nrt-VBR.1 - Y - Y - N Y/N - + * 11 nrt-VBR.2 - Y Y - - N Y/N - + * 12 nrt-VBR.3 - Y Y - - Y Y/N - + * 13 nrt-VBR.4 Y Y - - - Y/N Y/N - (*) + * 14 nrt-VBR.5 - Y - - - N Y/N - (*) + * 15 nrt-VBR.6 - Y - Y - N Y/N - (*) + * 16 ABR - Y - - - N Y/N O (*) + * 17 UBR.1 - Y - - Y N Y/N - + * 18 UBR.2 - Y - - Y Y Y/N - + * + * Allow ITU-T and NET coding, because its not clear, whether the + * new fields in UNI4.0 should be used with NET coding or not. + * Does not allow for experimental codings yet. + */ + +static void +print_ie_traffic_common(struct unicx *cx, u_int present, struct uni_xtraffic *ie) +{ + uni_print_entry(cx, "fwd", "("); + if(present & UNI_TRAFFIC_FPCR0_P) + uni_printf(cx, "%u", ie->fpcr0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FPCR1_P) + uni_printf(cx, "%u", ie->fpcr1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FSCR0_P) + uni_printf(cx, "%u", ie->fscr0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FSCR1_P) + uni_printf(cx, "%u", ie->fscr1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FMBS0_P) + uni_printf(cx, "%u", ie->fmbs0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FMBS1_P) + uni_printf(cx, "%u", ie->fmbs1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FABR1_P) + uni_printf(cx, "%u", ie->fabr1); + uni_printf(cx, ")"); + + uni_print_entry(cx, "bwd", "("); + if(present & UNI_TRAFFIC_BPCR0_P) + uni_printf(cx, "%u", ie->bpcr0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BPCR1_P) + uni_printf(cx, "%u", ie->bpcr1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BSCR0_P) + uni_printf(cx, "%u", ie->bscr0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BSCR1_P) + uni_printf(cx, "%u", ie->bscr1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BMBS0_P) + uni_printf(cx, "%u", ie->bmbs0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BMBS1_P) + uni_printf(cx, "%u", ie->bmbs1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BABR1_P) + uni_printf(cx, "%u", ie->babr1); + uni_printf(cx, ")"); + + if(present & UNI_TRAFFIC_BEST_P) + uni_print_flag("best_effort", cx); + if(present & UNI_TRAFFIC_MOPT_P) { + uni_print_entry(cx, "tag", "("); + if(ie->ftag) + uni_printf(cx, "fwd"); + uni_putc(',', cx); + if(ie->btag) + uni_printf(cx, "bwd"); + uni_putc(')', cx); + + uni_print_entry(cx, "disc", "("); + if(ie->fdisc) + uni_printf(cx, "fwd"); + uni_putc(',', cx); + if(ie->bdisc) + uni_printf(cx, "bwd"); + uni_putc(')', cx); + } +} + +struct tallow { + u_int mask; + int mopt_flag; + u_char mopt_mask, mopt_val; +}; + +static int +check_traffic(u_int mask, u_int mopt, struct tallow *a) +{ + if(mask != a->mask) + return 0; + + if(a->mopt_flag == 0) { + /* not allowed */ + if(mopt == 0xffff) + return 1; + return 0; + } + + if(a->mopt_flag < 0) { + /* optional */ + if(mopt == 0xffff) + return 1; + if((mopt & a->mopt_mask) == a->mopt_val) + return 1; + return 0; + } + + /* required */ + if(mopt == 0xffff) + return 0; + if((mopt & a->mopt_mask) == a->mopt_val) + return 1; + return 0; +} + +static int +check_ie_traffic_common(struct uni_xtraffic *ie, u_int present, + struct unicx *cx __unused) +{ + static u_int fmask = + UNI_TRAFFIC_FPCR0_P | UNI_TRAFFIC_FPCR1_P | + UNI_TRAFFIC_FSCR0_P | UNI_TRAFFIC_FSCR1_P | + UNI_TRAFFIC_FMBS0_P | UNI_TRAFFIC_FMBS1_P | + UNI_TRAFFIC_FABR1_P; + static u_int bmask = + UNI_TRAFFIC_BPCR0_P | UNI_TRAFFIC_BPCR1_P | + UNI_TRAFFIC_BSCR0_P | UNI_TRAFFIC_BSCR1_P | + UNI_TRAFFIC_BMBS0_P | UNI_TRAFFIC_BMBS1_P | + UNI_TRAFFIC_BABR1_P; +#define DTAB(U,X) \ + { U##X##PCR1_P, \ + -1, U##X##TAG, 0 }, /* 1, 2, 8, 14 */ \ + { U##X##PCR0_P | U##X##PCR1_P, \ + +1, U##X##TAG, U##X##TAG }, /* 3 */ \ + { U##X##PCR1_P | U##X##SCR1_P | U##X##MBS1_P, \ + -1, U##X##TAG, 0 }, /* 4, 9, 10, 15 */ \ + { U##X##PCR1_P | U##X##SCR0_P | U##X##MBS0_P, \ + -1, 0, 0 }, /* 5, 6, 11, 12 */ \ + { U##X##PCR0_P | U##X##PCR1_P, \ + -1, 0, 0 }, /* 7, 13 */ \ + { U##X##PCR1_P | U##X##ABR1_P, \ + -1, U##X##TAG, 0 }, /* 16a */ +#define DTABSIZE 6 + + static struct tallow allow[2][DTABSIZE] = { + { DTAB(UNI_TRAFFIC_, F) }, + { DTAB(UNI_TRAFFIC_, B) }, + }; +#undef DTAB + + u_int f, b, p, m; + int i; + + f = present & fmask; + b = present & bmask; + p = present & (fmask | bmask); + m = (present & UNI_TRAFFIC_MOPT_P) + ? ( (ie->ftag ? UNI_TRAFFIC_FTAG : 0) + | (ie->btag ? UNI_TRAFFIC_BTAG : 0) + | (ie->fdisc ? UNI_TRAFFIC_FDISC : 0) + | (ie->bdisc ? UNI_TRAFFIC_BDISC : 0)) + : 0xffff; + + + if(present & UNI_TRAFFIC_BEST_P) { + /* + * Lines 17 and 18 + */ + if(p != (UNI_TRAFFIC_FPCR1_P | UNI_TRAFFIC_BPCR1_P)) + return -1; + return 0; + } + + /* + * Check forward and backward independent. There must be a higher + * level checking in the CAC + */ + for(i = 0; i < DTABSIZE; i++) + if(check_traffic(f, m, &allow[0][i])) + break; + if(i == DTABSIZE) + return -1; + + for(i = 0; i < DTABSIZE; i++) + if(check_traffic(b, m, &allow[1][i])) + break; + if(i == DTABSIZE) + return -1; + + return 0; +} + +static int +encode_traffic_common(struct uni_msg *msg, struct uni_xtraffic *ie, + u_int present, struct unicx *cx __unused) +{ + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FPCR0_P, + UNI_TRAFFIC_FPCR0_ID, ie->fpcr0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BPCR0_P, + UNI_TRAFFIC_BPCR0_ID, ie->bpcr0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FPCR1_P, + UNI_TRAFFIC_FPCR1_ID, ie->fpcr1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BPCR1_P, + UNI_TRAFFIC_BPCR1_ID, ie->bpcr1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FSCR0_P, + UNI_TRAFFIC_FSCR0_ID, ie->fscr0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BSCR0_P, + UNI_TRAFFIC_BSCR0_ID, ie->bscr0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FSCR1_P, + UNI_TRAFFIC_FSCR1_ID, ie->fscr1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BSCR1_P, + UNI_TRAFFIC_BSCR1_ID, ie->bscr1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FMBS0_P, + UNI_TRAFFIC_FMBS0_ID, ie->fmbs0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BMBS0_P, + UNI_TRAFFIC_BMBS0_ID, ie->bmbs0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FMBS1_P, + UNI_TRAFFIC_FMBS1_ID, ie->fmbs1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BMBS1_P, + UNI_TRAFFIC_BMBS1_ID, ie->bmbs1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FABR1_P, + UNI_TRAFFIC_FABR1_ID, ie->fabr1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BABR1_P, + UNI_TRAFFIC_BABR1_ID, ie->babr1); + + APP_OPT(msg, present, UNI_TRAFFIC_BEST_P, + UNI_TRAFFIC_BEST_ID); + APP_OPT_BYTE(msg, present, UNI_TRAFFIC_MOPT_P, + UNI_TRAFFIC_MOPT_ID, + (ie->ftag ? UNI_TRAFFIC_FTAG : 0) | + (ie->btag ? UNI_TRAFFIC_BTAG : 0) | + (ie->fdisc ? UNI_TRAFFIC_FDISC : 0) | + (ie->fdisc ? UNI_TRAFFIC_BDISC : 0)); + + return 0; +} + +static int +decode_traffic_common(struct uni_xtraffic *ie, struct uni_msg *msg, + u_int ielen, u_int *present) +{ + u_char c; + + while(ielen--) { + switch(c = *msg->b_rptr++) { + + default: + rej: + return -1; + + DEC_GETF3(TRAFFIC_FPCR0, fpcr0, *present); + DEC_GETF3(TRAFFIC_BPCR0, bpcr0, *present); + DEC_GETF3(TRAFFIC_FPCR1, fpcr1, *present); + DEC_GETF3(TRAFFIC_BPCR1, bpcr1, *present); + DEC_GETF3(TRAFFIC_FSCR0, fscr0, *present); + DEC_GETF3(TRAFFIC_BSCR0, bscr0, *present); + DEC_GETF3(TRAFFIC_FSCR1, fscr1, *present); + DEC_GETF3(TRAFFIC_BSCR1, bscr1, *present); + DEC_GETF3(TRAFFIC_FMBS0, fmbs0, *present); + DEC_GETF3(TRAFFIC_BMBS0, bmbs0, *present); + DEC_GETF3(TRAFFIC_BMBS1, bmbs1, *present); + DEC_GETF3(TRAFFIC_FABR1, fabr1, *present); + DEC_GETF3(TRAFFIC_BABR1, babr1, *present); + + case UNI_TRAFFIC_BEST_ID: + *present |= UNI_TRAFFIC_BEST_P; + break; + + case UNI_TRAFFIC_MOPT_ID: + if(ielen == 0) + return -1; + ielen--; + if(!(*present & UNI_TRAFFIC_MOPT_P)) { + *present |= UNI_TRAFFIC_MOPT_P; + ie->ftag = (*msg->b_rptr&UNI_TRAFFIC_FTAG)?1:0; + ie->btag = (*msg->b_rptr&UNI_TRAFFIC_BTAG)?1:0; + ie->fdisc = (*msg->b_rptr&UNI_TRAFFIC_FDISC)?1:0; + ie->bdisc = (*msg->b_rptr&UNI_TRAFFIC_BDISC)?1:0; + } + msg->b_rptr++; + break; + } + } + return 0; +} + + +/*****************************************************************/ + +DEF_IE_PRINT(itu, traffic) +{ + if(uni_print_iehdr("traffic", &ie->h, cx)) + return; + print_ie_traffic_common(cx, ie->h.present, &ie->t); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, traffic) +{ + return check_ie_traffic_common(&ie->t, ie->h.present, cx); +} + +DEF_IE_ENCODE(itu, traffic) +{ + START_IE(traffic, UNI_IE_TRAFFIC, 26); + encode_traffic_common(msg, &ie->t, ie->h.present, cx); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, traffic) +{ + IE_START(;); + + if(ielen > 30) + goto rej; + + if(decode_traffic_common(&ie->t, msg, ielen, &ie->h.present)) + goto rej; + + IE_END(TRAFFIC); +} + +/*****************************************************************/ + +DEF_IE_PRINT(itu, atraffic) +{ + if(uni_print_iehdr("atraffic", &ie->h, cx)) + return; + print_ie_traffic_common(cx, ie->h.present, &ie->t); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, atraffic) +{ + return check_ie_traffic_common(&ie->t, ie->h.present, cx); +} + +DEF_IE_ENCODE(itu, atraffic) +{ + START_IE(traffic, UNI_IE_ATRAFFIC, 26); + encode_traffic_common(msg, &ie->t, ie->h.present, cx); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, atraffic) +{ + IE_START(;); + + if(ielen > 30) + goto rej; + + if(decode_traffic_common(&ie->t, msg, ielen, &ie->h.present)) + goto rej; + + IE_END(ATRAFFIC); +} + +/*****************************************************************/ + +DEF_IE_PRINT(itu, mintraffic) +{ + if(uni_print_iehdr("mintraffic", &ie->h, cx)) + return; + + uni_print_entry(cx, "pcr0", "("); + if(ie->h.present & UNI_MINTRAFFIC_FPCR0_P) + uni_printf(cx, "%u", ie->fpcr0); + uni_putc(',', cx); + if(ie->h.present & UNI_MINTRAFFIC_BPCR0_P) + uni_printf(cx, "%u", ie->bpcr0); + uni_putc(')', cx); + + uni_print_entry(cx, "pcr1", "("); + if(ie->h.present & UNI_MINTRAFFIC_FPCR1_P) + uni_printf(cx, "%u", ie->fpcr1); + uni_putc(',', cx); + if(ie->h.present & UNI_MINTRAFFIC_BPCR1_P) + uni_printf(cx, "%u", ie->bpcr1); + uni_putc(')', cx); + + uni_print_entry(cx, "abr1", "("); + if(ie->h.present & UNI_MINTRAFFIC_FABR1_P) + uni_printf(cx, "%u", ie->fabr1); + uni_putc(',', cx); + if(ie->h.present & UNI_MINTRAFFIC_BABR1_P) + uni_printf(cx, "%u", ie->babr1); + uni_printf(cx, ")"); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, mintraffic) +{ + u_int abr; + u_int xbr; + UNUSED(cx); + + abr = ie->h.present & (UNI_MINTRAFFIC_FABR1_P|UNI_MINTRAFFIC_BABR1_P); + xbr = ie->h.present & (UNI_MINTRAFFIC_FPCR0_P|UNI_MINTRAFFIC_BPCR0_P| + UNI_MINTRAFFIC_FPCR1_P|UNI_MINTRAFFIC_BPCR1_P); + + if(abr && xbr) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, mintraffic) +{ + START_IE(mintraffic, UNI_IE_MINTRAFFIC, 16); + + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_FPCR0_P, + UNI_TRAFFIC_FPCR0_ID, ie->fpcr0); + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_BPCR0_P, + UNI_TRAFFIC_BPCR0_ID, ie->bpcr0); + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_FPCR1_P, + UNI_TRAFFIC_FPCR1_ID, ie->fpcr1); + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_BPCR1_P, + UNI_TRAFFIC_BPCR1_ID, ie->bpcr1); + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_FABR1_P, + UNI_TRAFFIC_FABR1_ID, ie->fabr1); + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_BABR1_P, + UNI_TRAFFIC_BABR1_ID, ie->babr1); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, mintraffic) +{ + u_char c; + + IE_START(;); + + if(ielen > 20) + goto rej; + + while(ielen--) { + switch(c = *msg->b_rptr++) { + + default: + goto rej; + + DEC_GETF3(MINTRAFFIC_FPCR0, fpcr0, ie->h.present); + DEC_GETF3(MINTRAFFIC_BPCR0, bpcr0, ie->h.present); + DEC_GETF3(MINTRAFFIC_FPCR1, fpcr1, ie->h.present); + DEC_GETF3(MINTRAFFIC_BPCR1, bpcr1, ie->h.present); + DEC_GETF3(MINTRAFFIC_FABR1, fabr1, ie->h.present); + DEC_GETF3(MINTRAFFIC_BABR1, babr1, ie->h.present); + } + } + + IE_END(MINTRAFFIC); +} + +/*****************************************************************/ + +DEF_IE_PRINT(net, mdcr) +{ + static const struct uni_print_tbl origin_tbl[] = { + MKT(UNI_MDCR_ORIGIN_USER, user), + MKT(UNI_MDCR_ORIGIN_NET, net), + EOT() + }; + + if(uni_print_iehdr("mdcr", &ie->h, cx)) + return; + + uni_print_tbl("origin", ie->origin, origin_tbl, cx); + uni_print_entry(cx, "mdcr", "("); + uni_printf(cx, "%u", ie->fmdcr); + uni_putc(',', cx); + uni_printf(cx, "%u", ie->bmdcr); + uni_putc(')', cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, mdcr) +{ + UNUSED(cx); + + if ((ie->origin != UNI_MDCR_ORIGIN_USER && + ie->origin != UNI_MDCR_ORIGIN_NET) || + ie->fmdcr >= (1 << 24) || ie->bmdcr >= (1 << 24)) + return (-1); + + return (0); +} + +DEF_IE_ENCODE(net, mdcr) +{ + START_IE(mdcr, UNI_IE_MDCR, 9); + + APP_BYTE(msg, ie->origin); + APP_SUB_24BIT(msg, UNI_TRAFFIC_FMDCR_ID, ie->fmdcr); + APP_SUB_24BIT(msg, UNI_TRAFFIC_BMDCR_ID, ie->bmdcr); + + SET_IE_LEN(msg); + return (0); +} + +DEF_IE_DECODE(net, mdcr) +{ + u_char c; +#define UNI_TRAFFIC_FMDCR_P 0x01 +#define UNI_TRAFFIC_BMDCR_P 0x02 + u_int p = 0; + + IE_START(;); + + if(ielen != 9) + goto rej; + + ie->origin = *msg->b_rptr++; + ielen--; + + while(ielen--) { + switch(c = *msg->b_rptr++) { + + default: + goto rej; + + DEC_GETF3(TRAFFIC_FMDCR, fmdcr, p); + DEC_GETF3(TRAFFIC_BMDCR, bmdcr, p); + } + } + if (p != (UNI_TRAFFIC_FMDCR_P | UNI_TRAFFIC_BMDCR_P)) + goto rej; + + IE_END(MDCR); +} + +/********************************************************************* + * + * Connection identifier + * + * References for this IE are: + * + * Q.2931 pp. 69...70 + * UNI4.0 pp. 15...16 + * PNNI1.0 p. 198 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, connid) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_CONNID_VCI, exclusive), + MKT(UNI_CONNID_ANYVCI, any), + MKT(UNI_CONNID_NOVCI, no), + EOT() + }; + static const struct uni_print_tbl assoc_tbl[] = { + MKT(UNI_CONNID_ASSOC, associated), + MKT(UNI_CONNID_NONASSOC,non-associated), + EOT() + }; + + if(uni_print_iehdr("connid", &ie->h, cx)) + return; + + uni_print_tbl("mode", ie->assoc, assoc_tbl, cx); + uni_print_entry(cx, "connid", "(%u,", ie->vpci); + if(ie->type == UNI_CONNID_VCI) + uni_printf(cx, "%u", ie->vci); + else + uni_print_tbl(NULL, ie->type, tbl, cx); + uni_printf(cx, ")"); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, connid) +{ + UNUSED(cx); + switch(ie->type) { + default: + return -1; + case UNI_CONNID_VCI: + case UNI_CONNID_ANYVCI: + case UNI_CONNID_NOVCI: + break; + } + +#if 0 + /* + * This field must be checked by the application to fulfil + * Q.2931Amd4 27) 5.2.3 last sentence + */ + switch(ie->assoc) { + + case UNI_CONNID_ASSOC: + if(!cx->cx.pnni) + return -1; + break; + + case UNI_CONNID_NONASSOC: + break; + + default: + return -1; + } +#endif + return 0; +} + +DEF_IE_ENCODE(itu, connid) +{ + START_IE(connid, UNI_IE_CONNID, 5); + + APP_BYTE(msg, 0x80 | (ie->assoc << 3) | ie->type); + APP_BYTE(msg, ie->vpci >> 8); + APP_BYTE(msg, ie->vpci >> 0); + APP_BYTE(msg, ie->vci >> 8); + APP_BYTE(msg, ie->vci >> 0); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, connid) +{ + u_char c; + + IE_START(;); + + if(ielen != 5) + goto rej; + + c = *msg->b_rptr++; + if((c & 0x80) == 0) + goto rej; + ie->assoc = (c >> 3) & 3; + ie->type = c & 7; + ie->vpci = *msg->b_rptr++ << 8; + ie->vpci |= *msg->b_rptr++; + ie->vci = *msg->b_rptr++ << 8; + ie->vci |= *msg->b_rptr++; + + IE_END(CONNID); +} + +/********************************************************************* + * + * Quality of Service + * + * References for this IE are: + * + * Q.2931 pp. 72 + * UNI4.0 pp. 16...17 + */ + +static void +print_qos(struct unicx *cx, struct uni_ie_qos *ie) +{ + static const struct uni_print_tbl class_tbl[] = { + MKT(UNI_QOS_CLASS0, Class0), + MKT(UNI_QOS_CLASS1, Class1), + MKT(UNI_QOS_CLASS2, Class2), + MKT(UNI_QOS_CLASS3, Class3), + MKT(UNI_QOS_CLASS4, Class4), + EOT() + }; + + if(uni_print_iehdr("qos", &ie->h, cx)) + return; + + uni_print_tbl("fwd", ie->fwd, class_tbl, cx); + uni_print_tbl("bwd", ie->bwd, class_tbl, cx); + + uni_print_ieend(cx); +} + +DEF_IE_PRINT(itu, qos) +{ + print_qos(cx, ie); +} +DEF_IE_PRINT(net, qos) +{ + print_qos(cx, ie); +} + +DEF_IE_CHECK(itu, qos) +{ + UNUSED(cx); + + switch(ie->fwd) { + default: + return -1; + + case UNI_QOS_CLASS0: + break; + } + switch(ie->bwd) { + default: + return -1; + + case UNI_QOS_CLASS0: + break; + } + return 0; +} + +DEF_IE_CHECK(net, qos) +{ + UNUSED(cx); + + switch(ie->fwd) { + default: + return -1; + + case UNI_QOS_CLASS1: + case UNI_QOS_CLASS2: + case UNI_QOS_CLASS3: + case UNI_QOS_CLASS4: + break; + } + switch(ie->bwd) { + default: + return -1; + + case UNI_QOS_CLASS1: + case UNI_QOS_CLASS2: + case UNI_QOS_CLASS3: + case UNI_QOS_CLASS4: + break; + } + return 0; +} + +DEF_IE_ENCODE(itu, qos) +{ + START_IE(qos, UNI_IE_QOS, 2); + + APP_BYTE(msg, ie->fwd); + APP_BYTE(msg, ie->bwd); + + SET_IE_LEN(msg); + return 0; +} +DEF_IE_ENCODE(net, qos) +{ + START_IE(qos, UNI_IE_QOS, 2); + + APP_BYTE(msg, ie->fwd); + APP_BYTE(msg, ie->bwd); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, qos) +{ + IE_START(;); + + if(ielen != 2) + goto rej; + + ie->fwd = *msg->b_rptr++; + ie->bwd = *msg->b_rptr++; + + IE_END(QOS); +} + +DEF_IE_DECODE(net, qos) +{ + IE_START(;); + + if(ielen != 2) + goto rej; + + ie->fwd = *msg->b_rptr++; + ie->bwd = *msg->b_rptr++; + + IE_END(QOS); +} + +/********************************************************************* + * + * Broadband Lower Layer Information + * + * References for this IE are: + * + * Q.2931 pp. 53...54 + * UNI4.0 p. 12 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, bhli) +{ + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_BHLI_ISO, iso), + MKT(UNI_BHLI_USER, user), + MKT(UNI_BHLI_VENDOR, vendor), + EOT() + }; + u_int i; + + if(uni_print_iehdr("bhli", &ie->h, cx)) + return; + + uni_print_tbl("type", ie->type, type_tbl, cx); + uni_print_entry(cx, "len", "%d", ie->len); + uni_print_entry(cx, "info", "("); + for(i = 0; i < ie->len; i++) + uni_printf(cx, ",0x%02x", ie->info[i]); + uni_printf(cx, ")"); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, bhli) +{ + UNUSED(cx); + + switch(ie->type) { + default: + return -1; + + case UNI_BHLI_ISO: + case UNI_BHLI_USER: + case UNI_BHLI_VENDOR: + break; + } + if(ie->len > 8) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, bhli) +{ + START_IE(bhli, UNI_IE_BHLI, 9); + + APP_BYTE(msg, 0x80 | ie->type); + APP_BUF(msg, ie->info, ie->len); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, bhli) +{ + u_char c; + + IE_START(;); + + if(ielen > 9) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + if(!(c & 0x80)) + goto rej; + ie->type = c & 0x7f; + ie->len = ielen; + (void)memcpy(ie->info, msg->b_rptr, ielen); + msg->b_rptr += ielen; + + IE_END(BHLI); +} + +/********************************************************************* + * + * Broadband bearer capabilities + * + * References for this IE are: + * + * Q.2931 pp. 51...52 + * Q.2931 Amd 1 + * UNI4.0 pp. 10...12, 106...109 + * + * UNI4.0 changed the meaning of byte 5a. Instead of 3 bit traffic type and + * 2 bit timing requirements there are now 7 bits ATM transfer capabilities. + * However the old format is still supported: it should be recognized on + * input, but never be generated on output. Mapping is left to the user of + * UNI. + * + * Amd 1 not checked XXX. + * + * The Appendix in UNI4.0 lists all the supported combinations of various + * traffic IE's. The check function implements part of it. + * + * A C X VP + * 1 CBR.1 7 . 7 7 + * 2 CBR.2 - . 4,5,6 5 (*) + * 3 CBR.3 - . 4,5,6 5 (*) + * 4 rt-VBR.1 . 19 19 19 + * 5 rt-VBR.2 . 9 1,9 9 + * 6 rt-VBR.3 . 9 1,9 9 + * 7 rt-VBR.4 . . 1,9 . (*) + * 8 rt-VBR.5 . . 1,9 . (*) + * 9 rt-VBR.6 . 9 1,9 9 (*) + * 10 nrt-VBR.1 . 11 11 11 + * 11 nrt-VBR.2 . - -,0,2,8,10 -,10 + * 12 nrt-VBR.3 . - -,0,2,8,10 -,10 + * 13 nrt-VBR.4 . - -,0,2,8,10 . (*) + * 14 nrt-VBR.5 . - -,0,2,8,10 . (*) + * 15 nrt-VBR.6 . - -,0,2,8,10 -,10(*) + * 16 ABR . 12 12 12 + * 17 UBR.1 . - -,0,2,8,10 -,10 + * 18 UBR.2 . - -,0,2,8,10 -,10 + * + * (*) compatibility + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, bearer) +{ + static const struct uni_print_tbl bclass_tbl[] = { + MKT(UNI_BEARER_A, bcob-A), + MKT(UNI_BEARER_C, bcob-C), + MKT(UNI_BEARER_X, bcob-X), + MKT(UNI_BEARER_TVP, transparent-VP), + EOT() + }; + static const struct uni_print_tbl atc_tbl[] = { + MKT(UNI_BEARER_ATC_CBR, cbr), + MKT(UNI_BEARER_ATC_CBR1, cbr1), + MKT(UNI_BEARER_ATC_VBR, vbr), + MKT(UNI_BEARER_ATC_VBR1, vbr1), + MKT(UNI_BEARER_ATC_NVBR, nvbr), + MKT(UNI_BEARER_ATC_NVBR1, nvbr1), + MKT(UNI_BEARER_ATC_ABR, abr), + + MKT(UNI_BEARER_ATCX_0, x0), + MKT(UNI_BEARER_ATCX_1, x1), + MKT(UNI_BEARER_ATCX_2, x2), + MKT(UNI_BEARER_ATCX_4, x4), + MKT(UNI_BEARER_ATCX_6, x6), + MKT(UNI_BEARER_ATCX_8, x8), + EOT() + }; + static const struct uni_print_tbl cfg_tbl[] = { + MKT(UNI_BEARER_P2P, p2p), + MKT(UNI_BEARER_MP, mp), + EOT() + }; + static const struct uni_print_tbl clip_tbl[] = { + MKT(UNI_BEARER_NOCLIP, no), + MKT(UNI_BEARER_CLIP, yes), + EOT() + }; + + if(uni_print_iehdr("bearer", &ie->h, cx)) + return; + + uni_print_tbl("class", ie->bclass, bclass_tbl, cx); + + if(ie->h.present & UNI_BEARER_ATC_P) { + uni_print_tbl("atc", ie->atc, atc_tbl, cx); + } + uni_print_tbl("clip", ie->clip, clip_tbl, cx); + uni_print_tbl("cfg", ie->cfg, cfg_tbl, cx); + + uni_print_ieend(cx); +} + +#define QTYPE(C,A) ((UNI_BEARER_##C << 8) | UNI_BEARER_ATC_##A) +#define QTYPEX(C,A) ((UNI_BEARER_##C << 8) | UNI_BEARER_ATCX_##A) +#define QTYPE0(C) ((UNI_BEARER_##C << 8) | (1 << 16)) +DEF_IE_CHECK(itu, bearer) +{ + UNUSED(cx); + + switch((ie->bclass << 8) | + ((ie->h.present & UNI_BEARER_ATC_P) == 0 + ? (1 << 16) + : ie->atc)) { + + default: + return -1; + + case QTYPE (A, CBR1): /* 1 */ + case QTYPE (X, CBR1): /* 1 */ + case QTYPE (TVP, CBR1): /* 1 */ + + case QTYPE0(A): /* 2,3 */ + case QTYPEX(X, 4): /* 2,3 */ + case QTYPE (X, CBR): /* 2,3 */ + case QTYPEX(X, 6): /* 2,3 */ + case QTYPE (TVP, CBR): /* 2,3 */ + + case QTYPE (C, VBR1): /* 4 */ + case QTYPE (X, VBR1): /* 4 */ + case QTYPE (TVP, VBR1): /* 4 */ + + case QTYPE (C, VBR): /* 5,6,9 */ + case QTYPEX(X, 1): /* 5,6,7,8,9 */ + case QTYPE (X, VBR): /* 5,6,7,8,9 */ + case QTYPE (TVP, VBR): /* 5,6,9 */ + + case QTYPE (C, NVBR1): /* 10 */ + case QTYPE (X, NVBR1): /* 10 */ + case QTYPE (TVP, NVBR1): /* 10 */ + + case QTYPE0(C): /* 11,12,13,14,15,17,18 */ + case QTYPE0(X): /* 11,12,13,14,15,17,18 */ + case QTYPEX(X, 0): /* 11,12,13,14,15,17,18 */ + case QTYPEX(X, 2): /* 11,12,13,14,15,17,18 */ + case QTYPEX(X, 8): /* 11,12,13,14,15,17,18 */ + case QTYPE (X, NVBR): /* 11,12,13,14,15,17,18 */ + case QTYPE0(TVP): /* 11,12,15,17,18 */ + case QTYPE (TVP, NVBR): /* 11,12,15,17,18 */ + + case QTYPE (C, ABR): /* 16 */ + case QTYPE (X, ABR): /* 16 */ + case QTYPE (TVP, ABR): /* 16 */ + break; + } + + switch(ie->clip) { + default: + return -1; + + case UNI_BEARER_NOCLIP: + case UNI_BEARER_CLIP: + break; + } + switch(ie->cfg) { + default: + return -1; + + case UNI_BEARER_P2P: + case UNI_BEARER_MP: + break; + } + + return 0; +} +#undef QTYPE +#undef QTYPEX +#undef QTYPE0 + +DEF_IE_ENCODE(itu, bearer) +{ + START_IE(bearer, UNI_IE_BEARER, 3); + + APP_BYTE(msg, ie->bclass | + ((ie->h.present & UNI_BEARER_ATC_P) ? 0:0x80)); + APP_OPT(msg, ie->h.present, UNI_BEARER_ATC_P, + 0x80 | ie->atc); + APP_BYTE(msg, 0x80 | (ie->clip << 5) | ie->cfg); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, bearer) +{ + u_char c; + + IE_START(;); + + if(ielen != 2 && ielen != 3) + goto rej; + + c = *msg->b_rptr++; + ielen--; + ie->bclass = c & 0x1f; + if(!(c & 0x80)) { + c = *msg->b_rptr++; + ielen--; + ie->h.present |= UNI_BEARER_ATC_P; + + switch(c & 0x7f) { + /* + * Real legal values + */ + case UNI_BEARER_ATC_CBR: + case UNI_BEARER_ATC_CBR1: + case UNI_BEARER_ATC_VBR: + case UNI_BEARER_ATC_VBR1: + case UNI_BEARER_ATC_NVBR: + case UNI_BEARER_ATC_NVBR1: + case UNI_BEARER_ATC_ABR: + break; + + /* + * Compat values + */ + case UNI_BEARER_ATCX_0: + case UNI_BEARER_ATCX_1: + case UNI_BEARER_ATCX_2: + case UNI_BEARER_ATCX_4: + case UNI_BEARER_ATCX_6: + case UNI_BEARER_ATCX_8: + break; + + default: + goto rej; + } + + if(!(c & 0x80)) + goto rej; + + ie->atc = c & 0x7f; + } + if(ielen == 0) + goto rej; + c = *msg->b_rptr++; + ielen--; + if(!(c & 0x80)) + goto rej; + ie->clip = (c >> 5) & 0x3; + ie->cfg = c & 0x3; + + IE_END(BEARER); +} + +/********************************************************************* + * + * Broadband Lower Layer Information + * + * References for this IE are: + * + * Q.2931 pp. 54...59 + * UNI4.0 pp. 12...14 + * + * UNI4.0 states, that layer 1 info is not supported. + * We allow a layer 1 protocol identifier. + * + * UNI4.0 states, that the layer information subelements are NOT position + * dependent. We allow them in any order on input, but generate always the + * definit order on output. + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, blli) +{ + static const struct uni_print_tbl l2_tbl[] = { + MKT(UNI_BLLI_L2_BASIC, basic), + MKT(UNI_BLLI_L2_Q921, Q921), + MKT(UNI_BLLI_L2_X25LL, X25-LL), + MKT(UNI_BLLI_L2_X25ML, X25-ML), + MKT(UNI_BLLI_L2_LABP, LAPB), + MKT(UNI_BLLI_L2_HDLC_ARM, HDLC-ARM), + MKT(UNI_BLLI_L2_HDLC_NRM, HDLC-NRM), + MKT(UNI_BLLI_L2_HDLC_ABM, HDLC-ABM), + MKT(UNI_BLLI_L2_LAN, LAN), + MKT(UNI_BLLI_L2_X75, X75), + MKT(UNI_BLLI_L2_Q922, Q922), + MKT(UNI_BLLI_L2_USER, user), + MKT(UNI_BLLI_L2_ISO7776, ISO7776), + EOT() + }; + static const struct uni_print_tbl l2mode_tbl[] = { + MKT(UNI_BLLI_L2NORM, normal), + MKT(UNI_BLLI_L2EXT, extended), + EOT() + }; + static const struct uni_print_tbl l3_tbl[] = { + MKT(UNI_BLLI_L3_X25, X25), + MKT(UNI_BLLI_L3_ISO8208, ISO8208), + MKT(UNI_BLLI_L3_X223, X223), + MKT(UNI_BLLI_L3_CLMP, CLMP), + MKT(UNI_BLLI_L3_T70, T70), + MKT(UNI_BLLI_L3_TR9577, TR9577), + MKT(UNI_BLLI_L3_USER, user), + MKT(UNI_BLLI_L3_H310, H310), + MKT(UNI_BLLI_L3_H321, H321), + EOT() + }; + static const struct uni_print_tbl l3mode_tbl[] = { + MKT(UNI_BLLI_L3NSEQ, normal-seq), + MKT(UNI_BLLI_L3ESEQ, extended-seq), + EOT() + }; + static const struct uni_print_tbl l3psiz_tbl[] = { + MKT(UNI_BLLI_L3_16, 16), + MKT(UNI_BLLI_L3_32, 32), + MKT(UNI_BLLI_L3_64, 64), + MKT(UNI_BLLI_L3_128, 128), + MKT(UNI_BLLI_L3_256, 256), + MKT(UNI_BLLI_L3_512, 512), + MKT(UNI_BLLI_L3_1024, 1024), + MKT(UNI_BLLI_L3_2048, 2048), + MKT(UNI_BLLI_L3_4096, 4096), + EOT() + }; + static const struct uni_print_tbl l3ttype_tbl[] = { + MKT(UNI_BLLI_L3_TTYPE_RECV, receive_only), + MKT(UNI_BLLI_L3_TTYPE_SEND, send_only), + MKT(UNI_BLLI_L3_TTYPE_BOTH, both), + EOT() + }; + static const struct uni_print_tbl l3mux_tbl[] = { + MKT(UNI_BLLI_L3_MUX_NOMUX, NOMUX), + MKT(UNI_BLLI_L3_MUX_TS, TS), + MKT(UNI_BLLI_L3_MUX_TSFEC, TSFEC), + MKT(UNI_BLLI_L3_MUX_PS, PS), + MKT(UNI_BLLI_L3_MUX_PSFEC, PSFEC), + MKT(UNI_BLLI_L3_MUX_H221, H221), + EOT() + }; + static const struct uni_print_tbl l3tcap_tbl[] = { + MKT(UNI_BLLI_L3_TCAP_NOIND, noind), + MKT(UNI_BLLI_L3_TCAP_AAL1, aal1), + MKT(UNI_BLLI_L3_TCAP_AAL5, aal5), + MKT(UNI_BLLI_L3_TCAP_AAL15, aal1&5), + EOT() + }; + + if(uni_print_iehdr("blli", &ie->h, cx)) + return; + + if(ie->h.present & UNI_BLLI_L1_P) { + uni_print_entry(cx, "l1", "%u", ie->l1); + uni_print_eol(cx); + } + if(ie->h.present & UNI_BLLI_L2_P) { + uni_print_tbl("l2", ie->l2, l2_tbl, cx); + uni_print_push_prefix("l2", cx); + cx->indent++; + if(ie->h.present & UNI_BLLI_L2_USER_P) + uni_print_entry(cx, "proto", "%u", ie->l2_user); + if(ie->h.present & UNI_BLLI_L2_Q933_P) { + uni_print_entry(cx, "q933", "%u", ie->l2_q933); + uni_print_tbl("mode", ie->l2_mode, l2mode_tbl, cx); + } + if(ie->h.present & UNI_BLLI_L2_WSIZ_P) + uni_print_entry(cx, "wsize", "%u", ie->l2_wsiz); + uni_print_pop_prefix(cx); + cx->indent--; + uni_print_eol(cx); + + } + if(ie->h.present & UNI_BLLI_L3_P) { + uni_print_tbl("l3", ie->l3, l3_tbl, cx); + uni_print_push_prefix("l3", cx); + cx->indent++; + if(ie->h.present & UNI_BLLI_L3_USER_P) + uni_print_entry(cx, "proto", "%u", ie->l3_user); + if(ie->h.present & UNI_BLLI_L3_MODE_P) + uni_print_tbl("mode", ie->l3_mode, l3mode_tbl, cx); + if(ie->h.present & UNI_BLLI_L3_PSIZ_P) + uni_print_tbl("packet-size", ie->l3_psiz, l3psiz_tbl, cx); + if(ie->h.present & UNI_BLLI_L3_WSIZ_P) + uni_print_entry(cx, "window-size", "%u", ie->l3_wsiz); + if(ie->h.present & UNI_BLLI_L3_TTYPE_P) { + uni_print_tbl("ttype", ie->l3_ttype, l3ttype_tbl, cx); + uni_print_tbl("tcap", ie->l3_tcap, l3tcap_tbl, cx); + } + if(ie->h.present & UNI_BLLI_L3_MUX_P) { + uni_print_tbl("fmux", ie->l3_fmux, l3mux_tbl, cx); + uni_print_tbl("bmux", ie->l3_bmux, l3mux_tbl, cx); + } + if(ie->h.present & UNI_BLLI_L3_IPI_P) + uni_print_entry(cx, "ipi", "0x%02x", ie->l3_ipi); + if(ie->h.present & UNI_BLLI_L3_SNAP_P) + uni_print_entry(cx, "snap", "%06x.%04x", ie->oui, ie->pid); + uni_print_pop_prefix(cx); + cx->indent--; + uni_print_eol(cx); + } + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, blli) +{ + UNUSED(cx); +/* + if(ie->h.present & UNI_BLLI_L1_P) + ; +*/ + + if(ie->h.present & UNI_BLLI_L2_P) { + static u_int mask = + UNI_BLLI_L2_Q933_P | UNI_BLLI_L2_WSIZ_P | + UNI_BLLI_L2_USER_P; + + switch(ie->l2) { + default: + return -1; + + case UNI_BLLI_L2_BASIC: + case UNI_BLLI_L2_Q921: + case UNI_BLLI_L2_LABP: + case UNI_BLLI_L2_LAN: + case UNI_BLLI_L2_X75: + if(ie->h.present & mask) + return -1; + break; + + case UNI_BLLI_L2_X25LL: + case UNI_BLLI_L2_X25ML: + case UNI_BLLI_L2_HDLC_ARM: + case UNI_BLLI_L2_HDLC_NRM: + case UNI_BLLI_L2_HDLC_ABM: + case UNI_BLLI_L2_Q922: + case UNI_BLLI_L2_ISO7776: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: + case UNI_BLLI_L2_Q933_P: + case UNI_BLLI_L2_Q933_P | UNI_BLLI_L2_WSIZ_P: + break; + } + break; + + case UNI_BLLI_L2_USER: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: /* XXX ? */ + case UNI_BLLI_L2_USER_P: + break; + } + break; + } + if(ie->h.present & UNI_BLLI_L2_Q933_P) { + if(ie->l2_q933 != 0) + return -1; + + switch(ie->l2_mode) { + default: + return -1; + + case UNI_BLLI_L2NORM: + case UNI_BLLI_L2EXT: + break; + } + } + if(ie->h.present & UNI_BLLI_L2_WSIZ_P) { + if(ie->l2_wsiz == 0 || ie->l2_wsiz > 127) + return -1; + } + if(ie->h.present & UNI_BLLI_L2_USER_P) { + if(ie->l2_user > 127) + return -1; + } + } + if(ie->h.present & UNI_BLLI_L3_P) { + static u_int mask = + UNI_BLLI_L3_MODE_P | UNI_BLLI_L3_PSIZ_P | + UNI_BLLI_L3_WSIZ_P | UNI_BLLI_L3_USER_P | + UNI_BLLI_L3_IPI_P | UNI_BLLI_L3_SNAP_P | + UNI_BLLI_L3_TTYPE_P | UNI_BLLI_L3_MUX_P; + + switch(ie->l3) { + default: + return -1; + + case UNI_BLLI_L3_X25: + case UNI_BLLI_L3_ISO8208: + case UNI_BLLI_L3_X223: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: + case UNI_BLLI_L3_MODE_P: + case UNI_BLLI_L3_MODE_P | + UNI_BLLI_L3_PSIZ_P: + case UNI_BLLI_L3_MODE_P | + UNI_BLLI_L3_PSIZ_P | + UNI_BLLI_L3_WSIZ_P: + break; + } + break; + + case UNI_BLLI_L3_CLMP: + case UNI_BLLI_L3_T70: + if(ie->h.present & mask) + return -1; + break; + + case UNI_BLLI_L3_TR9577: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: + case UNI_BLLI_L3_IPI_P: + case UNI_BLLI_L3_IPI_P | UNI_BLLI_L3_SNAP_P: + break; + } + break; + + case UNI_BLLI_L3_H310: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: + case UNI_BLLI_L3_TTYPE_P: + case UNI_BLLI_L3_TTYPE_P|UNI_BLLI_L3_MUX_P: + break; + } + break; + + case UNI_BLLI_L3_USER: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: /* XXX ? */ + case UNI_BLLI_L3_USER_P: + break; + } + break; + } + if(ie->h.present & UNI_BLLI_L3_MODE_P) { + switch(ie->l3_mode) { + default: + return -1; + + case UNI_BLLI_L3NSEQ: + case UNI_BLLI_L3ESEQ: + break; + } + } + if(ie->h.present & UNI_BLLI_L3_PSIZ_P) { + switch(ie->l3_psiz) { + default: + return -1; + + case UNI_BLLI_L3_16: + case UNI_BLLI_L3_32: + case UNI_BLLI_L3_64: + case UNI_BLLI_L3_128: + case UNI_BLLI_L3_256: + case UNI_BLLI_L3_512: + case UNI_BLLI_L3_1024: + case UNI_BLLI_L3_2048: + case UNI_BLLI_L3_4096: + break; + } + } + if(ie->h.present & UNI_BLLI_L3_WSIZ_P) { + if(ie->l3_wsiz == 0 || ie->l3_wsiz > 127) + return -1; + } + if(ie->h.present & UNI_BLLI_L3_IPI_P) { + if(ie->l3_ipi == UNI_BLLI_L3_SNAP) { + if(!(ie->h.present & UNI_BLLI_L3_SNAP_P)) + return -1; + } else { + if(ie->h.present & UNI_BLLI_L3_SNAP_P) + return -1; + } + } + if(ie->h.present & UNI_BLLI_L3_USER_P) { + if(ie->l3_user > 127) + return -1; + } + if(ie->h.present & UNI_BLLI_L3_SNAP_P) { + if(ie->oui >= (1<<24)) + return -1; + if(ie->pid >= (1<<16)) + return -1; + } + if(ie->h.present & UNI_BLLI_L3_TTYPE_P) { + switch(ie->l3_ttype) { + default: + return -1; + + case UNI_BLLI_L3_TTYPE_RECV: + case UNI_BLLI_L3_TTYPE_SEND: + case UNI_BLLI_L3_TTYPE_BOTH: + break; + } + switch(ie->l3_tcap) { + default: + return -1; + + case UNI_BLLI_L3_TCAP_NOIND: + case UNI_BLLI_L3_TCAP_AAL1: + case UNI_BLLI_L3_TCAP_AAL5: + case UNI_BLLI_L3_TCAP_AAL15: + break; + } + } + if(ie->h.present & UNI_BLLI_L3_MUX_P) { + switch(ie->l3_fmux) { + default: + return -1; + + case UNI_BLLI_L3_MUX_NOMUX: + case UNI_BLLI_L3_MUX_TS: + case UNI_BLLI_L3_MUX_TSFEC: + case UNI_BLLI_L3_MUX_PS: + case UNI_BLLI_L3_MUX_PSFEC: + case UNI_BLLI_L3_MUX_H221: + break; + } + switch(ie->l3_bmux) { + default: + return -1; + + case UNI_BLLI_L3_MUX_NOMUX: + case UNI_BLLI_L3_MUX_TS: + case UNI_BLLI_L3_MUX_TSFEC: + case UNI_BLLI_L3_MUX_PS: + case UNI_BLLI_L3_MUX_PSFEC: + case UNI_BLLI_L3_MUX_H221: + break; + } + } + } + + return 0; +} + +DEF_IE_ENCODE(itu, blli) +{ + START_IE(blli, UNI_IE_BLLI, 13); + + if (IE_ISERROR(*ie)) { + APP_BYTE(msg, 0xff); + APP_BYTE(msg, 0xff); + goto out; + } + + if(ie->h.present & UNI_BLLI_L1_P) + APP_BYTE(msg, (UNI_BLLI_L1_ID<<5)|ie->l1|0x80); + + if(ie->h.present & UNI_BLLI_L2_P) { + if(ie->h.present & UNI_BLLI_L2_Q933_P) { + APP_BYTE(msg, (UNI_BLLI_L2_ID<<5)|ie->l2); + if(ie->h.present & UNI_BLLI_L2_WSIZ_P) { + APP_BYTE(msg, (ie->l2_mode<<5)|ie->l2_q933); + APP_BYTE(msg, ie->l2_wsiz | 0x80); + } else { + APP_BYTE(msg, (ie->l2_mode<<5)|ie->l2_q933|0x80); + } + } else if(ie->h.present & UNI_BLLI_L2_USER_P) { + APP_BYTE(msg, (UNI_BLLI_L2_ID<<5)|ie->l2); + APP_BYTE(msg, ie->l2_user | 0x80); + } else { + APP_BYTE(msg, (UNI_BLLI_L2_ID << 5) | ie->l2 | 0x80); + } + } + + if(ie->h.present & UNI_BLLI_L3_P) { + if(ie->h.present & UNI_BLLI_L3_MODE_P) { + if(ie->h.present & UNI_BLLI_L3_PSIZ_P) { + if(ie->h.present & UNI_BLLI_L3_WSIZ_P) { + APP_BYTE(msg,(UNI_BLLI_L3_ID<<5)|ie->l3); + APP_BYTE(msg,(ie->l3_mode<<5)); + APP_BYTE(msg,ie->l3_psiz); + APP_BYTE(msg,ie->l3_wsiz|0x80); + } else { + APP_BYTE(msg,(UNI_BLLI_L3_ID<<5)|ie->l3); + APP_BYTE(msg,(ie->l3_mode<<5)); + APP_BYTE(msg,(ie->l3_psiz|0x80)); + } + } else { + APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3); + APP_BYTE(msg, (ie->l3_mode<<5)|0x80); + } + } else if(ie->h.present & UNI_BLLI_L3_USER_P) { + APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3); + APP_BYTE(msg,(ie->l3_user|0x80)); + } else if(ie->h.present & UNI_BLLI_L3_IPI_P) { + APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3); + APP_BYTE(msg,((ie->l3_ipi>>1) & 0x7f)); + APP_BYTE(msg,(((ie->l3_ipi&1)<<6)|0x80)); + if(ie->h.present & UNI_BLLI_L3_SNAP_P) { + APP_BYTE(msg, 0x80); + APP_BYTE(msg, (ie->oui >> 16)); + APP_BYTE(msg, (ie->oui >> 8)); + APP_BYTE(msg, (ie->oui >> 0)); + APP_BYTE(msg, (ie->pid >> 8)); + APP_BYTE(msg, (ie->pid >> 0)); + } + } else if(ie->h.present & UNI_BLLI_L3_TTYPE_P) { + if(ie->h.present & UNI_BLLI_L3_MUX_P) { + APP_BYTE(msg, ie->l3_ttype | (ie->l3_tcap << 4)); + APP_BYTE(msg, 0x80 | (ie->l3_fmux << 3) | ie->l3_bmux); + } else { + APP_BYTE(msg, 0x80 | ie->l3_ttype | (ie->l3_tcap << 4)); + } + } else { + APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3|0x80); + } + } + + out: + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, blli) +{ + u_char c; + + IE_START(;); + + if(ielen > 17) + goto rej; + + while(ielen--) { + switch(((c = *msg->b_rptr++) >> 5) & 0x3) { + default: + goto rej; + + case UNI_BLLI_L1_ID: + ie->h.present |= UNI_BLLI_L1_P; + ie->l1 = c & 0x1f; + if(!(c & 0x80)) + goto rej; + break; + + case UNI_BLLI_L2_ID: + ie->h.present |= UNI_BLLI_L2_P; + ie->l2 = c & 0x1f; + if(!(c & 0x80)) { + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + if(ie->l2 == UNI_BLLI_L2_USER) { + ie->h.present |= UNI_BLLI_L2_USER_P; + ie->l2_user = c & 0x7f; + if(!(c & 0x80)) + goto rej; + } else { + ie->h.present |= UNI_BLLI_L2_Q933_P; + ie->l2_q933 = c & 0x3; + ie->l2_mode = (c >> 5) & 0x3; + if(!(c & 0x80)) { + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->h.present |= UNI_BLLI_L2_WSIZ_P; + ie->l2_wsiz = c & 0x7f; + if(!(c & 0x80)) + goto rej; + } + } + } + break; + + case UNI_BLLI_L3_ID: + ie->h.present |= UNI_BLLI_L3_P; + ie->l3 = c & 0x1f; + if(!(c & 0x80)) { + switch(ie->l3) { + default: + case UNI_BLLI_L3_CLMP: + case UNI_BLLI_L3_T70: + goto rej; + + case UNI_BLLI_L3_X25: + case UNI_BLLI_L3_ISO8208: + case UNI_BLLI_L3_X223: + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_mode = (c >> 5) & 0x3; + ie->h.present |= UNI_BLLI_L3_MODE_P; + + if(c & 0x80) + break; + + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_psiz = c & 0xf; + ie->h.present |= UNI_BLLI_L3_PSIZ_P; + + if(c & 0x80) + break; + + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_wsiz = c & 0x7f; + ie->h.present |= UNI_BLLI_L3_WSIZ_P; + + if(!(c & 0x80)) + goto rej; + break; + + case UNI_BLLI_L3_TR9577: + if(ielen < 2) + goto rej; + ielen -= 2; + c = *msg->b_rptr++; + ie->l3_ipi = (c << 1) & 0xfe; + if(c & 0x80) + goto rej; + c = *msg->b_rptr++; + ie->l3_ipi |= c & 1; + if(!(c & 0x80)) + goto rej; + ie->h.present |= UNI_BLLI_L3_IPI_P; + + if(ie->l3_ipi != UNI_BLLI_L3_SNAP) + break; + if(ielen < 6) + goto rej; + ielen -= 6; + if(*msg->b_rptr++ != 0x80) + goto rej; + ie->h.present |= UNI_BLLI_L3_SNAP_P; + ie->oui = *msg->b_rptr++ << 16; + ie->oui |= *msg->b_rptr++ << 8; + ie->oui |= *msg->b_rptr++; + ie->pid = *msg->b_rptr++ << 8; + ie->pid |= *msg->b_rptr++; + break; + + case UNI_BLLI_L3_H310: + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_ttype = c & 0xf; + ie->l3_tcap = (c >> 4) & 0x7; + ie->h.present |= UNI_BLLI_L3_TTYPE_P; + if(c & 0x80) + break; + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_fmux = (c >> 3) & 7; + ie->l3_bmux = c & 7; + ie->h.present |= UNI_BLLI_L3_MUX_P; + if(!(c & 0x80)) + goto rej; + break; + + case UNI_BLLI_L3_USER: + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_user = c & 0x7f; + ie->h.present |= UNI_BLLI_L3_USER_P; + if(!(c & 0x80)) + goto rej; + break; + } + } + break; + } + } + + IE_END(BLLI); +} + +/********************************************************************* + * + * Broadband locking shift + * Broadband non-locking shift. + * + * References for this IE are: + * + * Q.2931 pp. 41...42 + * UNI4.0 pp. 9 + * + * Procedure not supported in UNI4.0, but IE's must be recognized. + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, lshift) +{ + if(uni_print_iehdr("locking_shift", &ie->h, cx)) + return; + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, lshift) +{ + UNUSED(cx); UNUSED(ie); + return -1; +} + +DEF_IE_ENCODE(itu, lshift) +{ + START_IE(lshift, UNI_IE_LSHIFT, 1); + APP_BYTE(msg, 0x80 | ie->set); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, lshift) +{ + u_char c; + + IE_START(;); + + if(ielen != 1) + goto rej; + + c = *msg->b_rptr++; + + if(!(c & 0x80)) + goto rej; + ie->set = c & 7; + + IE_END(LSHIFT); +} + +/***********************************************************************/ + +DEF_IE_PRINT(itu, nlshift) +{ + if(uni_print_iehdr("nonlocking_shift", &ie->h, cx)) + return; + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, nlshift) +{ + UNUSED(cx); UNUSED(ie); + return -1; +} + +DEF_IE_ENCODE(itu, nlshift) +{ + START_IE(nlshift, UNI_IE_NLSHIFT, 1); + APP_BYTE(msg, 0x80 | ie->set); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, nlshift) +{ + u_char c; + + IE_START(;); + + if(ielen != 1) + goto rej; + + c = *msg->b_rptr++; + + if(!(c & 0x80)) + goto rej; + ie->set = c & 7; + + IE_END(NLSHIFT); +} + +/********************************************************************* + * + * Broadband Sending Complete Indicator + * + * References for this IE are: + * + * Q.2931 pp. 74-75 + * + * Only ITU-T coding allowed. + */ +DEF_IE_PRINT(itu, scompl) +{ + if(uni_print_iehdr("sending_complete", &ie->h, cx)) + return; + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, scompl) +{ + UNUSED(ie); UNUSED(cx); + return 0; +} + +DEF_IE_ENCODE(itu, scompl) +{ + START_IE(scompl, UNI_IE_SCOMPL, 1); + + APP_BYTE(msg, 0x80 | 0x21); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, scompl) +{ + IE_START(;); + + if(ielen != 1) + goto rej; + + if(*msg->b_rptr++ != (0x80 | 0x21)) + goto rej; + + IE_END(SCOMPL); +} + +/********************************************************************* + * + * Broadband Repeat Indicator + * + * References for this IE are: + * + * Q.2931 p. 73 + * PNNI1.0 p. 196 + * + * Q.2931 has table 4-19. Only codepoints 0x2 and 0xa (for PNNI) supported. + * + * Only ITU-T coding allowed. + */ +DEF_IE_PRINT(itu, repeat) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_REPEAT_PRIDESC, desc), + MKT(UNI_REPEAT_STACK, stack), + EOT() + }; + + if(uni_print_iehdr("repeat", &ie->h, cx)) + return; + uni_print_tbl("type", ie->type, tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, repeat) +{ + switch(ie->type) { + + case UNI_REPEAT_PRIDESC: + break; + + case UNI_REPEAT_STACK: + if(!cx->pnni) + return -1; + break; + + default: + return -1; + } + return 0; +} + +DEF_IE_ENCODE(itu, repeat) +{ + START_IE(repeat, UNI_IE_REPEAT, 1); + + APP_BYTE(msg, 0x80 | ie->type); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, repeat) +{ + u_char c; + + IE_START(;); + + if(ielen != 1) + goto rej; + + c = *msg->b_rptr++; + if(!(c & 0x80)) + goto rej; + ie->type = c & 0xf; + + IE_END(REPEAT); +} + +/********************************************************************* + * + * Transit Network Selection + * + * References for this IE are: + * + * Q.2931 pp. 75...76 + * UNI4.0 pp. 17 + * + * According to UNI4.0 this is always National Network Id/Carried Id. + * + * ITU-T/Net coding allowed. + */ + +DEF_IE_PRINT(itu, tns) +{ + u_int i; + + if(uni_print_iehdr("tns", &ie->h, cx)) + return; + uni_print_entry(cx, "net", "%u,\"", ie->len); + uni_putc('"', cx); + for(i = 0; i < ie->len; i++) { + if(ie->net[i] < ' ') + uni_printf(cx, "^%c", ie->net[i] + '@'); + else if(ie->net[i] < '~') + uni_putc(ie->net[i], cx); + else + uni_printf(cx, "\\%03o", ie->net[i]); + } + uni_putc('"', cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, tns) +{ + u_int i; + + UNUSED(cx); + + if(ie->len == 0 || ie->len > UNI_TNS_MAXLEN) + return -1; + for(i = 0; i < ie->len; i++) + if(ie->net[i] < ' ' || ie->net[i] > '~') + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, tns) +{ + START_IE(tns, UNI_IE_TNS, ie->len + 1); + + APP_BYTE(msg, 0x80 | (0x2 << 4) | 0x1); + APP_BUF(msg, ie->net, ie->len); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, tns) +{ + IE_START(;); + + if(ielen < 2 || ielen > 5) + goto rej; + + if(*msg->b_rptr++ != (0x80 | (0x2 << 4) | 0x1)) + goto rej; + ielen--; + + ie->len = 0; + while(ielen--) + ie->net[ie->len++] = *msg->b_rptr++; + + IE_END(TNS); +} + +/********************************************************************* + * + * Restart indicator + * + * References for this IE are: + * + * Q.2931 pp. 73...74 + * UNI4.0 p. 17 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, restart) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_RESTART_CHANNEL, channel), + MKT(UNI_RESTART_PATH, path), + MKT(UNI_RESTART_ALL, all), + EOT() + }; + + if(uni_print_iehdr("restart", &ie->h, cx)) + return; + uni_print_tbl("class", ie->rclass, tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, restart) +{ + UNUSED(cx); + + switch(ie->rclass) { + default: + return -1; + + case UNI_RESTART_CHANNEL: + case UNI_RESTART_PATH: + case UNI_RESTART_ALL: + break; + } + + return 0; +} + +DEF_IE_ENCODE(itu, restart) +{ + START_IE(restart, UNI_IE_RESTART, 1); + + APP_BYTE(msg, 0x80 | ie->rclass); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, restart) +{ + u_char c; + + IE_START(;); + + if(ielen != 1) + goto rej; + + ie->rclass = (c = *msg->b_rptr++) & 0x7; + + if(!(c & 0x80)) + goto rej; + + IE_END(RESTART); +} + +/********************************************************************* + * + * User-to-user info. + * + * References for this IE are: + * + * Q.2957 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, uu) +{ + u_int i; + + if(uni_print_iehdr("uu", &ie->h, cx)) + return; + uni_print_entry(cx, "len", "%u", ie->len); + uni_print_entry(cx, "info", "("); + for(i = 0; i < ie->len; i++) + uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->uu[i]); + uni_printf(cx, ")"); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, uu) +{ + UNUSED(cx); + + if(ie->len > UNI_UU_MAXLEN) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, uu) +{ + START_IE(uu, UNI_IE_UU, ie->len); + + APP_BUF(msg, ie->uu, ie->len); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, uu) +{ + IE_START(;); + + if(ielen > UNI_UU_MAXLEN || ielen < 1) + goto rej; + + ie->len = ielen; + ielen = 0; + (void)memcpy(ie->uu, msg->b_rptr, ie->len); + msg->b_rptr += ie->len; + + IE_END(UU); +} + +/********************************************************************* + * + * Generic Identifier Transport + * + * References for this IE are: + * + * UNI4.0 pp. 26...28 + * + * UNI4.0 prescribes a fixed format for this IE. We have a flag in the + * context structur, which tells us whether the check of this IE should be + * hard or soft. Probably it should be hard for end systems and soft for + * network nodes. + * + * Only Net Coding allowed. (XXX) + */ + +DEF_IE_PRINT(net, git) +{ + static const struct uni_print_tbl std_tbl[] = { + MKT(UNI_GIT_STD_DSMCC, dsmcc), + MKT(UNI_GIT_STD_H245, H.245), + EOT() + }; + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_GIT_TYPE_SESS, sess), + MKT(UNI_GIT_TYPE_RES, res), + EOT() + }; + u_int i, j; + char buf[20]; + + if(uni_print_iehdr("git", &ie->h, cx)) + return; + + uni_print_tbl("std", ie->std, std_tbl, cx); + + uni_print_eol(cx); + uni_print_push_prefix("id", cx); + cx->indent++; + for(i = 0; i < ie->numsub; i++) { + sprintf(buf, "%u", i); + uni_print_entry(cx, buf, "("); + uni_print_tbl(NULL, ie->sub[i].type, type_tbl, cx); + for(j = 0; j < ie->sub[i].len; j++) + uni_printf(cx, ",0x%02x", ie->sub[i].val[j]); + uni_printf(cx, ")"); + uni_print_eol(cx); + } + cx->indent--; + uni_print_pop_prefix(cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, git) +{ + u_int i; + + if(cx->git_hard) { + switch(ie->std) { + case UNI_GIT_STD_DSMCC: + case UNI_GIT_STD_H245: + break; + default: + return -1; + } + if(ie->numsub != 2) + return -1; + if(ie->sub[0].type != UNI_GIT_TYPE_SESS) + return -1; + if(ie->sub[0].len > UNI_GIT_MAXSESS) + return -1; + if(ie->sub[1].type != UNI_GIT_TYPE_RES) + return -1; + if(ie->sub[1].len > UNI_GIT_MAXRES) + return -1; + } else { + if(ie->numsub > UNI_GIT_MAXSUB) + return -1; + for(i = 0; i < ie->numsub; i++) + if(ie->sub[i].len > UNI_GIT_MAXVAL) + return -1; + } + return 0; +} + +DEF_IE_ENCODE(net, git) +{ + u_int i; + + START_IE(git, UNI_IE_GIT, 1 + ie->numsub * (1 + UNI_GIT_MAXVAL)); + + APP_BYTE(msg, ie->std); + for(i = 0; i < ie->numsub; i++) { + APP_BYTE(msg, ie->sub[i].type); + APP_BYTE(msg, ie->sub[i].len); + APP_BUF(msg, ie->sub[i].val, ie->sub[i].len); + } + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, git) +{ + IE_START(;); + + if(ielen > 1 + UNI_GIT_MAXSUB * (1 + UNI_GIT_MAXVAL) || ielen < 1) + goto rej; + + ie->std = *msg->b_rptr++; + ielen--; + + ie->numsub = 0; + while(ielen > 0) { + if(ie->numsub >= UNI_GIT_MAXSUB) + goto rej; + + ie->sub[ie->numsub].type = *msg->b_rptr++; + ielen--; + + if(ielen == 0) + goto rej; + ie->sub[ie->numsub].len = *msg->b_rptr++; + ielen--; + + if(ie->sub[ie->numsub].len > UNI_GIT_MAXVAL) + goto rej; + if(ie->sub[ie->numsub].len > (u_int)ielen) + goto rej; + + (void)memcpy(ie->sub[ie->numsub].val, msg->b_rptr, ie->sub[ie->numsub].len); + ielen -= ie->sub[ie->numsub].len; + msg->b_rptr += ie->sub[ie->numsub].len; + + ie->numsub++; + } + + IE_END(GIT); +} + +/********************************************************************* + * + * Additional ABR Parameters + * ABR Setup parameters + * + * References for this IE are: + * + * UNI4.0 pp. 78...82 + * PNNI1.0 p. 195 + * + * Notes: + * Only NET coding. + */ + +static void +print_abr_rec(struct unicx *cx, struct uni_abr_rec *rec) +{ + if(rec->present & UNI_ABR_REC_NRM_P) + uni_print_entry(cx, "nrm", "%d", rec->nrm); + if(rec->present & UNI_ABR_REC_TRM_P) + uni_print_entry(cx, "trm", "%d", rec->trm); + if(rec->present & UNI_ABR_REC_CDF_P) + uni_print_entry(cx, "cdf", "%d", rec->cdf); + if(rec->present & UNI_ABR_REC_ADTF_P) + uni_print_entry(cx, "adtf", "%d", rec->adtf); +} + +DEF_IE_PRINT(net, abradd) +{ + if(uni_print_iehdr("abradd", &ie->h, cx)) + return; + + uni_print_push_prefix("fwd", cx); + print_abr_rec(cx, &ie->fwd); + uni_print_pop_prefix(cx); + + uni_print_push_prefix("bwd", cx); + print_abr_rec(cx, &ie->bwd); + uni_print_pop_prefix(cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, abradd) +{ + UNUSED(cx); + UNUSED(ie); + + return 0; +} + +static u_int +encode_abr_rec(struct uni_abr_rec *rec) +{ + u_int ret = rec->present & 0xf000; + + if(ret & UNI_ABR_REC_NRM_P) + ret |= (rec->nrm & 0x7) << 25; + if(ret & UNI_ABR_REC_TRM_P) + ret |= (rec->trm & 0x7) << 22; + if(ret & UNI_ABR_REC_CDF_P) + ret |= (rec->cdf & 0x7) << 19; + if(ret & UNI_ABR_REC_ADTF_P) + ret |= (rec->adtf & 0x3ff) << 9; + + return ret; +} + +DEF_IE_ENCODE(net, abradd) +{ + START_IE(abradd, UNI_IE_ABRADD, 10); + + APP_SUB_32BIT(msg, UNI_ABRADD_FADD_ID, encode_abr_rec(&ie->fwd)); + APP_SUB_32BIT(msg, UNI_ABRADD_BADD_ID, encode_abr_rec(&ie->bwd)); + + SET_IE_LEN(msg); + return 0; +} + +static int +decode_abr_rec(struct uni_msg *msg, struct uni_abr_rec *rec) +{ + u_int val; + + val = *msg->b_rptr++ << 24; + val |= *msg->b_rptr++ << 16; + val |= *msg->b_rptr++ << 8; + val |= *msg->b_rptr++ << 0; + + rec->present = val & 0xf000; + + rec->nrm = (val & UNI_ABR_REC_NRM_P) ? ((val >> 25) & 0x7) : 0; + rec->trm = (val & UNI_ABR_REC_TRM_P) ? ((val >> 22) & 0x7) : 0; + rec->cdf = (val & UNI_ABR_REC_CDF_P) ? ((val >> 19) & 0x7) : 0; + rec->adtf = (val & UNI_ABR_REC_ADTF_P)? ((val >> 9) & 0x3ff) : 0; + + return 0; +} + +DEF_IE_DECODE(net, abradd) +{ + IE_START(;); + + if(ielen != 10) + goto rej; + + + while(ielen--) { + switch(*msg->b_rptr++) { + + default: + goto rej; + + case UNI_ABRADD_FADD_ID: + if(decode_abr_rec(msg, &ie->fwd)) + goto rej; + ielen -= 4; + break; + + case UNI_ABRADD_BADD_ID: + if(decode_abr_rec(msg, &ie->bwd)) + goto rej; + ielen -= 4; + break; + } + } + IE_END(ABRADD); +} + +/*********************************************************************/ + +DEF_IE_PRINT(net, abrsetup) +{ + if(uni_print_iehdr("abrsetup", &ie->h, cx)) + return; + + uni_print_entry(cx, "rm_frt", "%d", ie->rmfrt); + + uni_print_push_prefix("fwd", cx); + if(ie->h.present & UNI_ABRSETUP_FICR_P) + uni_print_entry(cx, "icr", "%d", ie->ficr); + if(ie->h.present & UNI_ABRSETUP_FTBE_P) + uni_print_entry(cx, "tbe", "%d", ie->ftbe); + if(ie->h.present & UNI_ABRSETUP_FRIF_P) + uni_print_entry(cx, "rif", "%d", ie->frif); + if(ie->h.present & UNI_ABRSETUP_FRDF_P) + uni_print_entry(cx, "rdf", "%d", ie->frdf); + uni_print_pop_prefix(cx); + + uni_print_push_prefix("bwd", cx); + if(ie->h.present & UNI_ABRSETUP_BICR_P) + uni_print_entry(cx, "icr", "%d", ie->bicr); + if(ie->h.present & UNI_ABRSETUP_BTBE_P) + uni_print_entry(cx, "tbe", "%d", ie->btbe); + if(ie->h.present & UNI_ABRSETUP_BRIF_P) + uni_print_entry(cx, "rif", "%d", ie->brif); + if(ie->h.present & UNI_ABRSETUP_BRDF_P) + uni_print_entry(cx, "rdf", "%d", ie->brdf); + uni_print_pop_prefix(cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, abrsetup) +{ + if(cx->pnni) { + if(!(ie->h.present & UNI_ABRSETUP_FICR_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_BICR_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_FTBE_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_BTBE_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_FRIF_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_BRIF_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_FRDF_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_BRDF_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_RMFRT_P)) + return -1; + } + + if(!(ie->h.present & UNI_ABRSETUP_RMFRT_P)) + return -1; + + if(ie->h.present & UNI_ABRSETUP_FICR_P) + if(ie->ficr >= 1 << 24) + return -1; + if(ie->h.present & UNI_ABRSETUP_BICR_P) + if(ie->bicr >= 1 << 24) + return -1; + + if(ie->h.present & UNI_ABRSETUP_FTBE_P) + if(ie->ftbe >= 1 << 24 || ie->ftbe == 0) + return -1; + if(ie->h.present & UNI_ABRSETUP_BTBE_P) + if(ie->btbe >= 1 << 24 || ie->btbe == 0) + return -1; + + if(ie->rmfrt >= 1 << 24) + return -1; + + if(ie->h.present & UNI_ABRSETUP_FRIF_P) + if(ie->frif > 15) + return -1; + if(ie->h.present & UNI_ABRSETUP_FRDF_P) + if(ie->frdf > 15) + return -1; + if(ie->h.present & UNI_ABRSETUP_BRIF_P) + if(ie->brif > 15) + return -1; + if(ie->h.present & UNI_ABRSETUP_BRDF_P) + if(ie->brdf > 15) + return -1; + return 0; +} + +DEF_IE_ENCODE(net, abrsetup) +{ + START_IE(abrsetup, UNI_IE_ABRSETUP, 32); + + APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_FICR_P, + UNI_ABRSETUP_FICR_ID, ie->ficr); + APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_BICR_P, + UNI_ABRSETUP_BICR_ID, ie->bicr); + APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_FTBE_P, + UNI_ABRSETUP_FTBE_ID, ie->ftbe); + APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_BTBE_P, + UNI_ABRSETUP_BTBE_ID, ie->btbe); + APP_SUB_24BIT(msg, UNI_ABRSETUP_RMFRT_ID, ie->rmfrt); + APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_FRIF_P, + UNI_ABRSETUP_FRIF_ID, ie->frif); + APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_BRIF_P, + UNI_ABRSETUP_BRIF_ID, ie->brif); + APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_FRDF_P, + UNI_ABRSETUP_FRDF_ID, ie->frdf); + APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_BRDF_P, + UNI_ABRSETUP_BRDF_ID, ie->brdf); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, abrsetup) +{ + IE_START(;); + + if(ielen < 4 || ielen > 32) + goto rej; + + + while(ielen--) { + switch(*msg->b_rptr++) { + + default: + goto rej; + + + DEC_GETF3(ABRSETUP_FICR, ficr, ie->h.present); + DEC_GETF3(ABRSETUP_BICR, bicr, ie->h.present); + DEC_GETF3(ABRSETUP_FTBE, ftbe, ie->h.present); + DEC_GETF3(ABRSETUP_BTBE, btbe, ie->h.present); + DEC_GETF1(ABRSETUP_FRIF, frif, ie->h.present); + DEC_GETF1(ABRSETUP_BRIF, brif, ie->h.present); + DEC_GETF1(ABRSETUP_FRDF, frdf, ie->h.present); + DEC_GETF1(ABRSETUP_BRDF, brdf, ie->h.present); + DEC_GETF3(ABRSETUP_RMFRT, frif, ie->h.present); + } + } + IE_END(ABRSETUP); +} + +/********************************************************************* + * + * Broadband report type + * + * References for this IE are: + * + * Q.2963.1 pp. 7...8 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, report) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_REPORT_MODCONF, modconf), + MKT(UNI_REPORT_CLOCK, clock), + MKT(UNI_REPORT_EEAVAIL, eeavail), + MKT(UNI_REPORT_EEREQ, eereq), + MKT(UNI_REPORT_EECOMPL, eecompl), + EOT() + }; + + if(uni_print_iehdr("report", &ie->h, cx)) + return; + uni_print_tbl("type", ie->report, tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, report) +{ + UNUSED(cx); + + switch(ie->report) { + + default: + return -1; + + case UNI_REPORT_MODCONF: + case UNI_REPORT_CLOCK: + case UNI_REPORT_EEAVAIL: + case UNI_REPORT_EEREQ: + case UNI_REPORT_EECOMPL: + break; + } + return 0; +} + +DEF_IE_ENCODE(itu, report) +{ + START_IE(report, UNI_IE_REPORT, 1); + + APP_BYTE(msg, ie->report); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, report) +{ + IE_START(;); + if(ielen != 1) + goto rej; + + ie->report = *msg->b_rptr++; + + IE_END(REPORT); +} + +/********************************************************************* + * + * Soft PVPC/PVCC + * + * References for this IE are: + * + * PNNI1.0 pp. 201...203 + * + * Only NET coding allowed. + */ +DEF_IE_PRINT(net, calling_soft) +{ + if(uni_print_iehdr("calling_soft", &ie->h, cx)) + return; + + uni_print_entry(cx, "vpi", "%d", ie->vpi); + if(ie->h.present & UNI_CALLING_SOFT_VCI_P) + uni_print_entry(cx, "vci", "%d", ie->vci); + + uni_print_ieend(cx); +} + +DEF_IE_PRINT(net, called_soft) +{ + static const struct uni_print_tbl tab[] = { + MKT(UNI_SOFT_SEL_ANY, any), + MKT(UNI_SOFT_SEL_REQ, required), + MKT(UNI_SOFT_SEL_ASS, assigned), + EOT() + }; + + if(uni_print_iehdr("called_soft", &ie->h, cx)) + return; + + uni_print_tbl("selection", ie->sel, tab, cx); + if(ie->h.present & UNI_CALLED_SOFT_VPI_P) + uni_print_entry(cx, "vpi", "%d", ie->vpi); + if(ie->h.present & UNI_CALLED_SOFT_VCI_P) + uni_print_entry(cx, "vci", "%d", ie->vci); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, calling_soft) +{ + UNUSED(cx); + + if(ie->vpi >= 1 << 12) + return -1; + return 0; +} + +DEF_IE_CHECK(net, called_soft) +{ + UNUSED(cx); + + switch(ie->sel) { + + case UNI_SOFT_SEL_ANY: + case UNI_SOFT_SEL_REQ: + case UNI_SOFT_SEL_ASS: + break; + + default: + return -1; + } + if(ie->h.present & UNI_CALLED_SOFT_VPI_P) { + if(ie->vpi >= 1 << 12) + return -1; + } else { + if(ie->sel != UNI_SOFT_SEL_ANY) + return -1; + } + + if(ie->h.present & UNI_CALLED_SOFT_VCI_P) + if(!(ie->h.present & UNI_CALLED_SOFT_VPI_P)) + return -1; + + + return 0; +} + +DEF_IE_ENCODE(net, calling_soft) +{ + START_IE(calling_soft, UNI_IE_CALLING_SOFT, 6); + + APP_BYTE(msg, 0x81); + APP_16BIT(msg, ie->vpi); + + if(ie->h.present & UNI_CALLING_SOFT_VCI_P) { + APP_BYTE(msg, 0x82); + APP_16BIT(msg, ie->vci); + } + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_ENCODE(net, called_soft) +{ + START_IE(called_soft, UNI_IE_CALLED_SOFT, 7); + + APP_BYTE(msg, ie->sel); + + if(ie->h.present & UNI_CALLED_SOFT_VPI_P) { + APP_BYTE(msg, 0x81); + APP_16BIT(msg, ie->vpi); + } + + if(ie->h.present & UNI_CALLED_SOFT_VCI_P) { + APP_BYTE(msg, 0x82); + APP_16BIT(msg, ie->vci); + } + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, calling_soft) +{ + int vci_seen, vpi_seen; + + IE_START(;); + if(ielen < 3) + goto rej; + + vci_seen = 0; + vpi_seen = 0; + + while(ielen) { + switch(*msg->b_rptr++) { + + case 0x81: + if(!vpi_seen) { + ie->vpi = *msg->b_rptr++ << 8; + ie->vpi |= *msg->b_rptr++; + } else { + msg->b_rptr += 2; + } + ielen -= 3; + break; + + case 0x82: + if(!vci_seen) { + ie->vci = *msg->b_rptr++ << 8; + ie->vci |= *msg->b_rptr++; + } else { + msg->b_rptr += 2; + } + ie->h.present |= UNI_CALLING_SOFT_VCI_P; + ielen -= 3; + break; + + default: + goto rej; + } + } + + if(!vpi_seen) + goto rej; + + IE_END(CALLING_SOFT); +} + +DEF_IE_DECODE(net, called_soft) +{ + int vci_seen, vpi_seen; + + IE_START(;); + if(ielen < 3) + goto rej; + + vci_seen = 0; + vpi_seen = 0; + + while(ielen) { + switch(*msg->b_rptr++) { + + case 0x81: + if(!vpi_seen) { + ie->vpi = *msg->b_rptr++ << 8; + ie->vpi |= *msg->b_rptr++; + vpi_seen = 1; + } else { + msg->b_rptr += 2; + } + ielen -= 3; + ie->h.present |= UNI_CALLED_SOFT_VCI_P; + break; + + case 0x82: + if(!vci_seen) { + ie->vci = *msg->b_rptr++ << 8; + ie->vci |= *msg->b_rptr++; + vci_seen = 1; + } else { + msg->b_rptr += 2; + } + ie->h.present |= UNI_CALLED_SOFT_VCI_P; + ielen -= 3; + break; + + default: + goto rej; + } + } + + IE_END(CALLED_SOFT); +} + +/********************************************************************* + * + * Crankback + * + * References for this IE are: + * + * PNNI1.0 pp. 203...206 + * + * Only NET coding allowed. + */ + +DEF_IE_PRINT(net, crankback) +{ + u_int j; + + if(uni_print_iehdr("crankback", &ie->h, cx)) + return; + + uni_print_entry(cx, "level", "%d", ie->level); + + switch(ie->type) { + + case UNI_CRANKBACK_IF: + uni_print_entry(cx, "type", "interface"); + break; + + case UNI_CRANKBACK_NODE: + uni_print_entry(cx, "type", "node"); + uni_print_entry(cx, "node", "{%d/", ie->id.node.level); + for(j = 0; j < 21; j++) + uni_printf(cx, "%02x", ie->id.node.id[j]); + uni_printf(cx, "}"); + uni_print_eol(cx); + break; + + case UNI_CRANKBACK_LINK: + uni_print_entry(cx, "type", "link"); + uni_print_push_prefix("link", cx); + cx->indent++; + + uni_print_entry(cx, "prec", "{%d/", ie->id.link.plevel); + for(j = 0; j < 21; j++) + uni_printf(cx, "%02x", ie->id.link.pid[j]); + uni_printf(cx, "}"); + uni_print_eol(cx); + + uni_print_entry(cx, "port", "0x%04x", ie->id.link.port); + uni_print_eol(cx); + + uni_print_entry(cx, "succ", "{%d/", ie->id.link.slevel); + for(j = 0; j < 21; j++) + uni_printf(cx, "%02x", ie->id.link.sid[j]); + uni_printf(cx, "}"); + uni_print_eol(cx); + + cx->indent--; + uni_print_pop_prefix(cx); + break; + + default: + uni_print_entry(cx, "type", "0x%02x", ie->type); + break; + } + + uni_print_entry(cx, "cause", "0x%02x", ie->cause); + + if(ie->h.present & UNI_CRANKBACK_TOP_P) { + uni_print_push_prefix("topol", cx); + uni_print_entry(cx, "dir", "%d", ie->diag.top.dir); + uni_print_entry(cx, "port", "0x%04x", ie->diag.top.port); + uni_print_entry(cx, "avcr", "%u", ie->diag.top.avcr); + if(ie->h.present & UNI_CRANKBACK_TOPX_P) { + uni_print_entry(cx, "crm", "%u", ie->diag.top.crm); + uni_print_entry(cx, "vf", "%u", ie->diag.top.vf); + } + uni_print_pop_prefix(cx); + uni_print_eol(cx); + } + if(ie->h.present & UNI_CRANKBACK_QOS_P) { + uni_print_push_prefix("qos", cx); + uni_print_entry(cx, "ctd", "%savail", ie->diag.qos.ctd ? "" : "un"); + uni_print_entry(cx, "cdv", "%savail", ie->diag.qos.cdv ? "" : "un"); + uni_print_entry(cx, "clr", "%savail", ie->diag.qos.clr ? "" : "un"); + uni_print_entry(cx, "other", "%savail", ie->diag.qos.other ? "" : "un"); + uni_print_pop_prefix(cx); + uni_print_eol(cx); + } + + uni_print_eol(cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, crankback) +{ + UNUSED(cx); + + if(ie->level > 104) + return -1; + switch(ie->type) { + case UNI_CRANKBACK_IF: + break; + case UNI_CRANKBACK_NODE: + if(ie->id.node.level > 104) + return -1; + break; + + case UNI_CRANKBACK_LINK: + if(ie->id.link.plevel > 104) + return -1; + if(ie->id.link.slevel > 104) + return -1; + break; + + default: + return -1; + } + + if(ie->h.present & UNI_CRANKBACK_TOP_P) { + if(ie->h.present & UNI_CRANKBACK_QOS_P) + return -1; + + if(ie->cause != UNI_CAUSE_CRATE_NAVL) + return -1; + switch(ie->diag.top.dir) { + + case 0x00: + case 0x01: + break; + + default: + return -1; + } + } + if(ie->h.present & UNI_CRANKBACK_QOS_P) { + if(ie->cause != UNI_CAUSE_QOS_NAVL) + return -1; + } + return 0; +} + +DEF_IE_ENCODE(net, crankback) +{ + START_IE(crankback, UNI_IE_CRANKBACK, 72); + + APP_BYTE(msg, ie->level); + APP_BYTE(msg, ie->type); + + switch(ie->type) { + + case UNI_CRANKBACK_IF: + break; + + case UNI_CRANKBACK_NODE: + APP_BYTE(msg, ie->id.node.level); + APP_BUF(msg, ie->id.node.id, 21); + break; + + case UNI_CRANKBACK_LINK: + APP_BYTE(msg, ie->id.link.plevel); + APP_BUF(msg, ie->id.link.pid, 21); + APP_32BIT(msg, ie->id.link.port); + APP_BYTE(msg, ie->id.link.slevel); + APP_BUF(msg, ie->id.link.sid, 21); + break; + } + + APP_BYTE(msg, ie->cause); + + if(ie->h.present & UNI_CRANKBACK_TOP_P) { + APP_BYTE(msg, ie->diag.top.dir); + APP_32BIT(msg, ie->diag.top.port); + APP_32BIT(msg, ie->diag.top.avcr); + if(ie->h.present & UNI_CRANKBACK_TOPX_P) { + APP_32BIT(msg, ie->diag.top.crm); + APP_32BIT(msg, ie->diag.top.vf); + } + } + + if(ie->h.present & UNI_CRANKBACK_QOS_P) { + APP_BYTE(msg, (ie->diag.qos.ctd << 3) + |(ie->diag.qos.cdv << 2) + |(ie->diag.qos.clr << 1) + |(ie->diag.qos.other)); + } + SET_IE_LEN(msg); + return 0; +} + + +DEF_IE_DECODE(net, crankback) +{ + IE_START(;); + + if(ielen < 3) + goto rej; + + ie->level = *msg->b_rptr++; + ielen--; + + ie->type = *msg->b_rptr++; + ielen--; + + switch(ie->type) { + + default: + goto rej; + + case UNI_CRANKBACK_IF: + break; + + case UNI_CRANKBACK_NODE: + if(ielen < 22) + goto rej; + ie->id.node.level = *msg->b_rptr++; + (void)memcpy(ie->id.node.id, msg->b_rptr, 21); + msg->b_rptr += 21; + ielen -= 22; + break; + + case UNI_CRANKBACK_LINK: + if(ielen < 48) + goto rej; + ie->id.link.plevel = *msg->b_rptr++; + (void)memcpy(ie->id.link.pid, msg->b_rptr, 21); + msg->b_rptr += 21; + ielen -= 22; + + ie->id.link.port = *msg->b_rptr++ << 24; + ie->id.link.port |= *msg->b_rptr++ << 16; + ie->id.link.port |= *msg->b_rptr++ << 8; + ie->id.link.port |= *msg->b_rptr++ << 0; + ielen -= 4; + + ie->id.link.slevel = *msg->b_rptr++; + (void)memcpy(ie->id.link.sid, msg->b_rptr, 21); + msg->b_rptr += 21; + ielen -= 22; + + break; + } + + if(ielen < 1) + goto rej; + ie->cause = *msg->b_rptr++; + ielen--; + + if(ie->cause == UNI_CAUSE_CRATE_NAVL) { + if(ielen > 0) { + if(ielen != 9 && ielen != 17) + goto rej; + ie->diag.top.dir = *msg->b_rptr++; + ie->diag.top.port = *msg->b_rptr++ << 24; + ie->diag.top.port |= *msg->b_rptr++ << 16; + ie->diag.top.port |= *msg->b_rptr++ << 8; + ie->diag.top.port |= *msg->b_rptr++ << 0; + ie->diag.top.avcr = *msg->b_rptr++ << 24; + ie->diag.top.avcr |= *msg->b_rptr++ << 16; + ie->diag.top.avcr |= *msg->b_rptr++ << 8; + ie->diag.top.avcr |= *msg->b_rptr++ << 0; + ielen -= 9; + ie->h.present |= UNI_CRANKBACK_TOP_P; + if(ielen > 0) { + ie->diag.top.crm = *msg->b_rptr++ << 24; + ie->diag.top.crm |= *msg->b_rptr++ << 16; + ie->diag.top.crm |= *msg->b_rptr++ << 8; + ie->diag.top.crm |= *msg->b_rptr++ << 0; + ie->diag.top.vf = *msg->b_rptr++ << 24; + ie->diag.top.vf |= *msg->b_rptr++ << 16; + ie->diag.top.vf |= *msg->b_rptr++ << 8; + ie->diag.top.vf |= *msg->b_rptr++ << 0; + ie->h.present |= UNI_CRANKBACK_TOPX_P; + ielen -= 8; + } + } + } else if(ie->cause == UNI_CAUSE_QOS_NAVL) { + if(ielen > 0) { + if(ielen != 1) + goto rej; + ie->diag.qos.ctd = *msg->b_rptr >> 3; + ie->diag.qos.cdv = *msg->b_rptr >> 2; + ie->diag.qos.clr = *msg->b_rptr >> 1; + ie->diag.qos.other = *msg->b_rptr >> 0; + ie->h.present |= UNI_CRANKBACK_QOS_P; + ielen -= 1; + } + } else { + if(ielen > 0) + goto rej; + } + + IE_END(CRANKBACK); +} + +/********************************************************************* + * + * Designated transit list + * + * References for this IE are: + * + * PNNI1.0 pp. 206...208 + * + * Only NET coding allowed. + */ +DEF_IE_PRINT(net, dtl) +{ + u_int i, j; + char buf[10]; + + if(uni_print_iehdr("dtl", &ie->h, cx)) + return; + + uni_print_entry(cx, "ptr", "%d(%d)", ie->ptr, ie->ptr / UNI_DTL_LOGNP_SIZE); + uni_print_push_prefix("dtl", cx); + cx->indent++; + uni_printf(cx, "{"); + for(i = 0; i < ie->num; i++) { + sprintf(buf, "%d", i); + uni_print_entry(cx, buf, "{%d/", ie->dtl[i].node_level); + for(j = 0; j < 21; j++) + uni_printf(cx, "%02x", ie->dtl[i].node_id[j]); + uni_printf(cx, ",%04x}", ie->dtl[i].port_id); + uni_print_eol(cx); + } + cx->indent--; + uni_print_pop_prefix(cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, dtl) +{ + u_int i; + + UNUSED(cx); + + if(ie->ptr % UNI_DTL_LOGNP_SIZE != 0) + return -1; + if(ie->ptr / UNI_DTL_LOGNP_SIZE > UNI_DTL_MAXNUM) + return -1; + if(ie->num > UNI_DTL_MAXNUM) + return -1; + for(i = 0; i < ie->num; i++) + if(ie->dtl[i].node_level > 104) + return -1; + return 0; +} + +DEF_IE_ENCODE(net, dtl) +{ + u_int i; + + START_IE(dtl, UNI_IE_DTL, 2 + UNI_DTL_LOGNP_SIZE * ie->num); + + APP_16BIT(msg, ie->ptr); + + for(i = 0; i < ie->num; i++) { + APP_BYTE(msg, UNI_DTL_LOGNP); + APP_BYTE(msg, ie->dtl[i].node_level); + APP_BUF(msg, ie->dtl[i].node_id, 21); + APP_32BIT(msg, ie->dtl[i].port_id); + } + + SET_IE_LEN(msg); + return 0; +} + + +DEF_IE_DECODE(net, dtl) +{ + IE_START(;); + + if(ielen < 2) + goto rej; + + ie->ptr = *msg->b_rptr++ << 8; + ie->ptr |= *msg->b_rptr++; + ielen -= 2; + + if(ielen % UNI_DTL_LOGNP_SIZE != 0) + goto rej; + if(ielen / UNI_DTL_LOGNP_SIZE > UNI_DTL_MAXNUM) + goto rej; + + ie->num = 0; + while(ielen) { + if(*msg->b_rptr++ != UNI_DTL_LOGNP) + goto rej; + ielen--; + + ie->dtl[ie->num].node_level = *msg->b_rptr++; + ielen--; + + (void)memcpy(ie->dtl[ie->num].node_id, msg->b_rptr, 21); + msg->b_rptr += 21; + ielen -= 21; + + ie->dtl[ie->num].port_id = *msg->b_rptr++ << 24; + ie->dtl[ie->num].port_id |= *msg->b_rptr++ << 16; + ie->dtl[ie->num].port_id |= *msg->b_rptr++ << 8; + ie->dtl[ie->num].port_id |= *msg->b_rptr++ << 0; + ielen -= 4; + + ie->num++; + } + + IE_END(DTL); +} + +/********************************************************************* + * + * Leaf initiated join call identifier. + * Leaf initiated join parameters. + * Leaf initiated join sequence number. + * + * References for this IE are: + * + * UNI4.0 pp. 46...48 + * + * Only NET coding allowed. + */ + +/**********************************************************************/ + +DEF_IE_PRINT(net, lij_callid) +{ + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_LIJ_IDTYPE_ROOT, root), + EOT() + }; + + if(uni_print_iehdr("lij_callid", &ie->h, cx)) + return; + + uni_print_tbl("type", ie->type, type_tbl, cx); + uni_print_entry(cx, "id", "0x%x", ie->callid); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, lij_callid) +{ + UNUSED(cx); + + switch(ie->type) { + + case UNI_LIJ_IDTYPE_ROOT: + break; + + default: + return -1; + } + + return 0; +} + +DEF_IE_ENCODE(net, lij_callid) +{ + START_IE(lij_callid, UNI_IE_LIJ_CALLID, 5); + + APP_BYTE(msg, 0x80 | ie->type); + APP_32BIT(msg, ie->callid); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, lij_callid) +{ + IE_START(;); + + if(ielen != 5) + goto rej; + + ie->type = *msg->b_rptr++ & 0xf; + ie->callid = *msg->b_rptr++ << 24; + ie->callid |= *msg->b_rptr++ << 16; + ie->callid |= *msg->b_rptr++ << 8; + ie->callid |= *msg->b_rptr++ << 0; + + IE_END(LIJ_CALLID); +} + +/**********************************************************************/ + +DEF_IE_PRINT(net, lij_param) +{ + static const struct uni_print_tbl lscreen_tbl[] = { + MKT(UNI_LIJ_SCREEN_NETJOIN, netjoin), + EOT() + }; + + if(uni_print_iehdr("lij_param", &ie->h, cx)) + return; + uni_print_tbl("screen", ie->screen, lscreen_tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, lij_param) +{ + UNUSED(cx); + + switch(ie->screen) { + + case UNI_LIJ_SCREEN_NETJOIN: + break; + + default: + return -1; + } + + return 0; +} + +DEF_IE_ENCODE(net, lij_param) +{ + START_IE(lij_param, UNI_IE_LIJ_PARAM, 1); + + APP_BYTE(msg, 0x80 | ie->screen); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, lij_param) +{ + IE_START(;); + + if(ielen != 1) + goto rej; + + ie->screen = *msg->b_rptr++ & 0xf; + + IE_END(LIJ_PARAM); +} + +/**********************************************************************/ + +DEF_IE_PRINT(net, lij_seqno) +{ + if(uni_print_iehdr("lij_seqno", &ie->h, cx)) + return; + uni_print_entry(cx, "seqno", "0x%x", ie->seqno); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, lij_seqno) +{ + UNUSED(cx); UNUSED(ie); + + return 0; +} + +DEF_IE_ENCODE(net, lij_seqno) +{ + START_IE(lij_seqno, UNI_IE_LIJ_SEQNO, 4); + + APP_32BIT(msg, ie->seqno); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, lij_seqno) +{ + IE_START(;); + + if(ielen != 4) + goto rej; + + ie->seqno = *msg->b_rptr++ << 24; + ie->seqno |= *msg->b_rptr++ << 16; + ie->seqno |= *msg->b_rptr++ << 8; + ie->seqno |= *msg->b_rptr++ << 0; + + IE_END(LIJ_SEQNO); +} + +/********************************************************************* + * + * Connection scope + * + * References for this IE are: + * + * UNI4.0 pp. 57...58 + * + * Only NET coding allowed. + */ +DEF_IE_PRINT(net, cscope) +{ + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_CSCOPE_ORG, org), + EOT() + }; + static const struct uni_print_tbl scope_tbl[] = { + MKT(UNI_CSCOPE_ORG_LOC, local_network), + MKT(UNI_CSCOPE_ORG_LOC_P1, local_network_plus_one), + MKT(UNI_CSCOPE_ORG_LOC_P2, local_network_plus_two), + MKT(UNI_CSCOPE_ORG_SITE_M1, site_minus_one), + MKT(UNI_CSCOPE_ORG_SITE, intra_site), + MKT(UNI_CSCOPE_ORG_SITE_P1, site_plus_one), + MKT(UNI_CSCOPE_ORG_ORG_M1, organisation_minus_one), + MKT(UNI_CSCOPE_ORG_ORG, intra_organisation), + MKT(UNI_CSCOPE_ORG_ORG_P1, organisation_plus_one), + MKT(UNI_CSCOPE_ORG_COMM_M1, community_minus_one), + MKT(UNI_CSCOPE_ORG_COMM, intra_community), + MKT(UNI_CSCOPE_ORG_COMM_P1, community_plus_one), + MKT(UNI_CSCOPE_ORG_REG, regional), + MKT(UNI_CSCOPE_ORG_INTER, inter_regional), + MKT(UNI_CSCOPE_ORG_GLOBAL, global), + EOT() + }; + + if(uni_print_iehdr("cscope", &ie->h, cx)) + return; + + uni_print_tbl("type", ie->type, type_tbl, cx); + if(ie->type == UNI_CSCOPE_ORG) + uni_print_tbl("scope", (u_int)ie->scope, scope_tbl, cx); + else + uni_print_entry(cx, "scope", "0x%02x", ie->scope); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, cscope) +{ + UNUSED(cx); + + switch(ie->type) { + + default: + return -1; + + case UNI_CSCOPE_ORG: + switch(ie->scope) { + + default: + return -1; + + case UNI_CSCOPE_ORG_LOC: + case UNI_CSCOPE_ORG_LOC_P1: + case UNI_CSCOPE_ORG_LOC_P2: + case UNI_CSCOPE_ORG_SITE_M1: + case UNI_CSCOPE_ORG_SITE: + case UNI_CSCOPE_ORG_SITE_P1: + case UNI_CSCOPE_ORG_ORG_M1: + case UNI_CSCOPE_ORG_ORG: + case UNI_CSCOPE_ORG_ORG_P1: + case UNI_CSCOPE_ORG_COMM_M1: + case UNI_CSCOPE_ORG_COMM: + case UNI_CSCOPE_ORG_COMM_P1: + case UNI_CSCOPE_ORG_REG: + case UNI_CSCOPE_ORG_INTER: + case UNI_CSCOPE_ORG_GLOBAL: + break; + } + break; + } + return 0; +} + +DEF_IE_ENCODE(net, cscope) +{ + START_IE(cscope, UNI_IE_CSCOPE, 2); + + APP_BYTE(msg, ie->type | 0x80); + APP_BYTE(msg, ie->scope); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, cscope) +{ + IE_START(;); + if(ielen != 2) + goto rej; + + if((*msg->b_rptr & 0xf0) != 0x80) + goto rej; + + ie->type = *msg->b_rptr++ & 0xf; + ie->scope = *msg->b_rptr++; + + IE_END(CSCOPE); +} + +/********************************************************************* + * + * Extended Quality of Service + * + * References for this IE are: + * + * UNI4.0 pp. 70...72 + * + * Notes: + * Only NET coding. + */ +DEF_IE_PRINT(net, exqos) +{ + static const struct uni_print_tbl tab[] = { + MKT(UNI_EXQOS_USER, user), + MKT(UNI_EXQOS_NET, net), + EOT() + }; + + if(uni_print_iehdr("exqos", &ie->h, cx)) + return; + + uni_print_tbl("origin", ie->origin, tab, cx); + + uni_print_entry(cx, "acceptable", "("); + if(ie->h.present & UNI_EXQOS_FACC_P) { + if(ie->facc == UNI_EXQOS_ANY_CDV) + uni_printf(cx, "ANY"); + else + uni_printf(cx, "%d", ie->facc); + } + uni_putc(',', cx); + if(ie->h.present & UNI_EXQOS_BACC_P) { + if(ie->bacc == UNI_EXQOS_ANY_CDV) + uni_printf(cx, "ANY"); + else + uni_printf(cx, "%d", ie->bacc); + } + uni_putc(')', cx); + + uni_print_entry(cx, "cumulative", "("); + if(ie->h.present & UNI_EXQOS_FCUM_P) + uni_printf(cx, "%d", ie->fcum); + uni_putc(',', cx); + if(ie->h.present & UNI_EXQOS_BCUM_P) + uni_printf(cx, "%d", ie->bcum); + uni_putc(')', cx); + + uni_print_entry(cx, "clrid", "("); + if(ie->h.present & UNI_EXQOS_FCLR_P) { + if(ie->fclr == UNI_EXQOS_ANY_CLR) + uni_printf(cx, "ANY"); + else + uni_printf(cx, "%d", ie->fclr); + } + uni_putc(',', cx); + if(ie->h.present & UNI_EXQOS_BCLR_P) { + if(ie->bclr == UNI_EXQOS_ANY_CLR) + uni_printf(cx, "ANY"); + else + uni_printf(cx, "%d", ie->bclr); + } + uni_putc(')', cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, exqos) +{ + UNUSED(cx); + + switch(ie->origin) { + case UNI_EXQOS_USER: + case UNI_EXQOS_NET: + break; + + default: + return -1; + } + if(ie->h.present & UNI_EXQOS_FACC_P) + if(!(ie->h.present & UNI_EXQOS_FCUM_P)) + return -1; + if(ie->h.present & UNI_EXQOS_BACC_P) + if(!(ie->h.present & UNI_EXQOS_BCUM_P)) + return -1; + + if(ie->h.present & UNI_EXQOS_FACC_P) + if(ie->facc >= 1 << 24) + return -1; + if(ie->h.present & UNI_EXQOS_BACC_P) + if(ie->bacc >= 1 << 24) + return -1; + if(ie->h.present & UNI_EXQOS_FCUM_P) + if(ie->fcum >= 1 << 24) + return -1; + if(ie->h.present & UNI_EXQOS_BCUM_P) + if(ie->bcum >= 1 << 24) + return -1; + + if(ie->h.present & UNI_EXQOS_FCLR_P) + if(ie->fclr==0 || (ie->fclr>15 && ie->fclr!=UNI_EXQOS_ANY_CLR)) + return -1; + if(ie->h.present & UNI_EXQOS_BCLR_P) + if(ie->bclr==0 || (ie->bclr>15 && ie->bclr!=UNI_EXQOS_ANY_CLR)) + return -1; + return 0; +} + +DEF_IE_ENCODE(net, exqos) +{ + START_IE(exqos, UNI_IE_EXQOS, 21); + + APP_BYTE(msg, ie->origin); + + APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_FACC_P, + UNI_EXQOS_FACC_ID, ie->facc); + APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_BACC_P, + UNI_EXQOS_BACC_ID, ie->bacc); + APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_FCUM_P, + UNI_EXQOS_FCUM_ID, ie->fcum); + APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_BCUM_P, + UNI_EXQOS_BCUM_ID, ie->bcum); + + APP_OPT_BYTE(msg, ie->h.present, UNI_EXQOS_FCLR_P, + UNI_EXQOS_FCLR_ID, ie->fclr); + APP_OPT_BYTE(msg, ie->h.present, UNI_EXQOS_BCLR_P, + UNI_EXQOS_BCLR_ID, ie->bclr); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, exqos) +{ + IE_START(;); + + if(ielen < 1 || ielen > 21) + goto rej; + + ie->origin = *msg->b_rptr++; + ielen--; + + while(ielen--) { + switch(*msg->b_rptr++) { + + default: + goto rej; + + DEC_GETF3(EXQOS_FACC, facc, ie->h.present); + DEC_GETF3(EXQOS_BACC, bacc, ie->h.present); + DEC_GETF3(EXQOS_FCUM, fcum, ie->h.present); + DEC_GETF3(EXQOS_BCUM, bcum, ie->h.present); + + DEC_GETF1(EXQOS_FCLR, fclr, ie->h.present); + DEC_GETF1(EXQOS_BCLR, bclr, ie->h.present); + + } + } + IE_END(EXQOS); +} + +/************************************************************** + * + * Free form IE (for testing mainly) + */ +DEF_IE_PRINT(itu, unrec) +{ + u_int i; + + if (uni_print_iehdr("unrec", &ie->h, cx)) + return; + uni_print_entry(cx, "len", "%u", ie->len); + uni_print_entry(cx, "data", "("); + for (i = 0; i < ie->len; i++) + uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->data[i]); + uni_printf(cx, ")"); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, unrec) +{ + UNUSED(cx); + + if (ie->len > sizeof(ie->data)) + return (-1); + + return (0); +} + +DEF_IE_ENCODE(itu, unrec) +{ + START_IE2(unrec, UNI_IE_UNREC, ie->len, ie->id); + + APP_BUF(msg, ie->data, ie->len); + + SET_IE_LEN(msg); + return (0); +} + +DEF_IE_DECODE(itu, unrec) +{ + IE_START(;); + + if (ielen > sizeof(ie->data) / sizeof(ie->data[0]) || ielen < 1) + goto rej; + + ie->len = ielen; + ielen = 0; + (void)memcpy(ie->data, msg->b_rptr, ie->len); + msg->b_rptr += ie->len; + + IE_END(UNREC); +} diff --git a/sys/contrib/ngatm/netnatm/msg/uni_ie.h b/sys/contrib/ngatm/netnatm/msg/uni_ie.h new file mode 100644 index 000000000000..f24c560fb8de --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/uni_ie.h @@ -0,0 +1,57 @@ +/* This file was created automatically + * Source file: $Begemot: libunimsg/atm/msg/ie.def,v 1.3 2003/09/19 11:58:15 hbb Exp $ + * $FreeBSD$ + */ + +#ifndef _NETNATM_MSG_UNI_IE_H_ +#define _NETNATM_MSG_UNI_IE_H_ + +union uni_ieall { + struct uni_iehdr h; + struct uni_ie_cause cause; + struct uni_ie_callstate callstate; + struct uni_ie_facility facility; + struct uni_ie_notify notify; + struct uni_ie_eetd eetd; + struct uni_ie_conned conned; + struct uni_ie_connedsub connedsub; + struct uni_ie_epref epref; + struct uni_ie_epstate epstate; + struct uni_ie_aal aal; + struct uni_ie_traffic traffic; + struct uni_ie_connid connid; + struct uni_ie_qos qos; + struct uni_ie_bhli bhli; + struct uni_ie_bearer bearer; + struct uni_ie_blli blli; + struct uni_ie_lshift lshift; + struct uni_ie_nlshift nlshift; + struct uni_ie_scompl scompl; + struct uni_ie_repeat repeat; + struct uni_ie_calling calling; + struct uni_ie_callingsub callingsub; + struct uni_ie_called called; + struct uni_ie_calledsub calledsub; + struct uni_ie_tns tns; + struct uni_ie_restart restart; + struct uni_ie_uu uu; + struct uni_ie_git git; + struct uni_ie_mintraffic mintraffic; + struct uni_ie_atraffic atraffic; + struct uni_ie_abrsetup abrsetup; + struct uni_ie_report report; + struct uni_ie_called_soft called_soft; + struct uni_ie_crankback crankback; + struct uni_ie_dtl dtl; + struct uni_ie_calling_soft calling_soft; + struct uni_ie_abradd abradd; + struct uni_ie_lij_callid lij_callid; + struct uni_ie_lij_param lij_param; + struct uni_ie_lij_seqno lij_seqno; + struct uni_ie_cscope cscope; + struct uni_ie_exqos exqos; + struct uni_ie_mdcr mdcr; + struct uni_ie_unrec unrec; +}; + +#endif diff --git a/sys/contrib/ngatm/netnatm/msg/uni_ietab.h b/sys/contrib/ngatm/netnatm/msg/uni_ietab.h new file mode 100644 index 000000000000..62cba33cd91d --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/uni_ietab.h @@ -0,0 +1,958 @@ +/* This file was created automatically + * Source file: $Begemot: libunimsg/atm/msg/ie.def,v 1.3 2003/09/19 11:58:15 hbb Exp $ + * $FreeBSD$ + */ + + +static void uni_ie_print_itu_cause(struct uni_ie_cause *, struct unicx *); +static int uni_ie_check_itu_cause(struct uni_ie_cause *, struct unicx *); +static int uni_ie_encode_itu_cause(struct uni_msg *, struct uni_ie_cause *, struct unicx *); +static int uni_ie_decode_itu_cause(struct uni_ie_cause *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_cause = { + 0, + 34, + (uni_print_f)uni_ie_print_itu_cause, + (uni_check_f)uni_ie_check_itu_cause, + (uni_encode_f)uni_ie_encode_itu_cause, + (uni_decode_f)uni_ie_decode_itu_cause +}; + +static void uni_ie_print_net_cause(struct uni_ie_cause *, struct unicx *); +static int uni_ie_check_net_cause(struct uni_ie_cause *, struct unicx *); +static int uni_ie_encode_net_cause(struct uni_msg *, struct uni_ie_cause *, struct unicx *); +static int uni_ie_decode_net_cause(struct uni_ie_cause *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_cause = { + 0, + 34, + (uni_print_f)uni_ie_print_net_cause, + (uni_check_f)uni_ie_check_net_cause, + (uni_encode_f)uni_ie_encode_net_cause, + (uni_decode_f)uni_ie_decode_net_cause +}; + +static void uni_ie_print_itu_callstate(struct uni_ie_callstate *, struct unicx *); +static int uni_ie_check_itu_callstate(struct uni_ie_callstate *, struct unicx *); +static int uni_ie_encode_itu_callstate(struct uni_msg *, struct uni_ie_callstate *, struct unicx *); +static int uni_ie_decode_itu_callstate(struct uni_ie_callstate *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_callstate = { + 0, + 5, + (uni_print_f)uni_ie_print_itu_callstate, + (uni_check_f)uni_ie_check_itu_callstate, + (uni_encode_f)uni_ie_encode_itu_callstate, + (uni_decode_f)uni_ie_decode_itu_callstate +}; + +static void uni_ie_print_itu_facility(struct uni_ie_facility *, struct unicx *); +static int uni_ie_check_itu_facility(struct uni_ie_facility *, struct unicx *); +static int uni_ie_encode_itu_facility(struct uni_msg *, struct uni_ie_facility *, struct unicx *); +static int uni_ie_decode_itu_facility(struct uni_ie_facility *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_facility = { + 0, + UNI_FACILITY_MAXAPDU+1+4, + (uni_print_f)uni_ie_print_itu_facility, + (uni_check_f)uni_ie_check_itu_facility, + (uni_encode_f)uni_ie_encode_itu_facility, + (uni_decode_f)uni_ie_decode_itu_facility +}; + +static void uni_ie_print_itu_notify(struct uni_ie_notify *, struct unicx *); +static int uni_ie_check_itu_notify(struct uni_ie_notify *, struct unicx *); +static int uni_ie_encode_itu_notify(struct uni_msg *, struct uni_ie_notify *, struct unicx *); +static int uni_ie_decode_itu_notify(struct uni_ie_notify *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_notify = { + 0, + UNI_NOTIFY_MAXLEN+4, + (uni_print_f)uni_ie_print_itu_notify, + (uni_check_f)uni_ie_check_itu_notify, + (uni_encode_f)uni_ie_encode_itu_notify, + (uni_decode_f)uni_ie_decode_itu_notify +}; + +static void uni_ie_print_itu_eetd(struct uni_ie_eetd *, struct unicx *); +static int uni_ie_check_itu_eetd(struct uni_ie_eetd *, struct unicx *); +static int uni_ie_encode_itu_eetd(struct uni_msg *, struct uni_ie_eetd *, struct unicx *); +static int uni_ie_decode_itu_eetd(struct uni_ie_eetd *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_eetd = { + 0, + 11, + (uni_print_f)uni_ie_print_itu_eetd, + (uni_check_f)uni_ie_check_itu_eetd, + (uni_encode_f)uni_ie_encode_itu_eetd, + (uni_decode_f)uni_ie_decode_itu_eetd +}; + +static void uni_ie_print_net_eetd(struct uni_ie_eetd *, struct unicx *); +static int uni_ie_check_net_eetd(struct uni_ie_eetd *, struct unicx *); +static int uni_ie_encode_net_eetd(struct uni_msg *, struct uni_ie_eetd *, struct unicx *); +static int uni_ie_decode_net_eetd(struct uni_ie_eetd *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_eetd = { + 0, + 13, + (uni_print_f)uni_ie_print_net_eetd, + (uni_check_f)uni_ie_check_net_eetd, + (uni_encode_f)uni_ie_encode_net_eetd, + (uni_decode_f)uni_ie_decode_net_eetd +}; + +static void uni_ie_print_itu_conned(struct uni_ie_conned *, struct unicx *); +static int uni_ie_check_itu_conned(struct uni_ie_conned *, struct unicx *); +static int uni_ie_encode_itu_conned(struct uni_msg *, struct uni_ie_conned *, struct unicx *); +static int uni_ie_decode_itu_conned(struct uni_ie_conned *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_conned = { + 0, + 25, + (uni_print_f)uni_ie_print_itu_conned, + (uni_check_f)uni_ie_check_itu_conned, + (uni_encode_f)uni_ie_encode_itu_conned, + (uni_decode_f)uni_ie_decode_itu_conned +}; + +static void uni_ie_print_itu_connedsub(struct uni_ie_connedsub *, struct unicx *); +static int uni_ie_check_itu_connedsub(struct uni_ie_connedsub *, struct unicx *); +static int uni_ie_encode_itu_connedsub(struct uni_msg *, struct uni_ie_connedsub *, struct unicx *); +static int uni_ie_decode_itu_connedsub(struct uni_ie_connedsub *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_connedsub = { + UNIFL_ACCESS, + 25, + (uni_print_f)uni_ie_print_itu_connedsub, + (uni_check_f)uni_ie_check_itu_connedsub, + (uni_encode_f)uni_ie_encode_itu_connedsub, + (uni_decode_f)uni_ie_decode_itu_connedsub +}; + +static void uni_ie_print_itu_epref(struct uni_ie_epref *, struct unicx *); +static int uni_ie_check_itu_epref(struct uni_ie_epref *, struct unicx *); +static int uni_ie_encode_itu_epref(struct uni_msg *, struct uni_ie_epref *, struct unicx *); +static int uni_ie_decode_itu_epref(struct uni_ie_epref *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_epref = { + 0, + 7, + (uni_print_f)uni_ie_print_itu_epref, + (uni_check_f)uni_ie_check_itu_epref, + (uni_encode_f)uni_ie_encode_itu_epref, + (uni_decode_f)uni_ie_decode_itu_epref +}; + +static void uni_ie_print_itu_epstate(struct uni_ie_epstate *, struct unicx *); +static int uni_ie_check_itu_epstate(struct uni_ie_epstate *, struct unicx *); +static int uni_ie_encode_itu_epstate(struct uni_msg *, struct uni_ie_epstate *, struct unicx *); +static int uni_ie_decode_itu_epstate(struct uni_ie_epstate *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_epstate = { + 0, + 5, + (uni_print_f)uni_ie_print_itu_epstate, + (uni_check_f)uni_ie_check_itu_epstate, + (uni_encode_f)uni_ie_encode_itu_epstate, + (uni_decode_f)uni_ie_decode_itu_epstate +}; + +static void uni_ie_print_itu_aal(struct uni_ie_aal *, struct unicx *); +static int uni_ie_check_itu_aal(struct uni_ie_aal *, struct unicx *); +static int uni_ie_encode_itu_aal(struct uni_msg *, struct uni_ie_aal *, struct unicx *); +static int uni_ie_decode_itu_aal(struct uni_ie_aal *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_aal = { + UNIFL_ACCESS, + 21, + (uni_print_f)uni_ie_print_itu_aal, + (uni_check_f)uni_ie_check_itu_aal, + (uni_encode_f)uni_ie_encode_itu_aal, + (uni_decode_f)uni_ie_decode_itu_aal +}; + +static void uni_ie_print_itu_traffic(struct uni_ie_traffic *, struct unicx *); +static int uni_ie_check_itu_traffic(struct uni_ie_traffic *, struct unicx *); +static int uni_ie_encode_itu_traffic(struct uni_msg *, struct uni_ie_traffic *, struct unicx *); +static int uni_ie_decode_itu_traffic(struct uni_ie_traffic *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_traffic = { + 0, + 30, + (uni_print_f)uni_ie_print_itu_traffic, + (uni_check_f)uni_ie_check_itu_traffic, + (uni_encode_f)uni_ie_encode_itu_traffic, + (uni_decode_f)uni_ie_decode_itu_traffic +}; + +static const struct iedecl decl_net_traffic = { + UNIFL_DEFAULT, + 0, + (uni_print_f)NULL, + (uni_check_f)NULL, + (uni_encode_f)NULL, + (uni_decode_f)NULL +}; + +static void uni_ie_print_itu_connid(struct uni_ie_connid *, struct unicx *); +static int uni_ie_check_itu_connid(struct uni_ie_connid *, struct unicx *); +static int uni_ie_encode_itu_connid(struct uni_msg *, struct uni_ie_connid *, struct unicx *); +static int uni_ie_decode_itu_connid(struct uni_ie_connid *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_connid = { + 0, + 9, + (uni_print_f)uni_ie_print_itu_connid, + (uni_check_f)uni_ie_check_itu_connid, + (uni_encode_f)uni_ie_encode_itu_connid, + (uni_decode_f)uni_ie_decode_itu_connid +}; + +static void uni_ie_print_itu_qos(struct uni_ie_qos *, struct unicx *); +static int uni_ie_check_itu_qos(struct uni_ie_qos *, struct unicx *); +static int uni_ie_encode_itu_qos(struct uni_msg *, struct uni_ie_qos *, struct unicx *); +static int uni_ie_decode_itu_qos(struct uni_ie_qos *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_qos = { + 0, + 6, + (uni_print_f)uni_ie_print_itu_qos, + (uni_check_f)uni_ie_check_itu_qos, + (uni_encode_f)uni_ie_encode_itu_qos, + (uni_decode_f)uni_ie_decode_itu_qos +}; + +static void uni_ie_print_net_qos(struct uni_ie_qos *, struct unicx *); +static int uni_ie_check_net_qos(struct uni_ie_qos *, struct unicx *); +static int uni_ie_encode_net_qos(struct uni_msg *, struct uni_ie_qos *, struct unicx *); +static int uni_ie_decode_net_qos(struct uni_ie_qos *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_qos = { + 0, + 6, + (uni_print_f)uni_ie_print_net_qos, + (uni_check_f)uni_ie_check_net_qos, + (uni_encode_f)uni_ie_encode_net_qos, + (uni_decode_f)uni_ie_decode_net_qos +}; + +static void uni_ie_print_itu_bhli(struct uni_ie_bhli *, struct unicx *); +static int uni_ie_check_itu_bhli(struct uni_ie_bhli *, struct unicx *); +static int uni_ie_encode_itu_bhli(struct uni_msg *, struct uni_ie_bhli *, struct unicx *); +static int uni_ie_decode_itu_bhli(struct uni_ie_bhli *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_bhli = { + UNIFL_ACCESS, + 13, + (uni_print_f)uni_ie_print_itu_bhli, + (uni_check_f)uni_ie_check_itu_bhli, + (uni_encode_f)uni_ie_encode_itu_bhli, + (uni_decode_f)uni_ie_decode_itu_bhli +}; + +static void uni_ie_print_itu_bearer(struct uni_ie_bearer *, struct unicx *); +static int uni_ie_check_itu_bearer(struct uni_ie_bearer *, struct unicx *); +static int uni_ie_encode_itu_bearer(struct uni_msg *, struct uni_ie_bearer *, struct unicx *); +static int uni_ie_decode_itu_bearer(struct uni_ie_bearer *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_bearer = { + 0, + 7, + (uni_print_f)uni_ie_print_itu_bearer, + (uni_check_f)uni_ie_check_itu_bearer, + (uni_encode_f)uni_ie_encode_itu_bearer, + (uni_decode_f)uni_ie_decode_itu_bearer +}; + +static void uni_ie_print_itu_blli(struct uni_ie_blli *, struct unicx *); +static int uni_ie_check_itu_blli(struct uni_ie_blli *, struct unicx *); +static int uni_ie_encode_itu_blli(struct uni_msg *, struct uni_ie_blli *, struct unicx *); +static int uni_ie_decode_itu_blli(struct uni_ie_blli *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_blli = { + UNIFL_ACCESS, + 17, + (uni_print_f)uni_ie_print_itu_blli, + (uni_check_f)uni_ie_check_itu_blli, + (uni_encode_f)uni_ie_encode_itu_blli, + (uni_decode_f)uni_ie_decode_itu_blli +}; + +static void uni_ie_print_itu_lshift(struct uni_ie_lshift *, struct unicx *); +static int uni_ie_check_itu_lshift(struct uni_ie_lshift *, struct unicx *); +static int uni_ie_encode_itu_lshift(struct uni_msg *, struct uni_ie_lshift *, struct unicx *); +static int uni_ie_decode_itu_lshift(struct uni_ie_lshift *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_lshift = { + 0, + 5, + (uni_print_f)uni_ie_print_itu_lshift, + (uni_check_f)uni_ie_check_itu_lshift, + (uni_encode_f)uni_ie_encode_itu_lshift, + (uni_decode_f)uni_ie_decode_itu_lshift +}; + +static void uni_ie_print_itu_nlshift(struct uni_ie_nlshift *, struct unicx *); +static int uni_ie_check_itu_nlshift(struct uni_ie_nlshift *, struct unicx *); +static int uni_ie_encode_itu_nlshift(struct uni_msg *, struct uni_ie_nlshift *, struct unicx *); +static int uni_ie_decode_itu_nlshift(struct uni_ie_nlshift *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_nlshift = { + 0, + 5, + (uni_print_f)uni_ie_print_itu_nlshift, + (uni_check_f)uni_ie_check_itu_nlshift, + (uni_encode_f)uni_ie_encode_itu_nlshift, + (uni_decode_f)uni_ie_decode_itu_nlshift +}; + +static void uni_ie_print_itu_scompl(struct uni_ie_scompl *, struct unicx *); +static int uni_ie_check_itu_scompl(struct uni_ie_scompl *, struct unicx *); +static int uni_ie_encode_itu_scompl(struct uni_msg *, struct uni_ie_scompl *, struct unicx *); +static int uni_ie_decode_itu_scompl(struct uni_ie_scompl *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_scompl = { + 0, + 5, + (uni_print_f)uni_ie_print_itu_scompl, + (uni_check_f)uni_ie_check_itu_scompl, + (uni_encode_f)uni_ie_encode_itu_scompl, + (uni_decode_f)uni_ie_decode_itu_scompl +}; + +static void uni_ie_print_itu_repeat(struct uni_ie_repeat *, struct unicx *); +static int uni_ie_check_itu_repeat(struct uni_ie_repeat *, struct unicx *); +static int uni_ie_encode_itu_repeat(struct uni_msg *, struct uni_ie_repeat *, struct unicx *); +static int uni_ie_decode_itu_repeat(struct uni_ie_repeat *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_repeat = { + 0, + 5, + (uni_print_f)uni_ie_print_itu_repeat, + (uni_check_f)uni_ie_check_itu_repeat, + (uni_encode_f)uni_ie_encode_itu_repeat, + (uni_decode_f)uni_ie_decode_itu_repeat +}; + +static void uni_ie_print_itu_calling(struct uni_ie_calling *, struct unicx *); +static int uni_ie_check_itu_calling(struct uni_ie_calling *, struct unicx *); +static int uni_ie_encode_itu_calling(struct uni_msg *, struct uni_ie_calling *, struct unicx *); +static int uni_ie_decode_itu_calling(struct uni_ie_calling *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_calling = { + 0, + 26, + (uni_print_f)uni_ie_print_itu_calling, + (uni_check_f)uni_ie_check_itu_calling, + (uni_encode_f)uni_ie_encode_itu_calling, + (uni_decode_f)uni_ie_decode_itu_calling +}; + +static void uni_ie_print_itu_callingsub(struct uni_ie_callingsub *, struct unicx *); +static int uni_ie_check_itu_callingsub(struct uni_ie_callingsub *, struct unicx *); +static int uni_ie_encode_itu_callingsub(struct uni_msg *, struct uni_ie_callingsub *, struct unicx *); +static int uni_ie_decode_itu_callingsub(struct uni_ie_callingsub *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_callingsub = { + UNIFL_ACCESS, + 25, + (uni_print_f)uni_ie_print_itu_callingsub, + (uni_check_f)uni_ie_check_itu_callingsub, + (uni_encode_f)uni_ie_encode_itu_callingsub, + (uni_decode_f)uni_ie_decode_itu_callingsub +}; + +static void uni_ie_print_itu_called(struct uni_ie_called *, struct unicx *); +static int uni_ie_check_itu_called(struct uni_ie_called *, struct unicx *); +static int uni_ie_encode_itu_called(struct uni_msg *, struct uni_ie_called *, struct unicx *); +static int uni_ie_decode_itu_called(struct uni_ie_called *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_called = { + 0, + 25, + (uni_print_f)uni_ie_print_itu_called, + (uni_check_f)uni_ie_check_itu_called, + (uni_encode_f)uni_ie_encode_itu_called, + (uni_decode_f)uni_ie_decode_itu_called +}; + +static void uni_ie_print_itu_calledsub(struct uni_ie_calledsub *, struct unicx *); +static int uni_ie_check_itu_calledsub(struct uni_ie_calledsub *, struct unicx *); +static int uni_ie_encode_itu_calledsub(struct uni_msg *, struct uni_ie_calledsub *, struct unicx *); +static int uni_ie_decode_itu_calledsub(struct uni_ie_calledsub *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_calledsub = { + UNIFL_ACCESS, + 25, + (uni_print_f)uni_ie_print_itu_calledsub, + (uni_check_f)uni_ie_check_itu_calledsub, + (uni_encode_f)uni_ie_encode_itu_calledsub, + (uni_decode_f)uni_ie_decode_itu_calledsub +}; + +static void uni_ie_print_itu_tns(struct uni_ie_tns *, struct unicx *); +static int uni_ie_check_itu_tns(struct uni_ie_tns *, struct unicx *); +static int uni_ie_encode_itu_tns(struct uni_msg *, struct uni_ie_tns *, struct unicx *); +static int uni_ie_decode_itu_tns(struct uni_ie_tns *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_tns = { + 0, + 9, + (uni_print_f)uni_ie_print_itu_tns, + (uni_check_f)uni_ie_check_itu_tns, + (uni_encode_f)uni_ie_encode_itu_tns, + (uni_decode_f)uni_ie_decode_itu_tns +}; + +static const struct iedecl decl_net_tns = { + UNIFL_DEFAULT, + 0, + (uni_print_f)NULL, + (uni_check_f)NULL, + (uni_encode_f)NULL, + (uni_decode_f)NULL +}; + +static void uni_ie_print_itu_restart(struct uni_ie_restart *, struct unicx *); +static int uni_ie_check_itu_restart(struct uni_ie_restart *, struct unicx *); +static int uni_ie_encode_itu_restart(struct uni_msg *, struct uni_ie_restart *, struct unicx *); +static int uni_ie_decode_itu_restart(struct uni_ie_restart *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_restart = { + 0, + 5, + (uni_print_f)uni_ie_print_itu_restart, + (uni_check_f)uni_ie_check_itu_restart, + (uni_encode_f)uni_ie_encode_itu_restart, + (uni_decode_f)uni_ie_decode_itu_restart +}; + +static void uni_ie_print_itu_uu(struct uni_ie_uu *, struct unicx *); +static int uni_ie_check_itu_uu(struct uni_ie_uu *, struct unicx *); +static int uni_ie_encode_itu_uu(struct uni_msg *, struct uni_ie_uu *, struct unicx *); +static int uni_ie_decode_itu_uu(struct uni_ie_uu *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_uu = { + UNIFL_ACCESS, + UNI_UU_MAXLEN+4, + (uni_print_f)uni_ie_print_itu_uu, + (uni_check_f)uni_ie_check_itu_uu, + (uni_encode_f)uni_ie_encode_itu_uu, + (uni_decode_f)uni_ie_decode_itu_uu +}; + +static void uni_ie_print_net_git(struct uni_ie_git *, struct unicx *); +static int uni_ie_check_net_git(struct uni_ie_git *, struct unicx *); +static int uni_ie_encode_net_git(struct uni_msg *, struct uni_ie_git *, struct unicx *); +static int uni_ie_decode_net_git(struct uni_ie_git *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_git = { + 0, + 33, + (uni_print_f)uni_ie_print_net_git, + (uni_check_f)uni_ie_check_net_git, + (uni_encode_f)uni_ie_encode_net_git, + (uni_decode_f)uni_ie_decode_net_git +}; + +static void uni_ie_print_itu_mintraffic(struct uni_ie_mintraffic *, struct unicx *); +static int uni_ie_check_itu_mintraffic(struct uni_ie_mintraffic *, struct unicx *); +static int uni_ie_encode_itu_mintraffic(struct uni_msg *, struct uni_ie_mintraffic *, struct unicx *); +static int uni_ie_decode_itu_mintraffic(struct uni_ie_mintraffic *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_mintraffic = { + 0, + 20, + (uni_print_f)uni_ie_print_itu_mintraffic, + (uni_check_f)uni_ie_check_itu_mintraffic, + (uni_encode_f)uni_ie_encode_itu_mintraffic, + (uni_decode_f)uni_ie_decode_itu_mintraffic +}; + +static const struct iedecl decl_net_mintraffic = { + UNIFL_DEFAULT, + 0, + (uni_print_f)NULL, + (uni_check_f)NULL, + (uni_encode_f)NULL, + (uni_decode_f)NULL +}; + +static void uni_ie_print_itu_atraffic(struct uni_ie_atraffic *, struct unicx *); +static int uni_ie_check_itu_atraffic(struct uni_ie_atraffic *, struct unicx *); +static int uni_ie_encode_itu_atraffic(struct uni_msg *, struct uni_ie_atraffic *, struct unicx *); +static int uni_ie_decode_itu_atraffic(struct uni_ie_atraffic *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_atraffic = { + 0, + 30, + (uni_print_f)uni_ie_print_itu_atraffic, + (uni_check_f)uni_ie_check_itu_atraffic, + (uni_encode_f)uni_ie_encode_itu_atraffic, + (uni_decode_f)uni_ie_decode_itu_atraffic +}; + +static const struct iedecl decl_net_atraffic = { + UNIFL_DEFAULT, + 0, + (uni_print_f)NULL, + (uni_check_f)NULL, + (uni_encode_f)NULL, + (uni_decode_f)NULL +}; + +static void uni_ie_print_net_abrsetup(struct uni_ie_abrsetup *, struct unicx *); +static int uni_ie_check_net_abrsetup(struct uni_ie_abrsetup *, struct unicx *); +static int uni_ie_encode_net_abrsetup(struct uni_msg *, struct uni_ie_abrsetup *, struct unicx *); +static int uni_ie_decode_net_abrsetup(struct uni_ie_abrsetup *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_abrsetup = { + 0, + 36, + (uni_print_f)uni_ie_print_net_abrsetup, + (uni_check_f)uni_ie_check_net_abrsetup, + (uni_encode_f)uni_ie_encode_net_abrsetup, + (uni_decode_f)uni_ie_decode_net_abrsetup +}; + +static void uni_ie_print_itu_report(struct uni_ie_report *, struct unicx *); +static int uni_ie_check_itu_report(struct uni_ie_report *, struct unicx *); +static int uni_ie_encode_itu_report(struct uni_msg *, struct uni_ie_report *, struct unicx *); +static int uni_ie_decode_itu_report(struct uni_ie_report *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_report = { + 0, + 5, + (uni_print_f)uni_ie_print_itu_report, + (uni_check_f)uni_ie_check_itu_report, + (uni_encode_f)uni_ie_encode_itu_report, + (uni_decode_f)uni_ie_decode_itu_report +}; + +static void uni_ie_print_net_called_soft(struct uni_ie_called_soft *, struct unicx *); +static int uni_ie_check_net_called_soft(struct uni_ie_called_soft *, struct unicx *); +static int uni_ie_encode_net_called_soft(struct uni_msg *, struct uni_ie_called_soft *, struct unicx *); +static int uni_ie_decode_net_called_soft(struct uni_ie_called_soft *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_called_soft = { + 0, + 11, + (uni_print_f)uni_ie_print_net_called_soft, + (uni_check_f)uni_ie_check_net_called_soft, + (uni_encode_f)uni_ie_encode_net_called_soft, + (uni_decode_f)uni_ie_decode_net_called_soft +}; + +static void uni_ie_print_net_crankback(struct uni_ie_crankback *, struct unicx *); +static int uni_ie_check_net_crankback(struct uni_ie_crankback *, struct unicx *); +static int uni_ie_encode_net_crankback(struct uni_msg *, struct uni_ie_crankback *, struct unicx *); +static int uni_ie_decode_net_crankback(struct uni_ie_crankback *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_crankback = { + 0, + 72, + (uni_print_f)uni_ie_print_net_crankback, + (uni_check_f)uni_ie_check_net_crankback, + (uni_encode_f)uni_ie_encode_net_crankback, + (uni_decode_f)uni_ie_decode_net_crankback +}; + +static void uni_ie_print_net_dtl(struct uni_ie_dtl *, struct unicx *); +static int uni_ie_check_net_dtl(struct uni_ie_dtl *, struct unicx *); +static int uni_ie_encode_net_dtl(struct uni_msg *, struct uni_ie_dtl *, struct unicx *); +static int uni_ie_decode_net_dtl(struct uni_ie_dtl *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_dtl = { + 0, + UNI_DTL_LOGNP_SIZE*UNI_DTL_MAXNUM+6, + (uni_print_f)uni_ie_print_net_dtl, + (uni_check_f)uni_ie_check_net_dtl, + (uni_encode_f)uni_ie_encode_net_dtl, + (uni_decode_f)uni_ie_decode_net_dtl +}; + +static void uni_ie_print_net_calling_soft(struct uni_ie_calling_soft *, struct unicx *); +static int uni_ie_check_net_calling_soft(struct uni_ie_calling_soft *, struct unicx *); +static int uni_ie_encode_net_calling_soft(struct uni_msg *, struct uni_ie_calling_soft *, struct unicx *); +static int uni_ie_decode_net_calling_soft(struct uni_ie_calling_soft *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_calling_soft = { + 0, + 10, + (uni_print_f)uni_ie_print_net_calling_soft, + (uni_check_f)uni_ie_check_net_calling_soft, + (uni_encode_f)uni_ie_encode_net_calling_soft, + (uni_decode_f)uni_ie_decode_net_calling_soft +}; + +static void uni_ie_print_net_abradd(struct uni_ie_abradd *, struct unicx *); +static int uni_ie_check_net_abradd(struct uni_ie_abradd *, struct unicx *); +static int uni_ie_encode_net_abradd(struct uni_msg *, struct uni_ie_abradd *, struct unicx *); +static int uni_ie_decode_net_abradd(struct uni_ie_abradd *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_abradd = { + 0, + 14, + (uni_print_f)uni_ie_print_net_abradd, + (uni_check_f)uni_ie_check_net_abradd, + (uni_encode_f)uni_ie_encode_net_abradd, + (uni_decode_f)uni_ie_decode_net_abradd +}; + +static void uni_ie_print_net_lij_callid(struct uni_ie_lij_callid *, struct unicx *); +static int uni_ie_check_net_lij_callid(struct uni_ie_lij_callid *, struct unicx *); +static int uni_ie_encode_net_lij_callid(struct uni_msg *, struct uni_ie_lij_callid *, struct unicx *); +static int uni_ie_decode_net_lij_callid(struct uni_ie_lij_callid *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_lij_callid = { + 0, + 9, + (uni_print_f)uni_ie_print_net_lij_callid, + (uni_check_f)uni_ie_check_net_lij_callid, + (uni_encode_f)uni_ie_encode_net_lij_callid, + (uni_decode_f)uni_ie_decode_net_lij_callid +}; + +static void uni_ie_print_net_lij_param(struct uni_ie_lij_param *, struct unicx *); +static int uni_ie_check_net_lij_param(struct uni_ie_lij_param *, struct unicx *); +static int uni_ie_encode_net_lij_param(struct uni_msg *, struct uni_ie_lij_param *, struct unicx *); +static int uni_ie_decode_net_lij_param(struct uni_ie_lij_param *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_lij_param = { + 0, + 5, + (uni_print_f)uni_ie_print_net_lij_param, + (uni_check_f)uni_ie_check_net_lij_param, + (uni_encode_f)uni_ie_encode_net_lij_param, + (uni_decode_f)uni_ie_decode_net_lij_param +}; + +static void uni_ie_print_net_lij_seqno(struct uni_ie_lij_seqno *, struct unicx *); +static int uni_ie_check_net_lij_seqno(struct uni_ie_lij_seqno *, struct unicx *); +static int uni_ie_encode_net_lij_seqno(struct uni_msg *, struct uni_ie_lij_seqno *, struct unicx *); +static int uni_ie_decode_net_lij_seqno(struct uni_ie_lij_seqno *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_lij_seqno = { + 0, + 8, + (uni_print_f)uni_ie_print_net_lij_seqno, + (uni_check_f)uni_ie_check_net_lij_seqno, + (uni_encode_f)uni_ie_encode_net_lij_seqno, + (uni_decode_f)uni_ie_decode_net_lij_seqno +}; + +static void uni_ie_print_net_cscope(struct uni_ie_cscope *, struct unicx *); +static int uni_ie_check_net_cscope(struct uni_ie_cscope *, struct unicx *); +static int uni_ie_encode_net_cscope(struct uni_msg *, struct uni_ie_cscope *, struct unicx *); +static int uni_ie_decode_net_cscope(struct uni_ie_cscope *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_cscope = { + 0, + 6, + (uni_print_f)uni_ie_print_net_cscope, + (uni_check_f)uni_ie_check_net_cscope, + (uni_encode_f)uni_ie_encode_net_cscope, + (uni_decode_f)uni_ie_decode_net_cscope +}; + +static void uni_ie_print_net_exqos(struct uni_ie_exqos *, struct unicx *); +static int uni_ie_check_net_exqos(struct uni_ie_exqos *, struct unicx *); +static int uni_ie_encode_net_exqos(struct uni_msg *, struct uni_ie_exqos *, struct unicx *); +static int uni_ie_decode_net_exqos(struct uni_ie_exqos *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_exqos = { + 0, + 25, + (uni_print_f)uni_ie_print_net_exqos, + (uni_check_f)uni_ie_check_net_exqos, + (uni_encode_f)uni_ie_encode_net_exqos, + (uni_decode_f)uni_ie_decode_net_exqos +}; + +static void uni_ie_print_net_mdcr(struct uni_ie_mdcr *, struct unicx *); +static int uni_ie_check_net_mdcr(struct uni_ie_mdcr *, struct unicx *); +static int uni_ie_encode_net_mdcr(struct uni_msg *, struct uni_ie_mdcr *, struct unicx *); +static int uni_ie_decode_net_mdcr(struct uni_ie_mdcr *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_net_mdcr = { + 0, + 13, + (uni_print_f)uni_ie_print_net_mdcr, + (uni_check_f)uni_ie_check_net_mdcr, + (uni_encode_f)uni_ie_encode_net_mdcr, + (uni_decode_f)uni_ie_decode_net_mdcr +}; + +static void uni_ie_print_itu_unrec(struct uni_ie_unrec *, struct unicx *); +static int uni_ie_check_itu_unrec(struct uni_ie_unrec *, struct unicx *); +static int uni_ie_encode_itu_unrec(struct uni_msg *, struct uni_ie_unrec *, struct unicx *); +static int uni_ie_decode_itu_unrec(struct uni_ie_unrec *, struct uni_msg *, u_int, struct unicx *); + +static struct iedecl decl_itu_unrec = { + 0, + 128, + (uni_print_f)uni_ie_print_itu_unrec, + (uni_check_f)uni_ie_check_itu_unrec, + (uni_encode_f)uni_ie_encode_itu_unrec, + (uni_decode_f)uni_ie_decode_itu_unrec +}; + +const struct iedecl *uni_ietable[256][4] = { + { NULL, NULL, NULL, NULL, }, /* 0x00 */ + { NULL, NULL, NULL, NULL, }, /* 0x01 */ + { NULL, NULL, NULL, NULL, }, /* 0x02 */ + { NULL, NULL, NULL, NULL, }, /* 0x03 */ + { NULL, NULL, NULL, NULL, }, /* 0x04 */ + { NULL, NULL, NULL, NULL, }, /* 0x05 */ + { NULL, NULL, NULL, NULL, }, /* 0x06 */ + { NULL, NULL, NULL, NULL, }, /* 0x07 */ + { &decl_itu_cause, NULL, NULL, &decl_net_cause, }, /* 0x08 */ + { NULL, NULL, NULL, NULL, }, /* 0x09 */ + { NULL, NULL, NULL, NULL, }, /* 0x0a */ + { NULL, NULL, NULL, NULL, }, /* 0x0b */ + { NULL, NULL, NULL, NULL, }, /* 0x0c */ + { NULL, NULL, NULL, NULL, }, /* 0x0d */ + { NULL, NULL, NULL, NULL, }, /* 0x0e */ + { NULL, NULL, NULL, NULL, }, /* 0x0f */ + { NULL, NULL, NULL, NULL, }, /* 0x10 */ + { NULL, NULL, NULL, NULL, }, /* 0x11 */ + { NULL, NULL, NULL, NULL, }, /* 0x12 */ + { NULL, NULL, NULL, NULL, }, /* 0x13 */ + { &decl_itu_callstate, NULL, NULL, NULL, }, /* 0x14 */ + { NULL, NULL, NULL, NULL, }, /* 0x15 */ + { NULL, NULL, NULL, NULL, }, /* 0x16 */ + { NULL, NULL, NULL, NULL, }, /* 0x17 */ + { NULL, NULL, NULL, NULL, }, /* 0x18 */ + { NULL, NULL, NULL, NULL, }, /* 0x19 */ + { NULL, NULL, NULL, NULL, }, /* 0x1a */ + { NULL, NULL, NULL, NULL, }, /* 0x1b */ + { &decl_itu_facility, NULL, NULL, NULL, }, /* 0x1c */ + { NULL, NULL, NULL, NULL, }, /* 0x1d */ + { NULL, NULL, NULL, NULL, }, /* 0x1e */ + { NULL, NULL, NULL, NULL, }, /* 0x1f */ + { NULL, NULL, NULL, NULL, }, /* 0x20 */ + { NULL, NULL, NULL, NULL, }, /* 0x21 */ + { NULL, NULL, NULL, NULL, }, /* 0x22 */ + { NULL, NULL, NULL, NULL, }, /* 0x23 */ + { NULL, NULL, NULL, NULL, }, /* 0x24 */ + { NULL, NULL, NULL, NULL, }, /* 0x25 */ + { NULL, NULL, NULL, NULL, }, /* 0x26 */ + { &decl_itu_notify, NULL, NULL, NULL, }, /* 0x27 */ + { NULL, NULL, NULL, NULL, }, /* 0x28 */ + { NULL, NULL, NULL, NULL, }, /* 0x29 */ + { NULL, NULL, NULL, NULL, }, /* 0x2a */ + { NULL, NULL, NULL, NULL, }, /* 0x2b */ + { NULL, NULL, NULL, NULL, }, /* 0x2c */ + { NULL, NULL, NULL, NULL, }, /* 0x2d */ + { NULL, NULL, NULL, NULL, }, /* 0x2e */ + { NULL, NULL, NULL, NULL, }, /* 0x2f */ + { NULL, NULL, NULL, NULL, }, /* 0x30 */ + { NULL, NULL, NULL, NULL, }, /* 0x31 */ + { NULL, NULL, NULL, NULL, }, /* 0x32 */ + { NULL, NULL, NULL, NULL, }, /* 0x33 */ + { NULL, NULL, NULL, NULL, }, /* 0x34 */ + { NULL, NULL, NULL, NULL, }, /* 0x35 */ + { NULL, NULL, NULL, NULL, }, /* 0x36 */ + { NULL, NULL, NULL, NULL, }, /* 0x37 */ + { NULL, NULL, NULL, NULL, }, /* 0x38 */ + { NULL, NULL, NULL, NULL, }, /* 0x39 */ + { NULL, NULL, NULL, NULL, }, /* 0x3a */ + { NULL, NULL, NULL, NULL, }, /* 0x3b */ + { NULL, NULL, NULL, NULL, }, /* 0x3c */ + { NULL, NULL, NULL, NULL, }, /* 0x3d */ + { NULL, NULL, NULL, NULL, }, /* 0x3e */ + { NULL, NULL, NULL, NULL, }, /* 0x3f */ + { NULL, NULL, NULL, NULL, }, /* 0x40 */ + { NULL, NULL, NULL, NULL, }, /* 0x41 */ + { &decl_itu_eetd, NULL, NULL, &decl_net_eetd, }, /* 0x42 */ + { NULL, NULL, NULL, NULL, }, /* 0x43 */ + { NULL, NULL, NULL, NULL, }, /* 0x44 */ + { NULL, NULL, NULL, NULL, }, /* 0x45 */ + { NULL, NULL, NULL, NULL, }, /* 0x46 */ + { NULL, NULL, NULL, NULL, }, /* 0x47 */ + { NULL, NULL, NULL, NULL, }, /* 0x48 */ + { NULL, NULL, NULL, NULL, }, /* 0x49 */ + { NULL, NULL, NULL, NULL, }, /* 0x4a */ + { NULL, NULL, NULL, NULL, }, /* 0x4b */ + { &decl_itu_conned, NULL, NULL, NULL, }, /* 0x4c */ + { &decl_itu_connedsub, NULL, NULL, NULL, }, /* 0x4d */ + { NULL, NULL, NULL, NULL, }, /* 0x4e */ + { NULL, NULL, NULL, NULL, }, /* 0x4f */ + { NULL, NULL, NULL, NULL, }, /* 0x50 */ + { NULL, NULL, NULL, NULL, }, /* 0x51 */ + { NULL, NULL, NULL, NULL, }, /* 0x52 */ + { NULL, NULL, NULL, NULL, }, /* 0x53 */ + { &decl_itu_epref, NULL, NULL, NULL, }, /* 0x54 */ + { &decl_itu_epstate, NULL, NULL, NULL, }, /* 0x55 */ + { NULL, NULL, NULL, NULL, }, /* 0x56 */ + { NULL, NULL, NULL, NULL, }, /* 0x57 */ + { &decl_itu_aal, NULL, NULL, NULL, }, /* 0x58 */ + { &decl_itu_traffic, NULL, NULL, &decl_net_traffic, }, /* 0x59 */ + { &decl_itu_connid, NULL, NULL, NULL, }, /* 0x5a */ + { NULL, NULL, NULL, NULL, }, /* 0x5b */ + { &decl_itu_qos, NULL, NULL, &decl_net_qos, }, /* 0x5c */ + { &decl_itu_bhli, NULL, NULL, NULL, }, /* 0x5d */ + { &decl_itu_bearer, NULL, NULL, NULL, }, /* 0x5e */ + { &decl_itu_blli, NULL, NULL, NULL, }, /* 0x5f */ + { &decl_itu_lshift, NULL, NULL, NULL, }, /* 0x60 */ + { &decl_itu_nlshift, NULL, NULL, NULL, }, /* 0x61 */ + { &decl_itu_scompl, NULL, NULL, NULL, }, /* 0x62 */ + { &decl_itu_repeat, NULL, NULL, NULL, }, /* 0x63 */ + { NULL, NULL, NULL, NULL, }, /* 0x64 */ + { NULL, NULL, NULL, NULL, }, /* 0x65 */ + { NULL, NULL, NULL, NULL, }, /* 0x66 */ + { NULL, NULL, NULL, NULL, }, /* 0x67 */ + { NULL, NULL, NULL, NULL, }, /* 0x68 */ + { NULL, NULL, NULL, NULL, }, /* 0x69 */ + { NULL, NULL, NULL, NULL, }, /* 0x6a */ + { NULL, NULL, NULL, NULL, }, /* 0x6b */ + { &decl_itu_calling, NULL, NULL, NULL, }, /* 0x6c */ + { &decl_itu_callingsub, NULL, NULL, NULL, }, /* 0x6d */ + { NULL, NULL, NULL, NULL, }, /* 0x6e */ + { NULL, NULL, NULL, NULL, }, /* 0x6f */ + { &decl_itu_called, NULL, NULL, NULL, }, /* 0x70 */ + { &decl_itu_calledsub, NULL, NULL, NULL, }, /* 0x71 */ + { NULL, NULL, NULL, NULL, }, /* 0x72 */ + { NULL, NULL, NULL, NULL, }, /* 0x73 */ + { NULL, NULL, NULL, NULL, }, /* 0x74 */ + { NULL, NULL, NULL, NULL, }, /* 0x75 */ + { NULL, NULL, NULL, NULL, }, /* 0x76 */ + { NULL, NULL, NULL, NULL, }, /* 0x77 */ + { &decl_itu_tns, NULL, NULL, &decl_net_tns, }, /* 0x78 */ + { &decl_itu_restart, NULL, NULL, NULL, }, /* 0x79 */ + { NULL, NULL, NULL, NULL, }, /* 0x7a */ + { NULL, NULL, NULL, NULL, }, /* 0x7b */ + { NULL, NULL, NULL, NULL, }, /* 0x7c */ + { NULL, NULL, NULL, NULL, }, /* 0x7d */ + { &decl_itu_uu, NULL, NULL, NULL, }, /* 0x7e */ + { NULL, NULL, NULL, &decl_net_git, }, /* 0x7f */ + { NULL, NULL, NULL, NULL, }, /* 0x80 */ + { &decl_itu_mintraffic, NULL, NULL, &decl_net_mintraffic, }, /* 0x81 */ + { &decl_itu_atraffic, NULL, NULL, &decl_net_atraffic, }, /* 0x82 */ + { NULL, NULL, NULL, NULL, }, /* 0x83 */ + { NULL, NULL, NULL, &decl_net_abrsetup, }, /* 0x84 */ + { NULL, NULL, NULL, NULL, }, /* 0x85 */ + { NULL, NULL, NULL, NULL, }, /* 0x86 */ + { NULL, NULL, NULL, NULL, }, /* 0x87 */ + { NULL, NULL, NULL, NULL, }, /* 0x88 */ + { &decl_itu_report, NULL, NULL, NULL, }, /* 0x89 */ + { NULL, NULL, NULL, NULL, }, /* 0x8a */ + { NULL, NULL, NULL, NULL, }, /* 0x8b */ + { NULL, NULL, NULL, NULL, }, /* 0x8c */ + { NULL, NULL, NULL, NULL, }, /* 0x8d */ + { NULL, NULL, NULL, NULL, }, /* 0x8e */ + { NULL, NULL, NULL, NULL, }, /* 0x8f */ + { NULL, NULL, NULL, NULL, }, /* 0x90 */ + { NULL, NULL, NULL, NULL, }, /* 0x91 */ + { NULL, NULL, NULL, NULL, }, /* 0x92 */ + { NULL, NULL, NULL, NULL, }, /* 0x93 */ + { NULL, NULL, NULL, NULL, }, /* 0x94 */ + { NULL, NULL, NULL, NULL, }, /* 0x95 */ + { NULL, NULL, NULL, NULL, }, /* 0x96 */ + { NULL, NULL, NULL, NULL, }, /* 0x97 */ + { NULL, NULL, NULL, NULL, }, /* 0x98 */ + { NULL, NULL, NULL, NULL, }, /* 0x99 */ + { NULL, NULL, NULL, NULL, }, /* 0x9a */ + { NULL, NULL, NULL, NULL, }, /* 0x9b */ + { NULL, NULL, NULL, NULL, }, /* 0x9c */ + { NULL, NULL, NULL, NULL, }, /* 0x9d */ + { NULL, NULL, NULL, NULL, }, /* 0x9e */ + { NULL, NULL, NULL, NULL, }, /* 0x9f */ + { NULL, NULL, NULL, NULL, }, /* 0xa0 */ + { NULL, NULL, NULL, NULL, }, /* 0xa1 */ + { NULL, NULL, NULL, NULL, }, /* 0xa2 */ + { NULL, NULL, NULL, NULL, }, /* 0xa3 */ + { NULL, NULL, NULL, NULL, }, /* 0xa4 */ + { NULL, NULL, NULL, NULL, }, /* 0xa5 */ + { NULL, NULL, NULL, NULL, }, /* 0xa6 */ + { NULL, NULL, NULL, NULL, }, /* 0xa7 */ + { NULL, NULL, NULL, NULL, }, /* 0xa8 */ + { NULL, NULL, NULL, NULL, }, /* 0xa9 */ + { NULL, NULL, NULL, NULL, }, /* 0xaa */ + { NULL, NULL, NULL, NULL, }, /* 0xab */ + { NULL, NULL, NULL, NULL, }, /* 0xac */ + { NULL, NULL, NULL, NULL, }, /* 0xad */ + { NULL, NULL, NULL, NULL, }, /* 0xae */ + { NULL, NULL, NULL, NULL, }, /* 0xaf */ + { NULL, NULL, NULL, NULL, }, /* 0xb0 */ + { NULL, NULL, NULL, NULL, }, /* 0xb1 */ + { NULL, NULL, NULL, NULL, }, /* 0xb2 */ + { NULL, NULL, NULL, NULL, }, /* 0xb3 */ + { NULL, NULL, NULL, NULL, }, /* 0xb4 */ + { NULL, NULL, NULL, NULL, }, /* 0xb5 */ + { NULL, NULL, NULL, NULL, }, /* 0xb6 */ + { NULL, NULL, NULL, NULL, }, /* 0xb7 */ + { NULL, NULL, NULL, NULL, }, /* 0xb8 */ + { NULL, NULL, NULL, NULL, }, /* 0xb9 */ + { NULL, NULL, NULL, NULL, }, /* 0xba */ + { NULL, NULL, NULL, NULL, }, /* 0xbb */ + { NULL, NULL, NULL, NULL, }, /* 0xbc */ + { NULL, NULL, NULL, NULL, }, /* 0xbd */ + { NULL, NULL, NULL, NULL, }, /* 0xbe */ + { NULL, NULL, NULL, NULL, }, /* 0xbf */ + { NULL, NULL, NULL, NULL, }, /* 0xc0 */ + { NULL, NULL, NULL, NULL, }, /* 0xc1 */ + { NULL, NULL, NULL, NULL, }, /* 0xc2 */ + { NULL, NULL, NULL, NULL, }, /* 0xc3 */ + { NULL, NULL, NULL, NULL, }, /* 0xc4 */ + { NULL, NULL, NULL, NULL, }, /* 0xc5 */ + { NULL, NULL, NULL, NULL, }, /* 0xc6 */ + { NULL, NULL, NULL, NULL, }, /* 0xc7 */ + { NULL, NULL, NULL, NULL, }, /* 0xc8 */ + { NULL, NULL, NULL, NULL, }, /* 0xc9 */ + { NULL, NULL, NULL, NULL, }, /* 0xca */ + { NULL, NULL, NULL, NULL, }, /* 0xcb */ + { NULL, NULL, NULL, NULL, }, /* 0xcc */ + { NULL, NULL, NULL, NULL, }, /* 0xcd */ + { NULL, NULL, NULL, NULL, }, /* 0xce */ + { NULL, NULL, NULL, NULL, }, /* 0xcf */ + { NULL, NULL, NULL, NULL, }, /* 0xd0 */ + { NULL, NULL, NULL, NULL, }, /* 0xd1 */ + { NULL, NULL, NULL, NULL, }, /* 0xd2 */ + { NULL, NULL, NULL, NULL, }, /* 0xd3 */ + { NULL, NULL, NULL, NULL, }, /* 0xd4 */ + { NULL, NULL, NULL, NULL, }, /* 0xd5 */ + { NULL, NULL, NULL, NULL, }, /* 0xd6 */ + { NULL, NULL, NULL, NULL, }, /* 0xd7 */ + { NULL, NULL, NULL, NULL, }, /* 0xd8 */ + { NULL, NULL, NULL, NULL, }, /* 0xd9 */ + { NULL, NULL, NULL, NULL, }, /* 0xda */ + { NULL, NULL, NULL, NULL, }, /* 0xdb */ + { NULL, NULL, NULL, NULL, }, /* 0xdc */ + { NULL, NULL, NULL, NULL, }, /* 0xdd */ + { NULL, NULL, NULL, NULL, }, /* 0xde */ + { NULL, NULL, NULL, NULL, }, /* 0xdf */ + { NULL, NULL, NULL, &decl_net_called_soft, }, /* 0xe0 */ + { NULL, NULL, NULL, &decl_net_crankback, }, /* 0xe1 */ + { NULL, NULL, NULL, &decl_net_dtl, }, /* 0xe2 */ + { NULL, NULL, NULL, &decl_net_calling_soft, }, /* 0xe3 */ + { NULL, NULL, NULL, &decl_net_abradd, }, /* 0xe4 */ + { NULL, NULL, NULL, NULL, }, /* 0xe5 */ + { NULL, NULL, NULL, NULL, }, /* 0xe6 */ + { NULL, NULL, NULL, NULL, }, /* 0xe7 */ + { NULL, NULL, NULL, &decl_net_lij_callid, }, /* 0xe8 */ + { NULL, NULL, NULL, &decl_net_lij_param, }, /* 0xe9 */ + { NULL, NULL, NULL, &decl_net_lij_seqno, }, /* 0xea */ + { NULL, NULL, NULL, &decl_net_cscope, }, /* 0xeb */ + { NULL, NULL, NULL, &decl_net_exqos, }, /* 0xec */ + { NULL, NULL, NULL, NULL, }, /* 0xed */ + { NULL, NULL, NULL, NULL, }, /* 0xee */ + { NULL, NULL, NULL, NULL, }, /* 0xef */ + { NULL, NULL, NULL, &decl_net_mdcr, }, /* 0xf0 */ + { NULL, NULL, NULL, NULL, }, /* 0xf1 */ + { NULL, NULL, NULL, NULL, }, /* 0xf2 */ + { NULL, NULL, NULL, NULL, }, /* 0xf3 */ + { NULL, NULL, NULL, NULL, }, /* 0xf4 */ + { NULL, NULL, NULL, NULL, }, /* 0xf5 */ + { NULL, NULL, NULL, NULL, }, /* 0xf6 */ + { NULL, NULL, NULL, NULL, }, /* 0xf7 */ + { NULL, NULL, NULL, NULL, }, /* 0xf8 */ + { NULL, NULL, NULL, NULL, }, /* 0xf9 */ + { NULL, NULL, NULL, NULL, }, /* 0xfa */ + { NULL, NULL, NULL, NULL, }, /* 0xfb */ + { NULL, NULL, NULL, NULL, }, /* 0xfc */ + { NULL, NULL, NULL, NULL, }, /* 0xfd */ + { &decl_itu_unrec, NULL, NULL, NULL, }, /* 0xfe */ + { NULL, NULL, NULL, NULL, }, /* 0xff */ +}; diff --git a/sys/contrib/ngatm/netnatm/msg/uni_msg.c b/sys/contrib/ngatm/netnatm/msg/uni_msg.c new file mode 100644 index 000000000000..f9991858b418 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/uni_msg.c @@ -0,0 +1,4901 @@ +/* This file was created automatically + * Source file: $Begemot: libunimsg/atm/msg/msg.def,v 1.3 2003/09/19 11:58:15 hbb Exp $ + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/param.h> + +#ifdef _KERNEL +#include <sys/libkern.h> +#else +#include <string.h> +#endif +#include <netnatm/unimsg.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#include <netnatm/msg/priv.h> +#include <netnatm/msg/privmsg.c> + +static void +print_alerting(struct uni_alerting *msg, struct unicx *cx) +{ + u_int i; + + if(msg->connid.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CONNID, (union uni_ieall *)&msg->connid, cx); + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->uu.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UU, (union uni_ieall *)&msg->uu, cx); + if(msg->report.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_REPORT, (union uni_ieall *)&msg->report, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_alerting(struct uni_alerting *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->connid); + else + ret |= uni_check_ie(UNI_IE_CONNID, (union uni_ieall *)&m->connid, cx); + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->uu); + else + ret |= uni_check_ie(UNI_IE_UU, (union uni_ieall *)&m->uu, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->report); + else + ret |= uni_check_ie(UNI_IE_REPORT, (union uni_ieall *)&m->report, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_alerting(struct uni_msg *msg, struct uni_alerting *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_ALERTING, cx, &mlen)) + return (-2); + + if((p->connid.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CONNID, msg, (union uni_ieall *)&p->connid, cx)) + return (UNI_IE_CONNID); + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->uu.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UU, msg, (union uni_ieall *)&p->uu, cx)) + return (UNI_IE_UU); + if((p->report.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_REPORT, msg, (union uni_ieall *)&p->report, cx)) + return (UNI_IE_REPORT); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_alerting(struct uni_alerting *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_CONNID: + if (!(!cx->pnni)) + return (DEC_ILL); + out->connid.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CONNID, (union uni_ieall *)&out->connid, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UU: + if (!(!cx->pnni)) + return (DEC_ILL); + out->uu.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UU, (union uni_ieall *)&out->uu, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_REPORT: + if (!(!cx->pnni)) + return (DEC_ILL); + out->report.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_REPORT, (union uni_ieall *)&out->report, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_alerting = { + 0, + "alerting", + (uni_msg_print_f)print_alerting, + (uni_msg_check_f)check_alerting, + (uni_msg_encode_f)encode_alerting, + (uni_msg_decode_f)decode_alerting +}; + +static void +print_call_proc(struct uni_call_proc *msg, struct unicx *cx) +{ + if(msg->connid.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CONNID, (union uni_ieall *)&msg->connid, cx); + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_call_proc(struct uni_call_proc *m, struct unicx *cx) +{ + int ret = 0; + + ret |= uni_check_ie(UNI_IE_CONNID, (union uni_ieall *)&m->connid, cx); + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->notify); + else + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_call_proc(struct uni_msg *msg, struct uni_call_proc *p, struct unicx *cx) +{ + u_int mlen; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_CALL_PROC, cx, &mlen)) + return (-2); + + if((p->connid.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CONNID, msg, (union uni_ieall *)&p->connid, cx)) + return (UNI_IE_CONNID); + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_call_proc(struct uni_call_proc *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + switch (ie) { + + case UNI_IE_CONNID: + out->connid.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CONNID, (union uni_ieall *)&out->connid, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + if (!(!cx->pnni)) + return (DEC_ILL); + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_call_proc = { + 0, + "call_proc", + (uni_msg_print_f)print_call_proc, + (uni_msg_check_f)check_call_proc, + (uni_msg_encode_f)encode_call_proc, + (uni_msg_decode_f)decode_call_proc +}; + +static void +print_connect(struct uni_connect *msg, struct unicx *cx) +{ + u_int i; + + if(msg->aal.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_AAL, (union uni_ieall *)&msg->aal, cx); + if(msg->blli.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_BLLI, (union uni_ieall *)&msg->blli, cx); + if(msg->connid.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CONNID, (union uni_ieall *)&msg->connid, cx); + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + if(msg->conned.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CONNED, (union uni_ieall *)&msg->conned, cx); + if(msg->connedsub.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CONNEDSUB, (union uni_ieall *)&msg->connedsub, cx); + if(msg->eetd.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EETD, (union uni_ieall *)&msg->eetd, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->uu.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UU, (union uni_ieall *)&msg->uu, cx); + if(msg->traffic.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_TRAFFIC, (union uni_ieall *)&msg->traffic, cx); + if(msg->exqos.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EXQOS, (union uni_ieall *)&msg->exqos, cx); + if(msg->facility.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_FACILITY, (union uni_ieall *)&msg->facility, cx); + if(msg->abrsetup.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_ABRSETUP, (union uni_ieall *)&msg->abrsetup, cx); + if(msg->abradd.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_ABRADD, (union uni_ieall *)&msg->abradd, cx); + if(msg->called_soft.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLED_SOFT, (union uni_ieall *)&msg->called_soft, cx); + if(msg->report.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_REPORT, (union uni_ieall *)&msg->report, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_connect(struct uni_connect *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_AAL, (union uni_ieall *)&m->aal, cx); + ret |= uni_check_ie(UNI_IE_BLLI, (union uni_ieall *)&m->blli, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->connid); + else + ret |= uni_check_ie(UNI_IE_CONNID, (union uni_ieall *)&m->connid, cx); + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + ret |= uni_check_ie(UNI_IE_CONNED, (union uni_ieall *)&m->conned, cx); + ret |= uni_check_ie(UNI_IE_CONNEDSUB, (union uni_ieall *)&m->connedsub, cx); + ret |= uni_check_ie(UNI_IE_EETD, (union uni_ieall *)&m->eetd, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->uu); + else + ret |= uni_check_ie(UNI_IE_UU, (union uni_ieall *)&m->uu, cx); + ret |= uni_check_ie(UNI_IE_TRAFFIC, (union uni_ieall *)&m->traffic, cx); + ret |= uni_check_ie(UNI_IE_EXQOS, (union uni_ieall *)&m->exqos, cx); + if(!(cx->q2932)) + ret |= IE_ISPRESENT(m->facility); + else + ret |= uni_check_ie(UNI_IE_FACILITY, (union uni_ieall *)&m->facility, cx); + ret |= uni_check_ie(UNI_IE_ABRSETUP, (union uni_ieall *)&m->abrsetup, cx); + ret |= uni_check_ie(UNI_IE_ABRADD, (union uni_ieall *)&m->abradd, cx); + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->called_soft); + else + ret |= uni_check_ie(UNI_IE_CALLED_SOFT, (union uni_ieall *)&m->called_soft, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->report); + else + ret |= uni_check_ie(UNI_IE_REPORT, (union uni_ieall *)&m->report, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_connect(struct uni_msg *msg, struct uni_connect *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_CONNECT, cx, &mlen)) + return (-2); + + if((p->aal.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_AAL, msg, (union uni_ieall *)&p->aal, cx)) + return (UNI_IE_AAL); + if((p->blli.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_BLLI, msg, (union uni_ieall *)&p->blli, cx)) + return (UNI_IE_BLLI); + if((p->connid.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CONNID, msg, (union uni_ieall *)&p->connid, cx)) + return (UNI_IE_CONNID); + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + if((p->conned.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CONNED, msg, (union uni_ieall *)&p->conned, cx)) + return (UNI_IE_CONNED); + if((p->connedsub.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CONNEDSUB, msg, (union uni_ieall *)&p->connedsub, cx)) + return (UNI_IE_CONNEDSUB); + if((p->eetd.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EETD, msg, (union uni_ieall *)&p->eetd, cx)) + return (UNI_IE_EETD); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->uu.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UU, msg, (union uni_ieall *)&p->uu, cx)) + return (UNI_IE_UU); + if((p->traffic.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_TRAFFIC, msg, (union uni_ieall *)&p->traffic, cx)) + return (UNI_IE_TRAFFIC); + if((p->exqos.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EXQOS, msg, (union uni_ieall *)&p->exqos, cx)) + return (UNI_IE_EXQOS); + if((p->facility.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_FACILITY, msg, (union uni_ieall *)&p->facility, cx)) + return (UNI_IE_FACILITY); + if((p->abrsetup.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_ABRSETUP, msg, (union uni_ieall *)&p->abrsetup, cx)) + return (UNI_IE_ABRSETUP); + if((p->abradd.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_ABRADD, msg, (union uni_ieall *)&p->abradd, cx)) + return (UNI_IE_ABRADD); + if((p->called_soft.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLED_SOFT, msg, (union uni_ieall *)&p->called_soft, cx)) + return (UNI_IE_CALLED_SOFT); + if((p->report.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_REPORT, msg, (union uni_ieall *)&p->report, cx)) + return (UNI_IE_REPORT); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_connect(struct uni_connect *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_AAL: + out->aal.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_AAL, (union uni_ieall *)&out->aal, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_BLLI: + out->blli.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_BLLI, (union uni_ieall *)&out->blli, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CONNID: + if (!(!cx->pnni)) + return (DEC_ILL); + out->connid.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CONNID, (union uni_ieall *)&out->connid, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CONNED: + out->conned.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CONNED, (union uni_ieall *)&out->conned, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CONNEDSUB: + out->connedsub.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CONNEDSUB, (union uni_ieall *)&out->connedsub, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EETD: + out->eetd.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EETD, (union uni_ieall *)&out->eetd, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UU: + if (!(!cx->pnni)) + return (DEC_ILL); + out->uu.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UU, (union uni_ieall *)&out->uu, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_TRAFFIC: + out->traffic.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_TRAFFIC, (union uni_ieall *)&out->traffic, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EXQOS: + out->exqos.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EXQOS, (union uni_ieall *)&out->exqos, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_FACILITY: + if (!(cx->q2932)) + return (DEC_ILL); + out->facility.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_FACILITY, (union uni_ieall *)&out->facility, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_ABRSETUP: + out->abrsetup.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_ABRSETUP, (union uni_ieall *)&out->abrsetup, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_ABRADD: + out->abradd.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_ABRADD, (union uni_ieall *)&out->abradd, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLED_SOFT: + if (!(cx->pnni)) + return (DEC_ILL); + out->called_soft.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLED_SOFT, (union uni_ieall *)&out->called_soft, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_REPORT: + if (!(!cx->pnni)) + return (DEC_ILL); + out->report.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_REPORT, (union uni_ieall *)&out->report, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_connect = { + 0, + "connect", + (uni_msg_print_f)print_connect, + (uni_msg_check_f)check_connect, + (uni_msg_encode_f)encode_connect, + (uni_msg_decode_f)decode_connect +}; + +static void +print_connect_ack(struct uni_connect_ack *msg, struct unicx *cx) +{ + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_connect_ack(struct uni_connect_ack *m, struct unicx *cx) +{ + int ret = 0; + + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_connect_ack(struct uni_msg *msg, struct uni_connect_ack *p, struct unicx *cx) +{ + u_int mlen; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_CONNECT_ACK, cx, &mlen)) + return (-2); + + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_connect_ack(struct uni_connect_ack *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + switch (ie) { + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_connect_ack = { + 0, + "connect_ack", + (uni_msg_print_f)print_connect_ack, + (uni_msg_check_f)check_connect_ack, + (uni_msg_encode_f)encode_connect_ack, + (uni_msg_decode_f)decode_connect_ack +}; + +static void +print_release(struct uni_release *msg, struct unicx *cx) +{ + u_int i; + + for(i = 0; i < 2; i++) + if(msg->cause[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CAUSE, (union uni_ieall *)&msg->cause[i], cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->uu.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UU, (union uni_ieall *)&msg->uu, cx); + if(msg->facility.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_FACILITY, (union uni_ieall *)&msg->facility, cx); + if(msg->crankback.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CRANKBACK, (union uni_ieall *)&msg->crankback, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_release(struct uni_release *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + for(i = 0; i < 2 ; i++) { + ret |= uni_check_ie(UNI_IE_CAUSE, (union uni_ieall *)&m->cause[i], cx); + } + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->uu); + else + ret |= uni_check_ie(UNI_IE_UU, (union uni_ieall *)&m->uu, cx); + if(!(cx->q2932)) + ret |= IE_ISPRESENT(m->facility); + else + ret |= uni_check_ie(UNI_IE_FACILITY, (union uni_ieall *)&m->facility, cx); + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->crankback); + else + ret |= uni_check_ie(UNI_IE_CRANKBACK, (union uni_ieall *)&m->crankback, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_release(struct uni_msg *msg, struct uni_release *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_RELEASE, cx, &mlen)) + return (-2); + + for(i = 0; i < 2; i++) + if((p->cause[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CAUSE, msg, (union uni_ieall *)&p->cause[i], cx)) + return ((i << 16) + UNI_IE_CAUSE); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->uu.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UU, msg, (union uni_ieall *)&p->uu, cx)) + return (UNI_IE_UU); + if((p->facility.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_FACILITY, msg, (union uni_ieall *)&p->facility, cx)) + return (UNI_IE_FACILITY); + if((p->crankback.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CRANKBACK, msg, (union uni_ieall *)&p->crankback, cx)) + return (UNI_IE_CRANKBACK); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_release(struct uni_release *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_CAUSE: + for(i = 0; i < 2; i++) + if (!IE_ISPRESENT(out->cause[i])) { + out->cause[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CAUSE, (union uni_ieall *)&out->cause[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UU: + if (!(!cx->pnni)) + return (DEC_ILL); + out->uu.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UU, (union uni_ieall *)&out->uu, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_FACILITY: + if (!(cx->q2932)) + return (DEC_ILL); + out->facility.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_FACILITY, (union uni_ieall *)&out->facility, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CRANKBACK: + if (!(cx->pnni)) + return (DEC_ILL); + out->crankback.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CRANKBACK, (union uni_ieall *)&out->crankback, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_release = { + 0, + "release", + (uni_msg_print_f)print_release, + (uni_msg_check_f)check_release, + (uni_msg_encode_f)encode_release, + (uni_msg_decode_f)decode_release +}; + +static void +print_release_compl(struct uni_release_compl *msg, struct unicx *cx) +{ + u_int i; + + for(i = 0; i < 2; i++) + if(msg->cause[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CAUSE, (union uni_ieall *)&msg->cause[i], cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->uu.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UU, (union uni_ieall *)&msg->uu, cx); + if(msg->crankback.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CRANKBACK, (union uni_ieall *)&msg->crankback, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_release_compl(struct uni_release_compl *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + for(i = 0; i < 2 ; i++) { + ret |= uni_check_ie(UNI_IE_CAUSE, (union uni_ieall *)&m->cause[i], cx); + } + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->git[i]); + else + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->uu); + else + ret |= uni_check_ie(UNI_IE_UU, (union uni_ieall *)&m->uu, cx); + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->crankback); + else + ret |= uni_check_ie(UNI_IE_CRANKBACK, (union uni_ieall *)&m->crankback, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_release_compl(struct uni_msg *msg, struct uni_release_compl *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_RELEASE_COMPL, cx, &mlen)) + return (-2); + + for(i = 0; i < 2; i++) + if((p->cause[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CAUSE, msg, (union uni_ieall *)&p->cause[i], cx)) + return ((i << 16) + UNI_IE_CAUSE); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->uu.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UU, msg, (union uni_ieall *)&p->uu, cx)) + return (UNI_IE_UU); + if((p->crankback.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CRANKBACK, msg, (union uni_ieall *)&p->crankback, cx)) + return (UNI_IE_CRANKBACK); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_release_compl(struct uni_release_compl *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_CAUSE: + for(i = 0; i < 2; i++) + if (!IE_ISPRESENT(out->cause[i])) { + out->cause[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CAUSE, (union uni_ieall *)&out->cause[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_GIT: + if (!(!cx->pnni)) + return (DEC_ILL); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UU: + if (!(!cx->pnni)) + return (DEC_ILL); + out->uu.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UU, (union uni_ieall *)&out->uu, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CRANKBACK: + if (!(cx->pnni)) + return (DEC_ILL); + out->crankback.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CRANKBACK, (union uni_ieall *)&out->crankback, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_release_compl = { + 0, + "release_compl", + (uni_msg_print_f)print_release_compl, + (uni_msg_check_f)check_release_compl, + (uni_msg_encode_f)encode_release_compl, + (uni_msg_decode_f)decode_release_compl +}; + +static void +print_setup(struct uni_setup *msg, struct unicx *cx) +{ + u_int i; + + if(msg->aal.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_AAL, (union uni_ieall *)&msg->aal, cx); + if(msg->traffic.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_TRAFFIC, (union uni_ieall *)&msg->traffic, cx); + if(msg->bearer.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_BEARER, (union uni_ieall *)&msg->bearer, cx); + if(msg->bhli.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_BHLI, (union uni_ieall *)&msg->bhli, cx); + if(msg->blli_repeat.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_REPEAT, (union uni_ieall *)&msg->blli_repeat, cx); + for(i = 0; i < UNI_NUM_IE_BLLI; i++) + if(msg->blli[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_BLLI, (union uni_ieall *)&msg->blli[i], cx); + if(msg->called.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLED, (union uni_ieall *)&msg->called, cx); + for(i = 0; i < UNI_NUM_IE_CALLEDSUB; i++) + if(msg->calledsub[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLEDSUB, (union uni_ieall *)&msg->calledsub[i], cx); + if(msg->calling.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLING, (union uni_ieall *)&msg->calling, cx); + for(i = 0; i < UNI_NUM_IE_CALLINGSUB; i++) + if(msg->callingsub[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLINGSUB, (union uni_ieall *)&msg->callingsub[i], cx); + if(msg->connid.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CONNID, (union uni_ieall *)&msg->connid, cx); + if(msg->qos.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_QOS, (union uni_ieall *)&msg->qos, cx); + if(msg->eetd.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EETD, (union uni_ieall *)&msg->eetd, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + if(msg->scompl.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_SCOMPL, (union uni_ieall *)&msg->scompl, cx); + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if(msg->tns[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_TNS, (union uni_ieall *)&msg->tns[i], cx); + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->atraffic.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_ATRAFFIC, (union uni_ieall *)&msg->atraffic, cx); + if(msg->mintraffic.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_MINTRAFFIC, (union uni_ieall *)&msg->mintraffic, cx); + if(msg->uu.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UU, (union uni_ieall *)&msg->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->lij_callid.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_LIJ_CALLID, (union uni_ieall *)&msg->lij_callid, cx); + if(msg->lij_param.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_LIJ_PARAM, (union uni_ieall *)&msg->lij_param, cx); + if(msg->lij_seqno.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&msg->lij_seqno, cx); + if(msg->exqos.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EXQOS, (union uni_ieall *)&msg->exqos, cx); + if(msg->abrsetup.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_ABRSETUP, (union uni_ieall *)&msg->abrsetup, cx); + if(msg->abradd.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_ABRADD, (union uni_ieall *)&msg->abradd, cx); + if(msg->cscope.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CSCOPE, (union uni_ieall *)&msg->cscope, cx); + if(msg->calling_soft.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLING_SOFT, (union uni_ieall *)&msg->calling_soft, cx); + if(msg->called_soft.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLED_SOFT, (union uni_ieall *)&msg->called_soft, cx); + if(msg->dtl_repeat.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_REPEAT, (union uni_ieall *)&msg->dtl_repeat, cx); + for(i = 0; i < UNI_NUM_IE_DTL; i++) + if(msg->dtl[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_DTL, (union uni_ieall *)&msg->dtl[i], cx); + if(msg->report.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_REPORT, (union uni_ieall *)&msg->report, cx); + if(msg->mdcr.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_MDCR, (union uni_ieall *)&msg->mdcr, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_setup(struct uni_setup *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_AAL, (union uni_ieall *)&m->aal, cx); + ret |= uni_check_ie(UNI_IE_TRAFFIC, (union uni_ieall *)&m->traffic, cx); + ret |= uni_check_ie(UNI_IE_BEARER, (union uni_ieall *)&m->bearer, cx); + ret |= uni_check_ie(UNI_IE_BHLI, (union uni_ieall *)&m->bhli, cx); + ret |= uni_check_ie(UNI_IE_REPEAT, (union uni_ieall *)&m->blli_repeat, cx); + for(i = 0; i < UNI_NUM_IE_BLLI ; i++) { + ret |= uni_check_ie(UNI_IE_BLLI, (union uni_ieall *)&m->blli[i], cx); + } + ret |= uni_check_ie(UNI_IE_CALLED, (union uni_ieall *)&m->called, cx); + for(i = 0; i < UNI_NUM_IE_CALLEDSUB ; i++) { + ret |= uni_check_ie(UNI_IE_CALLEDSUB, (union uni_ieall *)&m->calledsub[i], cx); + } + ret |= uni_check_ie(UNI_IE_CALLING, (union uni_ieall *)&m->calling, cx); + for(i = 0; i < UNI_NUM_IE_CALLINGSUB ; i++) { + ret |= uni_check_ie(UNI_IE_CALLINGSUB, (union uni_ieall *)&m->callingsub[i], cx); + } + ret |= uni_check_ie(UNI_IE_CONNID, (union uni_ieall *)&m->connid, cx); + ret |= uni_check_ie(UNI_IE_QOS, (union uni_ieall *)&m->qos, cx); + ret |= uni_check_ie(UNI_IE_EETD, (union uni_ieall *)&m->eetd, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->scompl); + else + ret |= uni_check_ie(UNI_IE_SCOMPL, (union uni_ieall *)&m->scompl, cx); + for(i = 0; i < UNI_NUM_IE_TNS ; i++) { + ret |= uni_check_ie(UNI_IE_TNS, (union uni_ieall *)&m->tns[i], cx); + } + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_ATRAFFIC, (union uni_ieall *)&m->atraffic, cx); + ret |= uni_check_ie(UNI_IE_MINTRAFFIC, (union uni_ieall *)&m->mintraffic, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->uu); + else + ret |= uni_check_ie(UNI_IE_UU, (union uni_ieall *)&m->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->lij_callid); + else + ret |= uni_check_ie(UNI_IE_LIJ_CALLID, (union uni_ieall *)&m->lij_callid, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->lij_param); + else + ret |= uni_check_ie(UNI_IE_LIJ_PARAM, (union uni_ieall *)&m->lij_param, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->lij_seqno); + else + ret |= uni_check_ie(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&m->lij_seqno, cx); + ret |= uni_check_ie(UNI_IE_EXQOS, (union uni_ieall *)&m->exqos, cx); + ret |= uni_check_ie(UNI_IE_ABRSETUP, (union uni_ieall *)&m->abrsetup, cx); + ret |= uni_check_ie(UNI_IE_ABRADD, (union uni_ieall *)&m->abradd, cx); + ret |= uni_check_ie(UNI_IE_CSCOPE, (union uni_ieall *)&m->cscope, cx); + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->calling_soft); + else + ret |= uni_check_ie(UNI_IE_CALLING_SOFT, (union uni_ieall *)&m->calling_soft, cx); + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->called_soft); + else + ret |= uni_check_ie(UNI_IE_CALLED_SOFT, (union uni_ieall *)&m->called_soft, cx); + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->dtl_repeat); + else + ret |= uni_check_ie(UNI_IE_REPEAT, (union uni_ieall *)&m->dtl_repeat, cx); + for(i = 0; i < UNI_NUM_IE_DTL ; i++) { + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->dtl[i]); + else + ret |= uni_check_ie(UNI_IE_DTL, (union uni_ieall *)&m->dtl[i], cx); + } + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->report); + else + ret |= uni_check_ie(UNI_IE_REPORT, (union uni_ieall *)&m->report, cx); + ret |= uni_check_ie(UNI_IE_MDCR, (union uni_ieall *)&m->mdcr, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_setup(struct uni_msg *msg, struct uni_setup *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_SETUP, cx, &mlen)) + return (-2); + + if((p->aal.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_AAL, msg, (union uni_ieall *)&p->aal, cx)) + return (UNI_IE_AAL); + if((p->traffic.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_TRAFFIC, msg, (union uni_ieall *)&p->traffic, cx)) + return (UNI_IE_TRAFFIC); + if((p->bearer.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_BEARER, msg, (union uni_ieall *)&p->bearer, cx)) + return (UNI_IE_BEARER); + if((p->bhli.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_BHLI, msg, (union uni_ieall *)&p->bhli, cx)) + return (UNI_IE_BHLI); + if((p->blli_repeat.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_BLLI, msg, (union uni_ieall *)&p->blli_repeat, cx)) + return (0x10000000 + UNI_IE_BLLI); + for(i = 0; i < UNI_NUM_IE_BLLI; i++) + if((p->blli[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_BLLI, msg, (union uni_ieall *)&p->blli[i], cx)) + return ((i << 16) + UNI_IE_BLLI); + if((p->called.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLED, msg, (union uni_ieall *)&p->called, cx)) + return (UNI_IE_CALLED); + for(i = 0; i < UNI_NUM_IE_CALLEDSUB; i++) + if((p->calledsub[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLEDSUB, msg, (union uni_ieall *)&p->calledsub[i], cx)) + return ((i << 16) + UNI_IE_CALLEDSUB); + if((p->calling.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLING, msg, (union uni_ieall *)&p->calling, cx)) + return (UNI_IE_CALLING); + for(i = 0; i < UNI_NUM_IE_CALLINGSUB; i++) + if((p->callingsub[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLINGSUB, msg, (union uni_ieall *)&p->callingsub[i], cx)) + return ((i << 16) + UNI_IE_CALLINGSUB); + if((p->connid.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CONNID, msg, (union uni_ieall *)&p->connid, cx)) + return (UNI_IE_CONNID); + if((p->qos.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_QOS, msg, (union uni_ieall *)&p->qos, cx)) + return (UNI_IE_QOS); + if((p->eetd.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EETD, msg, (union uni_ieall *)&p->eetd, cx)) + return (UNI_IE_EETD); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + if((p->scompl.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_SCOMPL, msg, (union uni_ieall *)&p->scompl, cx)) + return (UNI_IE_SCOMPL); + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if((p->tns[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_TNS, msg, (union uni_ieall *)&p->tns[i], cx)) + return ((i << 16) + UNI_IE_TNS); + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->atraffic.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_ATRAFFIC, msg, (union uni_ieall *)&p->atraffic, cx)) + return (UNI_IE_ATRAFFIC); + if((p->mintraffic.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_MINTRAFFIC, msg, (union uni_ieall *)&p->mintraffic, cx)) + return (UNI_IE_MINTRAFFIC); + if((p->uu.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UU, msg, (union uni_ieall *)&p->uu, cx)) + return (UNI_IE_UU); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->lij_callid.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_LIJ_CALLID, msg, (union uni_ieall *)&p->lij_callid, cx)) + return (UNI_IE_LIJ_CALLID); + if((p->lij_param.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_LIJ_PARAM, msg, (union uni_ieall *)&p->lij_param, cx)) + return (UNI_IE_LIJ_PARAM); + if((p->lij_seqno.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_LIJ_SEQNO, msg, (union uni_ieall *)&p->lij_seqno, cx)) + return (UNI_IE_LIJ_SEQNO); + if((p->exqos.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EXQOS, msg, (union uni_ieall *)&p->exqos, cx)) + return (UNI_IE_EXQOS); + if((p->abrsetup.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_ABRSETUP, msg, (union uni_ieall *)&p->abrsetup, cx)) + return (UNI_IE_ABRSETUP); + if((p->abradd.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_ABRADD, msg, (union uni_ieall *)&p->abradd, cx)) + return (UNI_IE_ABRADD); + if((p->cscope.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CSCOPE, msg, (union uni_ieall *)&p->cscope, cx)) + return (UNI_IE_CSCOPE); + if((p->calling_soft.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLING_SOFT, msg, (union uni_ieall *)&p->calling_soft, cx)) + return (UNI_IE_CALLING_SOFT); + if((p->called_soft.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLED_SOFT, msg, (union uni_ieall *)&p->called_soft, cx)) + return (UNI_IE_CALLED_SOFT); + if((p->dtl_repeat.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_DTL, msg, (union uni_ieall *)&p->dtl_repeat, cx)) + return (0x10000000 + UNI_IE_DTL); + for(i = 0; i < UNI_NUM_IE_DTL; i++) + if((p->dtl[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_DTL, msg, (union uni_ieall *)&p->dtl[i], cx)) + return ((i << 16) + UNI_IE_DTL); + if((p->report.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_REPORT, msg, (union uni_ieall *)&p->report, cx)) + return (UNI_IE_REPORT); + if((p->mdcr.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_MDCR, msg, (union uni_ieall *)&p->mdcr, cx)) + return (UNI_IE_MDCR); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_setup(struct uni_setup *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_AAL: + out->aal.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_AAL, (union uni_ieall *)&out->aal, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_TRAFFIC: + out->traffic.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_TRAFFIC, (union uni_ieall *)&out->traffic, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_BEARER: + out->bearer.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_BEARER, (union uni_ieall *)&out->bearer, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_BHLI: + out->bhli.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_BHLI, (union uni_ieall *)&out->bhli, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_BLLI: + if (IE_ISPRESENT(cx->repeat)) + out->blli_repeat = cx->repeat; + for(i = 0; i < UNI_NUM_IE_BLLI; i++) + if (!IE_ISPRESENT(out->blli[i])) { + out->blli[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_BLLI, (union uni_ieall *)&out->blli[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_CALLED: + out->called.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLED, (union uni_ieall *)&out->called, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLEDSUB: + for(i = 0; i < UNI_NUM_IE_CALLEDSUB; i++) + if (!IE_ISPRESENT(out->calledsub[i])) { + out->calledsub[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLEDSUB, (union uni_ieall *)&out->calledsub[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_CALLING: + out->calling.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLING, (union uni_ieall *)&out->calling, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLINGSUB: + for(i = 0; i < UNI_NUM_IE_CALLINGSUB; i++) + if (!IE_ISPRESENT(out->callingsub[i])) { + out->callingsub[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLINGSUB, (union uni_ieall *)&out->callingsub[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_CONNID: + out->connid.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CONNID, (union uni_ieall *)&out->connid, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_QOS: + out->qos.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_QOS, (union uni_ieall *)&out->qos, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EETD: + out->eetd.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EETD, (union uni_ieall *)&out->eetd, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_SCOMPL: + if (!(!cx->pnni)) + return (DEC_ILL); + out->scompl.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_SCOMPL, (union uni_ieall *)&out->scompl, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_TNS: + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if (!IE_ISPRESENT(out->tns[i])) { + out->tns[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_TNS, (union uni_ieall *)&out->tns[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_ATRAFFIC: + out->atraffic.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_ATRAFFIC, (union uni_ieall *)&out->atraffic, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_MINTRAFFIC: + out->mintraffic.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_MINTRAFFIC, (union uni_ieall *)&out->mintraffic, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UU: + if (!(!cx->pnni)) + return (DEC_ILL); + out->uu.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UU, (union uni_ieall *)&out->uu, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_LIJ_CALLID: + if (!(!cx->pnni)) + return (DEC_ILL); + out->lij_callid.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_LIJ_CALLID, (union uni_ieall *)&out->lij_callid, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_LIJ_PARAM: + if (!(!cx->pnni)) + return (DEC_ILL); + out->lij_param.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_LIJ_PARAM, (union uni_ieall *)&out->lij_param, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_LIJ_SEQNO: + if (!(!cx->pnni)) + return (DEC_ILL); + out->lij_seqno.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&out->lij_seqno, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EXQOS: + out->exqos.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EXQOS, (union uni_ieall *)&out->exqos, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_ABRSETUP: + out->abrsetup.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_ABRSETUP, (union uni_ieall *)&out->abrsetup, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_ABRADD: + out->abradd.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_ABRADD, (union uni_ieall *)&out->abradd, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CSCOPE: + out->cscope.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CSCOPE, (union uni_ieall *)&out->cscope, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLING_SOFT: + if (!(cx->pnni)) + return (DEC_ILL); + out->calling_soft.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLING_SOFT, (union uni_ieall *)&out->calling_soft, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLED_SOFT: + if (!(cx->pnni)) + return (DEC_ILL); + out->called_soft.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLED_SOFT, (union uni_ieall *)&out->called_soft, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_DTL: + if (!(cx->pnni)) + return (DEC_ILL); + if (IE_ISPRESENT(cx->repeat)) + out->dtl_repeat = cx->repeat; + for(i = 0; i < UNI_NUM_IE_DTL; i++) + if (!IE_ISPRESENT(out->dtl[i])) { + out->dtl[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_DTL, (union uni_ieall *)&out->dtl[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_REPORT: + if (!(!cx->pnni)) + return (DEC_ILL); + out->report.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_REPORT, (union uni_ieall *)&out->report, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_MDCR: + out->mdcr.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_MDCR, (union uni_ieall *)&out->mdcr, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_REPEAT: + cx->repeat.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if (uni_decode_ie_body(UNI_IE_REPEAT, (union uni_ieall *)&cx->repeat, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_setup = { + 0, + "setup", + (uni_msg_print_f)print_setup, + (uni_msg_check_f)check_setup, + (uni_msg_encode_f)encode_setup, + (uni_msg_decode_f)decode_setup +}; + +static void +print_status(struct uni_status *msg, struct unicx *cx) +{ + if(msg->callstate.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLSTATE, (union uni_ieall *)&msg->callstate, cx); + if(msg->cause.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CAUSE, (union uni_ieall *)&msg->cause, cx); + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->epstate.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPSTATE, (union uni_ieall *)&msg->epstate, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_status(struct uni_status *m, struct unicx *cx) +{ + int ret = 0; + + ret |= uni_check_ie(UNI_IE_CALLSTATE, (union uni_ieall *)&m->callstate, cx); + ret |= uni_check_ie(UNI_IE_CAUSE, (union uni_ieall *)&m->cause, cx); + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_EPSTATE, (union uni_ieall *)&m->epstate, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_status(struct uni_msg *msg, struct uni_status *p, struct unicx *cx) +{ + u_int mlen; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_STATUS, cx, &mlen)) + return (-2); + + if((p->callstate.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLSTATE, msg, (union uni_ieall *)&p->callstate, cx)) + return (UNI_IE_CALLSTATE); + if((p->cause.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CAUSE, msg, (union uni_ieall *)&p->cause, cx)) + return (UNI_IE_CAUSE); + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->epstate.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPSTATE, msg, (union uni_ieall *)&p->epstate, cx)) + return (UNI_IE_EPSTATE); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_status(struct uni_status *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + switch (ie) { + + case UNI_IE_CALLSTATE: + out->callstate.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLSTATE, (union uni_ieall *)&out->callstate, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CAUSE: + out->cause.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CAUSE, (union uni_ieall *)&out->cause, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EPSTATE: + out->epstate.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPSTATE, (union uni_ieall *)&out->epstate, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_status = { + 0, + "status", + (uni_msg_print_f)print_status, + (uni_msg_check_f)check_status, + (uni_msg_encode_f)encode_status, + (uni_msg_decode_f)decode_status +}; + +static void +print_status_enq(struct uni_status_enq *msg, struct unicx *cx) +{ + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_status_enq(struct uni_status_enq *m, struct unicx *cx) +{ + int ret = 0; + + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_status_enq(struct uni_msg *msg, struct uni_status_enq *p, struct unicx *cx) +{ + u_int mlen; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_STATUS_ENQ, cx, &mlen)) + return (-2); + + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_status_enq(struct uni_status_enq *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + switch (ie) { + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_status_enq = { + 0, + "status_enq", + (uni_msg_print_f)print_status_enq, + (uni_msg_check_f)check_status_enq, + (uni_msg_encode_f)encode_status_enq, + (uni_msg_decode_f)decode_status_enq +}; + +static void +print_notify(struct uni_notify *msg, struct unicx *cx) +{ + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_notify(struct uni_notify *m, struct unicx *cx) +{ + int ret = 0; + + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_notify(struct uni_msg *msg, struct uni_notify *p, struct unicx *cx) +{ + u_int mlen; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_NOTIFY, cx, &mlen)) + return (-2); + + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_notify(struct uni_notify *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + switch (ie) { + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_notify = { + 0, + "notify", + (uni_msg_print_f)print_notify, + (uni_msg_check_f)check_notify, + (uni_msg_encode_f)encode_notify, + (uni_msg_decode_f)decode_notify +}; + +static void +print_restart(struct uni_restart *msg, struct unicx *cx) +{ + if(msg->connid.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CONNID, (union uni_ieall *)&msg->connid, cx); + if(msg->restart.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_RESTART, (union uni_ieall *)&msg->restart, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_restart(struct uni_restart *m, struct unicx *cx) +{ + int ret = 0; + + ret |= uni_check_ie(UNI_IE_CONNID, (union uni_ieall *)&m->connid, cx); + ret |= uni_check_ie(UNI_IE_RESTART, (union uni_ieall *)&m->restart, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_restart(struct uni_msg *msg, struct uni_restart *p, struct unicx *cx) +{ + u_int mlen; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_RESTART, cx, &mlen)) + return (-2); + + if((p->connid.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CONNID, msg, (union uni_ieall *)&p->connid, cx)) + return (UNI_IE_CONNID); + if((p->restart.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_RESTART, msg, (union uni_ieall *)&p->restart, cx)) + return (UNI_IE_RESTART); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_restart(struct uni_restart *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + switch (ie) { + + case UNI_IE_CONNID: + out->connid.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CONNID, (union uni_ieall *)&out->connid, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_RESTART: + out->restart.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_RESTART, (union uni_ieall *)&out->restart, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_restart = { + 0, + "restart", + (uni_msg_print_f)print_restart, + (uni_msg_check_f)check_restart, + (uni_msg_encode_f)encode_restart, + (uni_msg_decode_f)decode_restart +}; + +static void +print_restart_ack(struct uni_restart_ack *msg, struct unicx *cx) +{ + if(msg->connid.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CONNID, (union uni_ieall *)&msg->connid, cx); + if(msg->restart.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_RESTART, (union uni_ieall *)&msg->restart, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_restart_ack(struct uni_restart_ack *m, struct unicx *cx) +{ + int ret = 0; + + ret |= uni_check_ie(UNI_IE_CONNID, (union uni_ieall *)&m->connid, cx); + ret |= uni_check_ie(UNI_IE_RESTART, (union uni_ieall *)&m->restart, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_restart_ack(struct uni_msg *msg, struct uni_restart_ack *p, struct unicx *cx) +{ + u_int mlen; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_RESTART_ACK, cx, &mlen)) + return (-2); + + if((p->connid.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CONNID, msg, (union uni_ieall *)&p->connid, cx)) + return (UNI_IE_CONNID); + if((p->restart.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_RESTART, msg, (union uni_ieall *)&p->restart, cx)) + return (UNI_IE_RESTART); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_restart_ack(struct uni_restart_ack *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + switch (ie) { + + case UNI_IE_CONNID: + out->connid.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CONNID, (union uni_ieall *)&out->connid, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_RESTART: + out->restart.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_RESTART, (union uni_ieall *)&out->restart, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_restart_ack = { + 0, + "restart_ack", + (uni_msg_print_f)print_restart_ack, + (uni_msg_check_f)check_restart_ack, + (uni_msg_encode_f)encode_restart_ack, + (uni_msg_decode_f)decode_restart_ack +}; + +static void +print_add_party(struct uni_add_party *msg, struct unicx *cx) +{ + u_int i; + + if(msg->aal.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_AAL, (union uni_ieall *)&msg->aal, cx); + if(msg->bhli.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_BHLI, (union uni_ieall *)&msg->bhli, cx); + if(msg->blli.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_BLLI, (union uni_ieall *)&msg->blli, cx); + if(msg->called.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLED, (union uni_ieall *)&msg->called, cx); + for(i = 0; i < UNI_NUM_IE_CALLEDSUB; i++) + if(msg->calledsub[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLEDSUB, (union uni_ieall *)&msg->calledsub[i], cx); + if(msg->calling.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLING, (union uni_ieall *)&msg->calling, cx); + for(i = 0; i < UNI_NUM_IE_CALLINGSUB; i++) + if(msg->callingsub[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLINGSUB, (union uni_ieall *)&msg->callingsub[i], cx); + if(msg->scompl.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_SCOMPL, (union uni_ieall *)&msg->scompl, cx); + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if(msg->tns[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_TNS, (union uni_ieall *)&msg->tns[i], cx); + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + if(msg->eetd.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EETD, (union uni_ieall *)&msg->eetd, cx); + if(msg->uu.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UU, (union uni_ieall *)&msg->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->lij_seqno.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&msg->lij_seqno, cx); + if(msg->calling_soft.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLING_SOFT, (union uni_ieall *)&msg->calling_soft, cx); + if(msg->called_soft.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLED_SOFT, (union uni_ieall *)&msg->called_soft, cx); + if(msg->dtl_repeat.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_REPEAT, (union uni_ieall *)&msg->dtl_repeat, cx); + for(i = 0; i < UNI_NUM_IE_DTL; i++) + if(msg->dtl[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_DTL, (union uni_ieall *)&msg->dtl[i], cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_add_party(struct uni_add_party *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_AAL, (union uni_ieall *)&m->aal, cx); + ret |= uni_check_ie(UNI_IE_BHLI, (union uni_ieall *)&m->bhli, cx); + ret |= uni_check_ie(UNI_IE_BLLI, (union uni_ieall *)&m->blli, cx); + ret |= uni_check_ie(UNI_IE_CALLED, (union uni_ieall *)&m->called, cx); + for(i = 0; i < UNI_NUM_IE_CALLEDSUB ; i++) { + ret |= uni_check_ie(UNI_IE_CALLEDSUB, (union uni_ieall *)&m->calledsub[i], cx); + } + ret |= uni_check_ie(UNI_IE_CALLING, (union uni_ieall *)&m->calling, cx); + for(i = 0; i < UNI_NUM_IE_CALLINGSUB ; i++) { + ret |= uni_check_ie(UNI_IE_CALLINGSUB, (union uni_ieall *)&m->callingsub[i], cx); + } + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->scompl); + else + ret |= uni_check_ie(UNI_IE_SCOMPL, (union uni_ieall *)&m->scompl, cx); + for(i = 0; i < UNI_NUM_IE_TNS ; i++) { + ret |= uni_check_ie(UNI_IE_TNS, (union uni_ieall *)&m->tns[i], cx); + } + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + ret |= uni_check_ie(UNI_IE_EETD, (union uni_ieall *)&m->eetd, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->uu); + else + ret |= uni_check_ie(UNI_IE_UU, (union uni_ieall *)&m->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->lij_seqno); + else + ret |= uni_check_ie(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&m->lij_seqno, cx); + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->calling_soft); + else + ret |= uni_check_ie(UNI_IE_CALLING_SOFT, (union uni_ieall *)&m->calling_soft, cx); + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->called_soft); + else + ret |= uni_check_ie(UNI_IE_CALLED_SOFT, (union uni_ieall *)&m->called_soft, cx); + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->dtl_repeat); + else + ret |= uni_check_ie(UNI_IE_REPEAT, (union uni_ieall *)&m->dtl_repeat, cx); + for(i = 0; i < UNI_NUM_IE_DTL ; i++) { + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->dtl[i]); + else + ret |= uni_check_ie(UNI_IE_DTL, (union uni_ieall *)&m->dtl[i], cx); + } + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_add_party(struct uni_msg *msg, struct uni_add_party *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_ADD_PARTY, cx, &mlen)) + return (-2); + + if((p->aal.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_AAL, msg, (union uni_ieall *)&p->aal, cx)) + return (UNI_IE_AAL); + if((p->bhli.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_BHLI, msg, (union uni_ieall *)&p->bhli, cx)) + return (UNI_IE_BHLI); + if((p->blli.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_BLLI, msg, (union uni_ieall *)&p->blli, cx)) + return (UNI_IE_BLLI); + if((p->called.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLED, msg, (union uni_ieall *)&p->called, cx)) + return (UNI_IE_CALLED); + for(i = 0; i < UNI_NUM_IE_CALLEDSUB; i++) + if((p->calledsub[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLEDSUB, msg, (union uni_ieall *)&p->calledsub[i], cx)) + return ((i << 16) + UNI_IE_CALLEDSUB); + if((p->calling.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLING, msg, (union uni_ieall *)&p->calling, cx)) + return (UNI_IE_CALLING); + for(i = 0; i < UNI_NUM_IE_CALLINGSUB; i++) + if((p->callingsub[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLINGSUB, msg, (union uni_ieall *)&p->callingsub[i], cx)) + return ((i << 16) + UNI_IE_CALLINGSUB); + if((p->scompl.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_SCOMPL, msg, (union uni_ieall *)&p->scompl, cx)) + return (UNI_IE_SCOMPL); + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if((p->tns[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_TNS, msg, (union uni_ieall *)&p->tns[i], cx)) + return ((i << 16) + UNI_IE_TNS); + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + if((p->eetd.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EETD, msg, (union uni_ieall *)&p->eetd, cx)) + return (UNI_IE_EETD); + if((p->uu.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UU, msg, (union uni_ieall *)&p->uu, cx)) + return (UNI_IE_UU); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->lij_seqno.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_LIJ_SEQNO, msg, (union uni_ieall *)&p->lij_seqno, cx)) + return (UNI_IE_LIJ_SEQNO); + if((p->calling_soft.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLING_SOFT, msg, (union uni_ieall *)&p->calling_soft, cx)) + return (UNI_IE_CALLING_SOFT); + if((p->called_soft.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLED_SOFT, msg, (union uni_ieall *)&p->called_soft, cx)) + return (UNI_IE_CALLED_SOFT); + if((p->dtl_repeat.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_DTL, msg, (union uni_ieall *)&p->dtl_repeat, cx)) + return (0x10000000 + UNI_IE_DTL); + for(i = 0; i < UNI_NUM_IE_DTL; i++) + if((p->dtl[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_DTL, msg, (union uni_ieall *)&p->dtl[i], cx)) + return ((i << 16) + UNI_IE_DTL); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_add_party(struct uni_add_party *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_AAL: + out->aal.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_AAL, (union uni_ieall *)&out->aal, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_BHLI: + out->bhli.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_BHLI, (union uni_ieall *)&out->bhli, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_BLLI: + out->blli.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_BLLI, (union uni_ieall *)&out->blli, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLED: + out->called.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLED, (union uni_ieall *)&out->called, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLEDSUB: + for(i = 0; i < UNI_NUM_IE_CALLEDSUB; i++) + if (!IE_ISPRESENT(out->calledsub[i])) { + out->calledsub[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLEDSUB, (union uni_ieall *)&out->calledsub[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_CALLING: + out->calling.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLING, (union uni_ieall *)&out->calling, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLINGSUB: + for(i = 0; i < UNI_NUM_IE_CALLINGSUB; i++) + if (!IE_ISPRESENT(out->callingsub[i])) { + out->callingsub[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLINGSUB, (union uni_ieall *)&out->callingsub[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_SCOMPL: + if (!(!cx->pnni)) + return (DEC_ILL); + out->scompl.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_SCOMPL, (union uni_ieall *)&out->scompl, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_TNS: + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if (!IE_ISPRESENT(out->tns[i])) { + out->tns[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_TNS, (union uni_ieall *)&out->tns[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EETD: + out->eetd.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EETD, (union uni_ieall *)&out->eetd, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UU: + if (!(!cx->pnni)) + return (DEC_ILL); + out->uu.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UU, (union uni_ieall *)&out->uu, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_LIJ_SEQNO: + if (!(!cx->pnni)) + return (DEC_ILL); + out->lij_seqno.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&out->lij_seqno, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLING_SOFT: + if (!(cx->pnni)) + return (DEC_ILL); + out->calling_soft.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLING_SOFT, (union uni_ieall *)&out->calling_soft, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLED_SOFT: + if (!(cx->pnni)) + return (DEC_ILL); + out->called_soft.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLED_SOFT, (union uni_ieall *)&out->called_soft, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_DTL: + if (!(cx->pnni)) + return (DEC_ILL); + if (IE_ISPRESENT(cx->repeat)) + out->dtl_repeat = cx->repeat; + for(i = 0; i < UNI_NUM_IE_DTL; i++) + if (!IE_ISPRESENT(out->dtl[i])) { + out->dtl[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_DTL, (union uni_ieall *)&out->dtl[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_REPEAT: + cx->repeat.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if (uni_decode_ie_body(UNI_IE_REPEAT, (union uni_ieall *)&cx->repeat, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_add_party = { + 0, + "add_party", + (uni_msg_print_f)print_add_party, + (uni_msg_check_f)check_add_party, + (uni_msg_encode_f)encode_add_party, + (uni_msg_decode_f)decode_add_party +}; + +static void +print_add_party_ack(struct uni_add_party_ack *msg, struct unicx *cx) +{ + u_int i; + + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->aal.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_AAL, (union uni_ieall *)&msg->aal, cx); + if(msg->blli.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_BLLI, (union uni_ieall *)&msg->blli, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + if(msg->eetd.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EETD, (union uni_ieall *)&msg->eetd, cx); + if(msg->conned.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CONNED, (union uni_ieall *)&msg->conned, cx); + if(msg->connedsub.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CONNEDSUB, (union uni_ieall *)&msg->connedsub, cx); + if(msg->uu.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UU, (union uni_ieall *)&msg->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->called_soft.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLED_SOFT, (union uni_ieall *)&msg->called_soft, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_add_party_ack(struct uni_add_party_ack *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_AAL, (union uni_ieall *)&m->aal, cx); + ret |= uni_check_ie(UNI_IE_BLLI, (union uni_ieall *)&m->blli, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + ret |= uni_check_ie(UNI_IE_EETD, (union uni_ieall *)&m->eetd, cx); + ret |= uni_check_ie(UNI_IE_CONNED, (union uni_ieall *)&m->conned, cx); + ret |= uni_check_ie(UNI_IE_CONNEDSUB, (union uni_ieall *)&m->connedsub, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->uu); + else + ret |= uni_check_ie(UNI_IE_UU, (union uni_ieall *)&m->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->called_soft); + else + ret |= uni_check_ie(UNI_IE_CALLED_SOFT, (union uni_ieall *)&m->called_soft, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_add_party_ack(struct uni_msg *msg, struct uni_add_party_ack *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_ADD_PARTY_ACK, cx, &mlen)) + return (-2); + + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->aal.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_AAL, msg, (union uni_ieall *)&p->aal, cx)) + return (UNI_IE_AAL); + if((p->blli.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_BLLI, msg, (union uni_ieall *)&p->blli, cx)) + return (UNI_IE_BLLI); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + if((p->eetd.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EETD, msg, (union uni_ieall *)&p->eetd, cx)) + return (UNI_IE_EETD); + if((p->conned.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CONNED, msg, (union uni_ieall *)&p->conned, cx)) + return (UNI_IE_CONNED); + if((p->connedsub.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CONNEDSUB, msg, (union uni_ieall *)&p->connedsub, cx)) + return (UNI_IE_CONNEDSUB); + if((p->uu.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UU, msg, (union uni_ieall *)&p->uu, cx)) + return (UNI_IE_UU); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->called_soft.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLED_SOFT, msg, (union uni_ieall *)&p->called_soft, cx)) + return (UNI_IE_CALLED_SOFT); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_add_party_ack(struct uni_add_party_ack *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_AAL: + out->aal.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_AAL, (union uni_ieall *)&out->aal, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_BLLI: + out->blli.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_BLLI, (union uni_ieall *)&out->blli, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EETD: + out->eetd.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EETD, (union uni_ieall *)&out->eetd, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CONNED: + out->conned.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CONNED, (union uni_ieall *)&out->conned, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CONNEDSUB: + out->connedsub.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CONNEDSUB, (union uni_ieall *)&out->connedsub, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UU: + if (!(!cx->pnni)) + return (DEC_ILL); + out->uu.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UU, (union uni_ieall *)&out->uu, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_CALLED_SOFT: + if (!(cx->pnni)) + return (DEC_ILL); + out->called_soft.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLED_SOFT, (union uni_ieall *)&out->called_soft, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_add_party_ack = { + 0, + "add_party_ack", + (uni_msg_print_f)print_add_party_ack, + (uni_msg_check_f)check_add_party_ack, + (uni_msg_encode_f)encode_add_party_ack, + (uni_msg_decode_f)decode_add_party_ack +}; + +static void +print_party_alerting(struct uni_party_alerting *msg, struct unicx *cx) +{ + u_int i; + + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + if(msg->uu.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UU, (union uni_ieall *)&msg->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_party_alerting(struct uni_party_alerting *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->uu); + else + ret |= uni_check_ie(UNI_IE_UU, (union uni_ieall *)&m->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_party_alerting(struct uni_msg *msg, struct uni_party_alerting *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_PARTY_ALERTING, cx, &mlen)) + return (-2); + + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + if((p->uu.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UU, msg, (union uni_ieall *)&p->uu, cx)) + return (UNI_IE_UU); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_party_alerting(struct uni_party_alerting *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UU: + if (!(!cx->pnni)) + return (DEC_ILL); + out->uu.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UU, (union uni_ieall *)&out->uu, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_party_alerting = { + 0, + "party_alerting", + (uni_msg_print_f)print_party_alerting, + (uni_msg_check_f)check_party_alerting, + (uni_msg_encode_f)encode_party_alerting, + (uni_msg_decode_f)decode_party_alerting +}; + +static void +print_add_party_rej(struct uni_add_party_rej *msg, struct unicx *cx) +{ + u_int i; + + if(msg->cause.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CAUSE, (union uni_ieall *)&msg->cause, cx); + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->uu.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UU, (union uni_ieall *)&msg->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->crankback.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CRANKBACK, (union uni_ieall *)&msg->crankback, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_add_party_rej(struct uni_add_party_rej *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_CAUSE, (union uni_ieall *)&m->cause, cx); + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->uu); + else + ret |= uni_check_ie(UNI_IE_UU, (union uni_ieall *)&m->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + if(!(cx->pnni)) + ret |= IE_ISPRESENT(m->crankback); + else + ret |= uni_check_ie(UNI_IE_CRANKBACK, (union uni_ieall *)&m->crankback, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_add_party_rej(struct uni_msg *msg, struct uni_add_party_rej *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_ADD_PARTY_REJ, cx, &mlen)) + return (-2); + + if((p->cause.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CAUSE, msg, (union uni_ieall *)&p->cause, cx)) + return (UNI_IE_CAUSE); + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->uu.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UU, msg, (union uni_ieall *)&p->uu, cx)) + return (UNI_IE_UU); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->crankback.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CRANKBACK, msg, (union uni_ieall *)&p->crankback, cx)) + return (UNI_IE_CRANKBACK); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_add_party_rej(struct uni_add_party_rej *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_CAUSE: + out->cause.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CAUSE, (union uni_ieall *)&out->cause, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UU: + if (!(!cx->pnni)) + return (DEC_ILL); + out->uu.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UU, (union uni_ieall *)&out->uu, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_CRANKBACK: + if (!(cx->pnni)) + return (DEC_ILL); + out->crankback.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CRANKBACK, (union uni_ieall *)&out->crankback, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_add_party_rej = { + 0, + "add_party_rej", + (uni_msg_print_f)print_add_party_rej, + (uni_msg_check_f)check_add_party_rej, + (uni_msg_encode_f)encode_add_party_rej, + (uni_msg_decode_f)decode_add_party_rej +}; + +static void +print_drop_party(struct uni_drop_party *msg, struct unicx *cx) +{ + u_int i; + + if(msg->cause.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CAUSE, (union uni_ieall *)&msg->cause, cx); + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + if(msg->uu.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UU, (union uni_ieall *)&msg->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_drop_party(struct uni_drop_party *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_CAUSE, (union uni_ieall *)&m->cause, cx); + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->uu); + else + ret |= uni_check_ie(UNI_IE_UU, (union uni_ieall *)&m->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_drop_party(struct uni_msg *msg, struct uni_drop_party *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_DROP_PARTY, cx, &mlen)) + return (-2); + + if((p->cause.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CAUSE, msg, (union uni_ieall *)&p->cause, cx)) + return (UNI_IE_CAUSE); + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + if((p->uu.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UU, msg, (union uni_ieall *)&p->uu, cx)) + return (UNI_IE_UU); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_drop_party(struct uni_drop_party *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_CAUSE: + out->cause.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CAUSE, (union uni_ieall *)&out->cause, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UU: + if (!(!cx->pnni)) + return (DEC_ILL); + out->uu.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UU, (union uni_ieall *)&out->uu, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_drop_party = { + 0, + "drop_party", + (uni_msg_print_f)print_drop_party, + (uni_msg_check_f)check_drop_party, + (uni_msg_encode_f)encode_drop_party, + (uni_msg_decode_f)decode_drop_party +}; + +static void +print_drop_party_ack(struct uni_drop_party_ack *msg, struct unicx *cx) +{ + u_int i; + + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->cause.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CAUSE, (union uni_ieall *)&msg->cause, cx); + if(msg->uu.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UU, (union uni_ieall *)&msg->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_drop_party_ack(struct uni_drop_party_ack *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_CAUSE, (union uni_ieall *)&m->cause, cx); + if(!(!cx->pnni)) + ret |= IE_ISPRESENT(m->uu); + else + ret |= uni_check_ie(UNI_IE_UU, (union uni_ieall *)&m->uu, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_drop_party_ack(struct uni_msg *msg, struct uni_drop_party_ack *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_DROP_PARTY_ACK, cx, &mlen)) + return (-2); + + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->cause.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CAUSE, msg, (union uni_ieall *)&p->cause, cx)) + return (UNI_IE_CAUSE); + if((p->uu.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UU, msg, (union uni_ieall *)&p->uu, cx)) + return (UNI_IE_UU); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_drop_party_ack(struct uni_drop_party_ack *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CAUSE: + out->cause.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CAUSE, (union uni_ieall *)&out->cause, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UU: + if (!(!cx->pnni)) + return (DEC_ILL); + out->uu.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UU, (union uni_ieall *)&out->uu, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_drop_party_ack = { + 0, + "drop_party_ack", + (uni_msg_print_f)print_drop_party_ack, + (uni_msg_check_f)check_drop_party_ack, + (uni_msg_encode_f)encode_drop_party_ack, + (uni_msg_decode_f)decode_drop_party_ack +}; + +static void +print_leaf_setup_req(struct uni_leaf_setup_req *msg, struct unicx *cx) +{ + u_int i; + + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if(msg->tns[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_TNS, (union uni_ieall *)&msg->tns[i], cx); + if(msg->calling.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLING, (union uni_ieall *)&msg->calling, cx); + for(i = 0; i < UNI_NUM_IE_CALLINGSUB; i++) + if(msg->callingsub[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLINGSUB, (union uni_ieall *)&msg->callingsub[i], cx); + if(msg->called.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLED, (union uni_ieall *)&msg->called, cx); + for(i = 0; i < UNI_NUM_IE_CALLEDSUB; i++) + if(msg->calledsub[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLEDSUB, (union uni_ieall *)&msg->calledsub[i], cx); + if(msg->lij_callid.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_LIJ_CALLID, (union uni_ieall *)&msg->lij_callid, cx); + if(msg->lij_seqno.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&msg->lij_seqno, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_leaf_setup_req(struct uni_leaf_setup_req *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + for(i = 0; i < UNI_NUM_IE_TNS ; i++) { + ret |= uni_check_ie(UNI_IE_TNS, (union uni_ieall *)&m->tns[i], cx); + } + ret |= uni_check_ie(UNI_IE_CALLING, (union uni_ieall *)&m->calling, cx); + for(i = 0; i < UNI_NUM_IE_CALLINGSUB ; i++) { + ret |= uni_check_ie(UNI_IE_CALLINGSUB, (union uni_ieall *)&m->callingsub[i], cx); + } + ret |= uni_check_ie(UNI_IE_CALLED, (union uni_ieall *)&m->called, cx); + for(i = 0; i < UNI_NUM_IE_CALLEDSUB ; i++) { + ret |= uni_check_ie(UNI_IE_CALLEDSUB, (union uni_ieall *)&m->calledsub[i], cx); + } + ret |= uni_check_ie(UNI_IE_LIJ_CALLID, (union uni_ieall *)&m->lij_callid, cx); + ret |= uni_check_ie(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&m->lij_seqno, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_leaf_setup_req(struct uni_msg *msg, struct uni_leaf_setup_req *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_LEAF_SETUP_REQ, cx, &mlen)) + return (-2); + + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if((p->tns[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_TNS, msg, (union uni_ieall *)&p->tns[i], cx)) + return ((i << 16) + UNI_IE_TNS); + if((p->calling.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLING, msg, (union uni_ieall *)&p->calling, cx)) + return (UNI_IE_CALLING); + for(i = 0; i < UNI_NUM_IE_CALLINGSUB; i++) + if((p->callingsub[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLINGSUB, msg, (union uni_ieall *)&p->callingsub[i], cx)) + return ((i << 16) + UNI_IE_CALLINGSUB); + if((p->called.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLED, msg, (union uni_ieall *)&p->called, cx)) + return (UNI_IE_CALLED); + for(i = 0; i < UNI_NUM_IE_CALLEDSUB; i++) + if((p->calledsub[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLEDSUB, msg, (union uni_ieall *)&p->calledsub[i], cx)) + return ((i << 16) + UNI_IE_CALLEDSUB); + if((p->lij_callid.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_LIJ_CALLID, msg, (union uni_ieall *)&p->lij_callid, cx)) + return (UNI_IE_LIJ_CALLID); + if((p->lij_seqno.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_LIJ_SEQNO, msg, (union uni_ieall *)&p->lij_seqno, cx)) + return (UNI_IE_LIJ_SEQNO); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_leaf_setup_req(struct uni_leaf_setup_req *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_TNS: + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if (!IE_ISPRESENT(out->tns[i])) { + out->tns[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_TNS, (union uni_ieall *)&out->tns[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_CALLING: + out->calling.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLING, (union uni_ieall *)&out->calling, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLINGSUB: + for(i = 0; i < UNI_NUM_IE_CALLINGSUB; i++) + if (!IE_ISPRESENT(out->callingsub[i])) { + out->callingsub[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLINGSUB, (union uni_ieall *)&out->callingsub[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_CALLED: + out->called.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLED, (union uni_ieall *)&out->called, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLEDSUB: + for(i = 0; i < UNI_NUM_IE_CALLEDSUB; i++) + if (!IE_ISPRESENT(out->calledsub[i])) { + out->calledsub[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLEDSUB, (union uni_ieall *)&out->calledsub[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_LIJ_CALLID: + out->lij_callid.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_LIJ_CALLID, (union uni_ieall *)&out->lij_callid, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_LIJ_SEQNO: + out->lij_seqno.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&out->lij_seqno, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_leaf_setup_req = { + 0, + "leaf_setup_req", + (uni_msg_print_f)print_leaf_setup_req, + (uni_msg_check_f)check_leaf_setup_req, + (uni_msg_encode_f)encode_leaf_setup_req, + (uni_msg_decode_f)decode_leaf_setup_req +}; + +static void +print_leaf_setup_fail(struct uni_leaf_setup_fail *msg, struct unicx *cx) +{ + u_int i; + + if(msg->cause.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CAUSE, (union uni_ieall *)&msg->cause, cx); + if(msg->called.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLED, (union uni_ieall *)&msg->called, cx); + if(msg->calledsub.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLEDSUB, (union uni_ieall *)&msg->calledsub, cx); + if(msg->lij_seqno.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&msg->lij_seqno, cx); + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if(msg->tns[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_TNS, (union uni_ieall *)&msg->tns[i], cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_leaf_setup_fail(struct uni_leaf_setup_fail *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_CAUSE, (union uni_ieall *)&m->cause, cx); + ret |= uni_check_ie(UNI_IE_CALLED, (union uni_ieall *)&m->called, cx); + ret |= uni_check_ie(UNI_IE_CALLEDSUB, (union uni_ieall *)&m->calledsub, cx); + ret |= uni_check_ie(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&m->lij_seqno, cx); + for(i = 0; i < UNI_NUM_IE_TNS ; i++) { + ret |= uni_check_ie(UNI_IE_TNS, (union uni_ieall *)&m->tns[i], cx); + } + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_leaf_setup_fail(struct uni_msg *msg, struct uni_leaf_setup_fail *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_LEAF_SETUP_FAIL, cx, &mlen)) + return (-2); + + if((p->cause.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CAUSE, msg, (union uni_ieall *)&p->cause, cx)) + return (UNI_IE_CAUSE); + if((p->called.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLED, msg, (union uni_ieall *)&p->called, cx)) + return (UNI_IE_CALLED); + if((p->calledsub.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLEDSUB, msg, (union uni_ieall *)&p->calledsub, cx)) + return (UNI_IE_CALLEDSUB); + if((p->lij_seqno.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_LIJ_SEQNO, msg, (union uni_ieall *)&p->lij_seqno, cx)) + return (UNI_IE_LIJ_SEQNO); + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if((p->tns[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_TNS, msg, (union uni_ieall *)&p->tns[i], cx)) + return ((i << 16) + UNI_IE_TNS); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_leaf_setup_fail(struct uni_leaf_setup_fail *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_CAUSE: + out->cause.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CAUSE, (union uni_ieall *)&out->cause, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLED: + out->called.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLED, (union uni_ieall *)&out->called, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLEDSUB: + out->calledsub.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLEDSUB, (union uni_ieall *)&out->calledsub, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_LIJ_SEQNO: + out->lij_seqno.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_LIJ_SEQNO, (union uni_ieall *)&out->lij_seqno, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_TNS: + for(i = 0; i < UNI_NUM_IE_TNS; i++) + if (!IE_ISPRESENT(out->tns[i])) { + out->tns[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_TNS, (union uni_ieall *)&out->tns[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_leaf_setup_fail = { + 0, + "leaf_setup_fail", + (uni_msg_print_f)print_leaf_setup_fail, + (uni_msg_check_f)check_leaf_setup_fail, + (uni_msg_encode_f)encode_leaf_setup_fail, + (uni_msg_decode_f)decode_leaf_setup_fail +}; + +static void +print_cobisetup(struct uni_cobisetup *msg, struct unicx *cx) +{ + if(msg->facility.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_FACILITY, (union uni_ieall *)&msg->facility, cx); + if(msg->called.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLED, (union uni_ieall *)&msg->called, cx); + if(msg->calledsub.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLEDSUB, (union uni_ieall *)&msg->calledsub, cx); + if(msg->calling.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLING, (union uni_ieall *)&msg->calling, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_cobisetup(struct uni_cobisetup *m, struct unicx *cx) +{ + int ret = 0; + + ret |= uni_check_ie(UNI_IE_FACILITY, (union uni_ieall *)&m->facility, cx); + ret |= uni_check_ie(UNI_IE_CALLED, (union uni_ieall *)&m->called, cx); + ret |= uni_check_ie(UNI_IE_CALLEDSUB, (union uni_ieall *)&m->calledsub, cx); + ret |= uni_check_ie(UNI_IE_CALLING, (union uni_ieall *)&m->calling, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_cobisetup(struct uni_msg *msg, struct uni_cobisetup *p, struct unicx *cx) +{ + u_int mlen; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_COBISETUP, cx, &mlen)) + return (-2); + + if((p->facility.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_FACILITY, msg, (union uni_ieall *)&p->facility, cx)) + return (UNI_IE_FACILITY); + if((p->called.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLED, msg, (union uni_ieall *)&p->called, cx)) + return (UNI_IE_CALLED); + if((p->calledsub.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLEDSUB, msg, (union uni_ieall *)&p->calledsub, cx)) + return (UNI_IE_CALLEDSUB); + if((p->calling.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLING, msg, (union uni_ieall *)&p->calling, cx)) + return (UNI_IE_CALLING); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_cobisetup(struct uni_cobisetup *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + switch (ie) { + + case UNI_IE_FACILITY: + out->facility.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_FACILITY, (union uni_ieall *)&out->facility, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLED: + out->called.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLED, (union uni_ieall *)&out->called, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLEDSUB: + out->calledsub.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLEDSUB, (union uni_ieall *)&out->calledsub, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLING: + out->calling.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLING, (union uni_ieall *)&out->calling, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_cobisetup = { + 0, + "cobisetup", + (uni_msg_print_f)print_cobisetup, + (uni_msg_check_f)check_cobisetup, + (uni_msg_encode_f)encode_cobisetup, + (uni_msg_decode_f)decode_cobisetup +}; + +static void +print_facility(struct uni_facility *msg, struct unicx *cx) +{ + if(msg->facility.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_FACILITY, (union uni_ieall *)&msg->facility, cx); + if(msg->called.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLED, (union uni_ieall *)&msg->called, cx); + if(msg->calledsub.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLEDSUB, (union uni_ieall *)&msg->calledsub, cx); + if(msg->calling.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CALLING, (union uni_ieall *)&msg->calling, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_facility(struct uni_facility *m, struct unicx *cx) +{ + int ret = 0; + + ret |= uni_check_ie(UNI_IE_FACILITY, (union uni_ieall *)&m->facility, cx); + ret |= uni_check_ie(UNI_IE_CALLED, (union uni_ieall *)&m->called, cx); + ret |= uni_check_ie(UNI_IE_CALLEDSUB, (union uni_ieall *)&m->calledsub, cx); + ret |= uni_check_ie(UNI_IE_CALLING, (union uni_ieall *)&m->calling, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_facility(struct uni_msg *msg, struct uni_facility *p, struct unicx *cx) +{ + u_int mlen; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_FACILITY, cx, &mlen)) + return (-2); + + if((p->facility.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_FACILITY, msg, (union uni_ieall *)&p->facility, cx)) + return (UNI_IE_FACILITY); + if((p->called.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLED, msg, (union uni_ieall *)&p->called, cx)) + return (UNI_IE_CALLED); + if((p->calledsub.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLEDSUB, msg, (union uni_ieall *)&p->calledsub, cx)) + return (UNI_IE_CALLEDSUB); + if((p->calling.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CALLING, msg, (union uni_ieall *)&p->calling, cx)) + return (UNI_IE_CALLING); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_facility(struct uni_facility *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + switch (ie) { + + case UNI_IE_FACILITY: + out->facility.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_FACILITY, (union uni_ieall *)&out->facility, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLED: + out->called.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLED, (union uni_ieall *)&out->called, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLEDSUB: + out->calledsub.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLEDSUB, (union uni_ieall *)&out->calledsub, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_CALLING: + out->calling.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CALLING, (union uni_ieall *)&out->calling, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_facility = { + 0, + "facility", + (uni_msg_print_f)print_facility, + (uni_msg_check_f)check_facility, + (uni_msg_encode_f)encode_facility, + (uni_msg_decode_f)decode_facility +}; + +static void +print_modify_req(struct uni_modify_req *msg, struct unicx *cx) +{ + u_int i; + + if(msg->traffic.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_TRAFFIC, (union uni_ieall *)&msg->traffic, cx); + if(msg->atraffic.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_ATRAFFIC, (union uni_ieall *)&msg->atraffic, cx); + if(msg->mintraffic.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_MINTRAFFIC, (union uni_ieall *)&msg->mintraffic, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_modify_req(struct uni_modify_req *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_TRAFFIC, (union uni_ieall *)&m->traffic, cx); + ret |= uni_check_ie(UNI_IE_ATRAFFIC, (union uni_ieall *)&m->atraffic, cx); + ret |= uni_check_ie(UNI_IE_MINTRAFFIC, (union uni_ieall *)&m->mintraffic, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_modify_req(struct uni_msg *msg, struct uni_modify_req *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_MODIFY_REQ, cx, &mlen)) + return (-2); + + if((p->traffic.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_TRAFFIC, msg, (union uni_ieall *)&p->traffic, cx)) + return (UNI_IE_TRAFFIC); + if((p->atraffic.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_ATRAFFIC, msg, (union uni_ieall *)&p->atraffic, cx)) + return (UNI_IE_ATRAFFIC); + if((p->mintraffic.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_MINTRAFFIC, msg, (union uni_ieall *)&p->mintraffic, cx)) + return (UNI_IE_MINTRAFFIC); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_modify_req(struct uni_modify_req *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_TRAFFIC: + out->traffic.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_TRAFFIC, (union uni_ieall *)&out->traffic, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_ATRAFFIC: + out->atraffic.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_ATRAFFIC, (union uni_ieall *)&out->atraffic, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_MINTRAFFIC: + out->mintraffic.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_MINTRAFFIC, (union uni_ieall *)&out->mintraffic, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_modify_req = { + 0, + "modify_req", + (uni_msg_print_f)print_modify_req, + (uni_msg_check_f)check_modify_req, + (uni_msg_encode_f)encode_modify_req, + (uni_msg_decode_f)decode_modify_req +}; + +static void +print_modify_ack(struct uni_modify_ack *msg, struct unicx *cx) +{ + u_int i; + + if(msg->report.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_REPORT, (union uni_ieall *)&msg->report, cx); + if(msg->traffic.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_TRAFFIC, (union uni_ieall *)&msg->traffic, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_modify_ack(struct uni_modify_ack *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_REPORT, (union uni_ieall *)&m->report, cx); + ret |= uni_check_ie(UNI_IE_TRAFFIC, (union uni_ieall *)&m->traffic, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_modify_ack(struct uni_msg *msg, struct uni_modify_ack *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_MODIFY_ACK, cx, &mlen)) + return (-2); + + if((p->report.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_REPORT, msg, (union uni_ieall *)&p->report, cx)) + return (UNI_IE_REPORT); + if((p->traffic.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_TRAFFIC, msg, (union uni_ieall *)&p->traffic, cx)) + return (UNI_IE_TRAFFIC); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_modify_ack(struct uni_modify_ack *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_REPORT: + out->report.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_REPORT, (union uni_ieall *)&out->report, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_TRAFFIC: + out->traffic.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_TRAFFIC, (union uni_ieall *)&out->traffic, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_modify_ack = { + 0, + "modify_ack", + (uni_msg_print_f)print_modify_ack, + (uni_msg_check_f)check_modify_ack, + (uni_msg_encode_f)encode_modify_ack, + (uni_msg_decode_f)decode_modify_ack +}; + +static void +print_modify_rej(struct uni_modify_rej *msg, struct unicx *cx) +{ + u_int i; + + if(msg->cause.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_CAUSE, (union uni_ieall *)&msg->cause, cx); + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_modify_rej(struct uni_modify_rej *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_CAUSE, (union uni_ieall *)&m->cause, cx); + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_modify_rej(struct uni_msg *msg, struct uni_modify_rej *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_MODIFY_REJ, cx, &mlen)) + return (-2); + + if((p->cause.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_CAUSE, msg, (union uni_ieall *)&p->cause, cx)) + return (UNI_IE_CAUSE); + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_modify_rej(struct uni_modify_rej *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_CAUSE: + out->cause.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_CAUSE, (union uni_ieall *)&out->cause, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_modify_rej = { + 0, + "modify_rej", + (uni_msg_print_f)print_modify_rej, + (uni_msg_check_f)check_modify_rej, + (uni_msg_encode_f)encode_modify_rej, + (uni_msg_decode_f)decode_modify_rej +}; + +static void +print_conn_avail(struct uni_conn_avail *msg, struct unicx *cx) +{ + u_int i; + + if(msg->notify.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_NOTIFY, (union uni_ieall *)&msg->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if(msg->git[i].h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_GIT, (union uni_ieall *)&msg->git[i], cx); + if(msg->report.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_REPORT, (union uni_ieall *)&msg->report, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_conn_avail(struct uni_conn_avail *m, struct unicx *cx) +{ + int ret = 0; + u_int i; + + ret |= uni_check_ie(UNI_IE_NOTIFY, (union uni_ieall *)&m->notify, cx); + for(i = 0; i < UNI_NUM_IE_GIT ; i++) { + ret |= uni_check_ie(UNI_IE_GIT, (union uni_ieall *)&m->git[i], cx); + } + ret |= uni_check_ie(UNI_IE_REPORT, (union uni_ieall *)&m->report, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_conn_avail(struct uni_msg *msg, struct uni_conn_avail *p, struct unicx *cx) +{ + u_int mlen; + u_int i; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_CONN_AVAIL, cx, &mlen)) + return (-2); + + if((p->notify.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_NOTIFY, msg, (union uni_ieall *)&p->notify, cx)) + return (UNI_IE_NOTIFY); + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if((p->git[i].h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_GIT, msg, (union uni_ieall *)&p->git[i], cx)) + return ((i << 16) + UNI_IE_GIT); + if((p->report.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_REPORT, msg, (union uni_ieall *)&p->report, cx)) + return (UNI_IE_REPORT); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_conn_avail(struct uni_conn_avail *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + u_int i; + + switch (ie) { + + case UNI_IE_NOTIFY: + out->notify.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_NOTIFY, (union uni_ieall *)&out->notify, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_GIT: + for(i = 0; i < UNI_NUM_IE_GIT; i++) + if (!IE_ISPRESENT(out->git[i])) { + out->git[i].h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_GIT, (union uni_ieall *)&out->git[i], msg, ielen, cx)) + return (DEC_ERR); + break; + } + break; + + case UNI_IE_REPORT: + out->report.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_REPORT, (union uni_ieall *)&out->report, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_conn_avail = { + 0, + "conn_avail", + (uni_msg_print_f)print_conn_avail, + (uni_msg_check_f)check_conn_avail, + (uni_msg_encode_f)encode_conn_avail, + (uni_msg_decode_f)decode_conn_avail +}; + +static void +print_unknown(struct uni_unknown *msg, struct unicx *cx) +{ + if(msg->epref.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_EPREF, (union uni_ieall *)&msg->epref, cx); + if(msg->unrec.h.present & UNI_IE_PRESENT) + uni_print_ie_internal(UNI_IE_UNREC, (union uni_ieall *)&msg->unrec, cx); +} + +static int +check_unknown(struct uni_unknown *m, struct unicx *cx) +{ + int ret = 0; + + ret |= uni_check_ie(UNI_IE_EPREF, (union uni_ieall *)&m->epref, cx); + ret |= uni_check_ie(UNI_IE_UNREC, (union uni_ieall *)&m->unrec, cx); + + return ret; +} + +static int +encode_unknown(struct uni_msg *msg, struct uni_unknown *p, struct unicx *cx) +{ + u_int mlen; + + if(uni_encode_msg_hdr(msg, &p->hdr, UNI_UNKNOWN, cx, &mlen)) + return (-2); + + if((p->epref.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_EPREF, msg, (union uni_ieall *)&p->epref, cx)) + return (UNI_IE_EPREF); + if((p->unrec.h.present & UNI_IE_PRESENT) && + uni_encode_ie(UNI_IE_UNREC, msg, (union uni_ieall *)&p->unrec, cx)) + return (UNI_IE_UNREC); + + msg->b_buf[mlen+0] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 8; + msg->b_buf[mlen+1] = ((msg->b_wptr-msg->b_rptr)-mlen-2) >> 0; + + return (0); +} + +static int +decode_unknown(struct uni_unknown *out, struct uni_msg *msg, + enum uni_ietype ie, struct uni_iehdr *hdr, u_int ielen, + struct unicx *cx) +{ + switch (ie) { + + case UNI_IE_EPREF: + out->epref.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_EPREF, (union uni_ieall *)&out->epref, msg, ielen, cx)) + return (DEC_ERR); + break; + + case UNI_IE_UNREC: + out->unrec.h = *hdr; + if (hdr->present & UNI_IE_ERROR) + return (DEC_ERR); + if(uni_decode_ie_body(UNI_IE_UNREC, (union uni_ieall *)&out->unrec, msg, ielen, cx)) + return (DEC_ERR); + break; + + default: + return (DEC_ILL); + } + return (DEC_OK); +} + +static const struct msgdecl decl_unknown = { + 0, + "unknown", + (uni_msg_print_f)print_unknown, + (uni_msg_check_f)check_unknown, + (uni_msg_encode_f)encode_unknown, + (uni_msg_decode_f)decode_unknown +}; + +const struct msgdecl *uni_msgtable[256] = { + &decl_unknown, /* 0x00 */ + &decl_alerting, /* 0x01 */ + &decl_call_proc, /* 0x02 */ + &decl_unknown, /* 0x03 */ + &decl_unknown, /* 0x04 */ + &decl_setup, /* 0x05 */ + &decl_unknown, /* 0x06 */ + &decl_connect, /* 0x07 */ + &decl_unknown, /* 0x08 */ + &decl_unknown, /* 0x09 */ + &decl_unknown, /* 0x0a */ + &decl_unknown, /* 0x0b */ + &decl_unknown, /* 0x0c */ + &decl_unknown, /* 0x0d */ + &decl_unknown, /* 0x0e */ + &decl_connect_ack, /* 0x0f */ + &decl_unknown, /* 0x10 */ + &decl_unknown, /* 0x11 */ + &decl_unknown, /* 0x12 */ + &decl_unknown, /* 0x13 */ + &decl_unknown, /* 0x14 */ + &decl_cobisetup, /* 0x15 */ + &decl_unknown, /* 0x16 */ + &decl_unknown, /* 0x17 */ + &decl_unknown, /* 0x18 */ + &decl_unknown, /* 0x19 */ + &decl_unknown, /* 0x1a */ + &decl_unknown, /* 0x1b */ + &decl_unknown, /* 0x1c */ + &decl_unknown, /* 0x1d */ + &decl_unknown, /* 0x1e */ + &decl_unknown, /* 0x1f */ + &decl_unknown, /* 0x20 */ + &decl_unknown, /* 0x21 */ + &decl_unknown, /* 0x22 */ + &decl_unknown, /* 0x23 */ + &decl_unknown, /* 0x24 */ + &decl_unknown, /* 0x25 */ + &decl_unknown, /* 0x26 */ + &decl_unknown, /* 0x27 */ + &decl_unknown, /* 0x28 */ + &decl_unknown, /* 0x29 */ + &decl_unknown, /* 0x2a */ + &decl_unknown, /* 0x2b */ + &decl_unknown, /* 0x2c */ + &decl_unknown, /* 0x2d */ + &decl_unknown, /* 0x2e */ + &decl_unknown, /* 0x2f */ + &decl_unknown, /* 0x30 */ + &decl_unknown, /* 0x31 */ + &decl_unknown, /* 0x32 */ + &decl_unknown, /* 0x33 */ + &decl_unknown, /* 0x34 */ + &decl_unknown, /* 0x35 */ + &decl_unknown, /* 0x36 */ + &decl_unknown, /* 0x37 */ + &decl_unknown, /* 0x38 */ + &decl_unknown, /* 0x39 */ + &decl_unknown, /* 0x3a */ + &decl_unknown, /* 0x3b */ + &decl_unknown, /* 0x3c */ + &decl_unknown, /* 0x3d */ + &decl_unknown, /* 0x3e */ + &decl_unknown, /* 0x3f */ + &decl_unknown, /* 0x40 */ + &decl_unknown, /* 0x41 */ + &decl_unknown, /* 0x42 */ + &decl_unknown, /* 0x43 */ + &decl_unknown, /* 0x44 */ + &decl_unknown, /* 0x45 */ + &decl_restart, /* 0x46 */ + &decl_unknown, /* 0x47 */ + &decl_unknown, /* 0x48 */ + &decl_unknown, /* 0x49 */ + &decl_unknown, /* 0x4a */ + &decl_unknown, /* 0x4b */ + &decl_unknown, /* 0x4c */ + &decl_release, /* 0x4d */ + &decl_restart_ack, /* 0x4e */ + &decl_unknown, /* 0x4f */ + &decl_unknown, /* 0x50 */ + &decl_unknown, /* 0x51 */ + &decl_unknown, /* 0x52 */ + &decl_unknown, /* 0x53 */ + &decl_unknown, /* 0x54 */ + &decl_unknown, /* 0x55 */ + &decl_unknown, /* 0x56 */ + &decl_unknown, /* 0x57 */ + &decl_unknown, /* 0x58 */ + &decl_unknown, /* 0x59 */ + &decl_release_compl, /* 0x5a */ + &decl_unknown, /* 0x5b */ + &decl_unknown, /* 0x5c */ + &decl_unknown, /* 0x5d */ + &decl_unknown, /* 0x5e */ + &decl_unknown, /* 0x5f */ + &decl_unknown, /* 0x60 */ + &decl_unknown, /* 0x61 */ + &decl_facility, /* 0x62 */ + &decl_unknown, /* 0x63 */ + &decl_unknown, /* 0x64 */ + &decl_unknown, /* 0x65 */ + &decl_unknown, /* 0x66 */ + &decl_unknown, /* 0x67 */ + &decl_unknown, /* 0x68 */ + &decl_unknown, /* 0x69 */ + &decl_unknown, /* 0x6a */ + &decl_unknown, /* 0x6b */ + &decl_unknown, /* 0x6c */ + &decl_unknown, /* 0x6d */ + &decl_notify, /* 0x6e */ + &decl_unknown, /* 0x6f */ + &decl_unknown, /* 0x70 */ + &decl_unknown, /* 0x71 */ + &decl_unknown, /* 0x72 */ + &decl_unknown, /* 0x73 */ + &decl_unknown, /* 0x74 */ + &decl_status_enq, /* 0x75 */ + &decl_unknown, /* 0x76 */ + &decl_unknown, /* 0x77 */ + &decl_unknown, /* 0x78 */ + &decl_unknown, /* 0x79 */ + &decl_unknown, /* 0x7a */ + &decl_unknown, /* 0x7b */ + &decl_unknown, /* 0x7c */ + &decl_status, /* 0x7d */ + &decl_unknown, /* 0x7e */ + &decl_unknown, /* 0x7f */ + &decl_add_party, /* 0x80 */ + &decl_add_party_ack, /* 0x81 */ + &decl_add_party_rej, /* 0x82 */ + &decl_drop_party, /* 0x83 */ + &decl_drop_party_ack, /* 0x84 */ + &decl_party_alerting, /* 0x85 */ + &decl_unknown, /* 0x86 */ + &decl_unknown, /* 0x87 */ + &decl_modify_req, /* 0x88 */ + &decl_modify_ack, /* 0x89 */ + &decl_modify_rej, /* 0x8a */ + &decl_conn_avail, /* 0x8b */ + &decl_unknown, /* 0x8c */ + &decl_unknown, /* 0x8d */ + &decl_unknown, /* 0x8e */ + &decl_unknown, /* 0x8f */ + &decl_leaf_setup_fail, /* 0x90 */ + &decl_leaf_setup_req, /* 0x91 */ + &decl_unknown, /* 0x92 */ + &decl_unknown, /* 0x93 */ + &decl_unknown, /* 0x94 */ + &decl_unknown, /* 0x95 */ + &decl_unknown, /* 0x96 */ + &decl_unknown, /* 0x97 */ + &decl_unknown, /* 0x98 */ + &decl_unknown, /* 0x99 */ + &decl_unknown, /* 0x9a */ + &decl_unknown, /* 0x9b */ + &decl_unknown, /* 0x9c */ + &decl_unknown, /* 0x9d */ + &decl_unknown, /* 0x9e */ + &decl_unknown, /* 0x9f */ + &decl_unknown, /* 0xa0 */ + &decl_unknown, /* 0xa1 */ + &decl_unknown, /* 0xa2 */ + &decl_unknown, /* 0xa3 */ + &decl_unknown, /* 0xa4 */ + &decl_unknown, /* 0xa5 */ + &decl_unknown, /* 0xa6 */ + &decl_unknown, /* 0xa7 */ + &decl_unknown, /* 0xa8 */ + &decl_unknown, /* 0xa9 */ + &decl_unknown, /* 0xaa */ + &decl_unknown, /* 0xab */ + &decl_unknown, /* 0xac */ + &decl_unknown, /* 0xad */ + &decl_unknown, /* 0xae */ + &decl_unknown, /* 0xaf */ + &decl_unknown, /* 0xb0 */ + &decl_unknown, /* 0xb1 */ + &decl_unknown, /* 0xb2 */ + &decl_unknown, /* 0xb3 */ + &decl_unknown, /* 0xb4 */ + &decl_unknown, /* 0xb5 */ + &decl_unknown, /* 0xb6 */ + &decl_unknown, /* 0xb7 */ + &decl_unknown, /* 0xb8 */ + &decl_unknown, /* 0xb9 */ + &decl_unknown, /* 0xba */ + &decl_unknown, /* 0xbb */ + &decl_unknown, /* 0xbc */ + &decl_unknown, /* 0xbd */ + &decl_unknown, /* 0xbe */ + &decl_unknown, /* 0xbf */ + &decl_unknown, /* 0xc0 */ + &decl_unknown, /* 0xc1 */ + &decl_unknown, /* 0xc2 */ + &decl_unknown, /* 0xc3 */ + &decl_unknown, /* 0xc4 */ + &decl_unknown, /* 0xc5 */ + &decl_unknown, /* 0xc6 */ + &decl_unknown, /* 0xc7 */ + &decl_unknown, /* 0xc8 */ + &decl_unknown, /* 0xc9 */ + &decl_unknown, /* 0xca */ + &decl_unknown, /* 0xcb */ + &decl_unknown, /* 0xcc */ + &decl_unknown, /* 0xcd */ + &decl_unknown, /* 0xce */ + &decl_unknown, /* 0xcf */ + &decl_unknown, /* 0xd0 */ + &decl_unknown, /* 0xd1 */ + &decl_unknown, /* 0xd2 */ + &decl_unknown, /* 0xd3 */ + &decl_unknown, /* 0xd4 */ + &decl_unknown, /* 0xd5 */ + &decl_unknown, /* 0xd6 */ + &decl_unknown, /* 0xd7 */ + &decl_unknown, /* 0xd8 */ + &decl_unknown, /* 0xd9 */ + &decl_unknown, /* 0xda */ + &decl_unknown, /* 0xdb */ + &decl_unknown, /* 0xdc */ + &decl_unknown, /* 0xdd */ + &decl_unknown, /* 0xde */ + &decl_unknown, /* 0xdf */ + &decl_unknown, /* 0xe0 */ + &decl_unknown, /* 0xe1 */ + &decl_unknown, /* 0xe2 */ + &decl_unknown, /* 0xe3 */ + &decl_unknown, /* 0xe4 */ + &decl_unknown, /* 0xe5 */ + &decl_unknown, /* 0xe6 */ + &decl_unknown, /* 0xe7 */ + &decl_unknown, /* 0xe8 */ + &decl_unknown, /* 0xe9 */ + &decl_unknown, /* 0xea */ + &decl_unknown, /* 0xeb */ + &decl_unknown, /* 0xec */ + &decl_unknown, /* 0xed */ + &decl_unknown, /* 0xee */ + &decl_unknown, /* 0xef */ + &decl_unknown, /* 0xf0 */ + &decl_unknown, /* 0xf1 */ + &decl_unknown, /* 0xf2 */ + &decl_unknown, /* 0xf3 */ + &decl_unknown, /* 0xf4 */ + &decl_unknown, /* 0xf5 */ + &decl_unknown, /* 0xf6 */ + &decl_unknown, /* 0xf7 */ + &decl_unknown, /* 0xf8 */ + &decl_unknown, /* 0xf9 */ + &decl_unknown, /* 0xfa */ + &decl_unknown, /* 0xfb */ + &decl_unknown, /* 0xfc */ + &decl_unknown, /* 0xfd */ + &decl_unknown, /* 0xfe */ + &decl_unknown, /* 0xff */ +}; diff --git a/sys/contrib/ngatm/netnatm/msg/uni_msg.h b/sys/contrib/ngatm/netnatm/msg/uni_msg.h new file mode 100644 index 000000000000..ddb095b612c5 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/uni_msg.h @@ -0,0 +1,342 @@ +/* This file was created automatically + * Source file: $Begemot: libunimsg/atm/msg/msg.def,v 1.3 2003/09/19 11:58:15 hbb Exp $ + * $FreeBSD$ + */ + +#ifndef _NETNATM_MSG_UNI_MSG_H_ +#define _NETNATM_MSG_UNI_MSG_H_ + +struct uni_alerting { + struct uni_msghdr hdr; + struct uni_ie_connid connid; + struct uni_ie_epref epref; + struct uni_ie_notify notify; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_uu uu; + struct uni_ie_report report; + struct uni_ie_unrec unrec; +}; + +struct uni_call_proc { + struct uni_msghdr hdr; + struct uni_ie_connid connid; + struct uni_ie_epref epref; + struct uni_ie_notify notify; + struct uni_ie_unrec unrec; +}; + +struct uni_connect { + struct uni_msghdr hdr; + struct uni_ie_aal aal; + struct uni_ie_blli blli; + struct uni_ie_connid connid; + struct uni_ie_epref epref; + struct uni_ie_notify notify; + struct uni_ie_conned conned; + struct uni_ie_connedsub connedsub; + struct uni_ie_eetd eetd; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_uu uu; + struct uni_ie_traffic traffic; + struct uni_ie_exqos exqos; + struct uni_ie_facility facility; + struct uni_ie_abrsetup abrsetup; + struct uni_ie_abradd abradd; + struct uni_ie_called_soft called_soft; + struct uni_ie_report report; + struct uni_ie_unrec unrec; +}; + +struct uni_connect_ack { + struct uni_msghdr hdr; + struct uni_ie_notify notify; + struct uni_ie_unrec unrec; +}; + +struct uni_release { + struct uni_msghdr hdr; + struct uni_ie_cause cause[2]; + struct uni_ie_notify notify; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_uu uu; + struct uni_ie_facility facility; + struct uni_ie_crankback crankback; + struct uni_ie_unrec unrec; +}; + +struct uni_release_compl { + struct uni_msghdr hdr; + struct uni_ie_cause cause[2]; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_uu uu; + struct uni_ie_crankback crankback; + struct uni_ie_unrec unrec; +}; + +struct uni_setup { + struct uni_msghdr hdr; + struct uni_ie_aal aal; + struct uni_ie_traffic traffic; + struct uni_ie_bearer bearer; + struct uni_ie_bhli bhli; + struct uni_ie_repeat blli_repeat; + struct uni_ie_blli blli[UNI_NUM_IE_BLLI]; + struct uni_ie_called called; + struct uni_ie_calledsub calledsub[UNI_NUM_IE_CALLEDSUB]; + struct uni_ie_calling calling; + struct uni_ie_callingsub callingsub[UNI_NUM_IE_CALLINGSUB]; + struct uni_ie_connid connid; + struct uni_ie_qos qos; + struct uni_ie_eetd eetd; + struct uni_ie_notify notify; + struct uni_ie_scompl scompl; + struct uni_ie_tns tns[UNI_NUM_IE_TNS]; + struct uni_ie_epref epref; + struct uni_ie_atraffic atraffic; + struct uni_ie_mintraffic mintraffic; + struct uni_ie_uu uu; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_lij_callid lij_callid; + struct uni_ie_lij_param lij_param; + struct uni_ie_lij_seqno lij_seqno; + struct uni_ie_exqos exqos; + struct uni_ie_abrsetup abrsetup; + struct uni_ie_abradd abradd; + struct uni_ie_cscope cscope; + struct uni_ie_calling_soft calling_soft; + struct uni_ie_called_soft called_soft; + struct uni_ie_repeat dtl_repeat; + struct uni_ie_dtl dtl[UNI_NUM_IE_DTL]; + struct uni_ie_report report; + struct uni_ie_mdcr mdcr; + struct uni_ie_unrec unrec; +}; + +struct uni_status { + struct uni_msghdr hdr; + struct uni_ie_callstate callstate; + struct uni_ie_cause cause; + struct uni_ie_epref epref; + struct uni_ie_epstate epstate; + struct uni_ie_unrec unrec; +}; + +struct uni_status_enq { + struct uni_msghdr hdr; + struct uni_ie_epref epref; + struct uni_ie_unrec unrec; +}; + +struct uni_notify { + struct uni_msghdr hdr; + struct uni_ie_notify notify; + struct uni_ie_epref epref; + struct uni_ie_unrec unrec; +}; + +struct uni_restart { + struct uni_msghdr hdr; + struct uni_ie_connid connid; + struct uni_ie_restart restart; + struct uni_ie_unrec unrec; +}; + +struct uni_restart_ack { + struct uni_msghdr hdr; + struct uni_ie_connid connid; + struct uni_ie_restart restart; + struct uni_ie_unrec unrec; +}; + +struct uni_add_party { + struct uni_msghdr hdr; + struct uni_ie_aal aal; + struct uni_ie_bhli bhli; + struct uni_ie_blli blli; + struct uni_ie_called called; + struct uni_ie_calledsub calledsub[UNI_NUM_IE_CALLEDSUB]; + struct uni_ie_calling calling; + struct uni_ie_callingsub callingsub[UNI_NUM_IE_CALLINGSUB]; + struct uni_ie_scompl scompl; + struct uni_ie_tns tns[UNI_NUM_IE_TNS]; + struct uni_ie_epref epref; + struct uni_ie_notify notify; + struct uni_ie_eetd eetd; + struct uni_ie_uu uu; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_lij_seqno lij_seqno; + struct uni_ie_calling_soft calling_soft; + struct uni_ie_called_soft called_soft; + struct uni_ie_repeat dtl_repeat; + struct uni_ie_dtl dtl[UNI_NUM_IE_DTL]; + struct uni_ie_unrec unrec; +}; + +struct uni_add_party_ack { + struct uni_msghdr hdr; + struct uni_ie_epref epref; + struct uni_ie_aal aal; + struct uni_ie_blli blli; + struct uni_ie_notify notify; + struct uni_ie_eetd eetd; + struct uni_ie_conned conned; + struct uni_ie_connedsub connedsub; + struct uni_ie_uu uu; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_called_soft called_soft; + struct uni_ie_unrec unrec; +}; + +struct uni_party_alerting { + struct uni_msghdr hdr; + struct uni_ie_epref epref; + struct uni_ie_notify notify; + struct uni_ie_uu uu; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_unrec unrec; +}; + +struct uni_add_party_rej { + struct uni_msghdr hdr; + struct uni_ie_cause cause; + struct uni_ie_epref epref; + struct uni_ie_uu uu; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_crankback crankback; + struct uni_ie_unrec unrec; +}; + +struct uni_drop_party { + struct uni_msghdr hdr; + struct uni_ie_cause cause; + struct uni_ie_epref epref; + struct uni_ie_notify notify; + struct uni_ie_uu uu; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_unrec unrec; +}; + +struct uni_drop_party_ack { + struct uni_msghdr hdr; + struct uni_ie_epref epref; + struct uni_ie_cause cause; + struct uni_ie_uu uu; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_unrec unrec; +}; + +struct uni_leaf_setup_req { + struct uni_msghdr hdr; + struct uni_ie_tns tns[UNI_NUM_IE_TNS]; + struct uni_ie_calling calling; + struct uni_ie_callingsub callingsub[UNI_NUM_IE_CALLINGSUB]; + struct uni_ie_called called; + struct uni_ie_calledsub calledsub[UNI_NUM_IE_CALLEDSUB]; + struct uni_ie_lij_callid lij_callid; + struct uni_ie_lij_seqno lij_seqno; + struct uni_ie_unrec unrec; +}; + +struct uni_leaf_setup_fail { + struct uni_msghdr hdr; + struct uni_ie_cause cause; + struct uni_ie_called called; + struct uni_ie_calledsub calledsub; + struct uni_ie_lij_seqno lij_seqno; + struct uni_ie_tns tns[UNI_NUM_IE_TNS]; + struct uni_ie_unrec unrec; +}; + +struct uni_cobisetup { + struct uni_msghdr hdr; + struct uni_ie_facility facility; + struct uni_ie_called called; + struct uni_ie_calledsub calledsub; + struct uni_ie_calling calling; + struct uni_ie_notify notify; + struct uni_ie_unrec unrec; +}; + +struct uni_facility { + struct uni_msghdr hdr; + struct uni_ie_facility facility; + struct uni_ie_called called; + struct uni_ie_calledsub calledsub; + struct uni_ie_calling calling; + struct uni_ie_notify notify; + struct uni_ie_unrec unrec; +}; + +struct uni_modify_req { + struct uni_msghdr hdr; + struct uni_ie_traffic traffic; + struct uni_ie_atraffic atraffic; + struct uni_ie_mintraffic mintraffic; + struct uni_ie_notify notify; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_unrec unrec; +}; + +struct uni_modify_ack { + struct uni_msghdr hdr; + struct uni_ie_report report; + struct uni_ie_traffic traffic; + struct uni_ie_notify notify; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_unrec unrec; +}; + +struct uni_modify_rej { + struct uni_msghdr hdr; + struct uni_ie_cause cause; + struct uni_ie_notify notify; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_unrec unrec; +}; + +struct uni_conn_avail { + struct uni_msghdr hdr; + struct uni_ie_notify notify; + struct uni_ie_git git[UNI_NUM_IE_GIT]; + struct uni_ie_report report; + struct uni_ie_unrec unrec; +}; + +struct uni_unknown { + struct uni_msghdr hdr; + struct uni_ie_epref epref; + struct uni_ie_unrec unrec; +}; + +union uni_msgall { + struct uni_msghdr hdr; + struct uni_alerting alerting; + struct uni_call_proc call_proc; + struct uni_connect connect; + struct uni_connect_ack connect_ack; /* !pnni */ + struct uni_release release; + struct uni_release_compl release_compl; + struct uni_setup setup; + struct uni_status status; + struct uni_status_enq status_enq; + struct uni_notify notify; + struct uni_restart restart; + struct uni_restart_ack restart_ack; + struct uni_add_party add_party; + struct uni_add_party_ack add_party_ack; + struct uni_party_alerting party_alerting; + struct uni_add_party_rej add_party_rej; + struct uni_drop_party drop_party; + struct uni_drop_party_ack drop_party_ack; + struct uni_leaf_setup_req leaf_setup_req; /* !pnni */ + struct uni_leaf_setup_fail leaf_setup_fail; /* !pnni */ + struct uni_cobisetup cobisetup; /* !pnni&&q2932 */ + struct uni_facility facility; /* !pnni&&q2932 */ + struct uni_modify_req modify_req; /* !pnni */ + struct uni_modify_ack modify_ack; /* !pnni */ + struct uni_modify_rej modify_rej; /* !pnni */ + struct uni_conn_avail conn_avail; /* !pnni */ + struct uni_unknown unknown; +}; + +#endif diff --git a/sys/contrib/ngatm/netnatm/msg/unimsglib.h b/sys/contrib/ngatm/netnatm/msg/unimsglib.h new file mode 100644 index 000000000000..f8489dbffc0c --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/unimsglib.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/msg/unimsglib.h,v 1.6 2004/07/08 08:22:07 brandt Exp $ + */ +#ifndef _NETNATM_MSG_UNIMSGLIB_H_ +#define _NETNATM_MSG_UNIMSGLIB_H_ + +#include <netnatm/msg/uni_config.h> + +struct uni_msg; + +enum uni_ierr_type { + UNI_IERR_UNK, /* unknown IE */ + UNI_IERR_LEN, /* length error */ + UNI_IERR_BAD, /* content error */ + UNI_IERR_ACC, /* access element content error */ + UNI_IERR_MIS, /* mandatory IE missing (not used here) */ +}; + +struct uni_ierr { + enum uni_ierr_type err; /* what error */ + enum uni_ieact act; /* the action indicator */ + u_int ie:8; /* the ie type */ + u_int man:1; /* mandatory flag */ + u_int epref:1;/* Q.2971 9.5.3.2.1 low-pri epref */ +}; + +/* + * Context buffer. Needed to reduce number of arguments to routines. + */ +struct unicx { + /* + * globals for error handling + */ + u_int errcnt; /* number of bad IEs */ + struct uni_ierr err[UNI_MAX_ERRIE]; /* the errors */ + + int q2932; /* Enable GFP */ + int pnni; /* Enable PNNI */ + + int git_hard; /* do hard check on GIT IE */ + int bearer_hard; /* do hard check on BEARER IE */ + int cause_hard; /* do hard check on cause */ + + int multiline; /* printing mode */ + u_int tabsiz; /* tabulation size */ + + /* + * Internal context of library -- don't touch + */ + struct uni_ie_repeat repeat; /* repeat IE during decoding */ + enum uni_ietype ielast; /* last IE seen for repeat handling */ + + const char *prefix[20]; + u_int nprefix; + int doindent; + char *buf; + size_t bufsiz; + u_int indent; /* indentation */ + int dont_init; +}; + +/* + * Functions for all messages + */ +void uni_print_cref(char *, size_t, const struct uni_cref *, struct unicx *); +void uni_print_msghdr(char *, size_t, const struct uni_msghdr *, struct unicx *); +void uni_print(char *, size_t, const struct uni_all *, struct unicx *); +void uni_print_msg(char *, size_t, u_int _mtype, const union uni_msgall *, + struct unicx *); +int uni_encode(struct uni_msg *, struct uni_all *, struct unicx *); +int uni_decode(struct uni_msg *, struct uni_all *, struct unicx *); + +int uni_decode_head(struct uni_msg *, struct uni_all *, struct unicx *); +int uni_decode_body(struct uni_msg *, struct uni_all *, struct unicx *); + +int uni_encode_msg_hdr(struct uni_msg *, struct uni_msghdr *, enum uni_msgtype, + struct unicx *, int *); + + +/* + * Functions for all information elements + */ +void uni_print_ie(char *, size_t, enum uni_ietype, const union uni_ieall *, + struct unicx *); +int uni_check_ie(enum uni_ietype, union uni_ieall *, struct unicx *); +int uni_encode_ie(enum uni_ietype, struct uni_msg *, union uni_ieall *, + struct unicx *); +int uni_decode_ie_hdr(enum uni_ietype *, struct uni_iehdr *, struct uni_msg *, + struct unicx *, u_int *); +int uni_encode_ie_hdr(struct uni_msg *, enum uni_ietype, struct uni_iehdr *, + u_int, struct unicx *); +int uni_decode_ie_body(enum uni_ietype, union uni_ieall *, struct uni_msg *, + u_int, struct unicx *); + + +/* + * Context handling + */ +void uni_initcx(struct unicx *); +void uni_print_cx(char *, size_t, struct unicx *); + +#define UNI_SAVE_IERR(CX, IETYPE, ACT, ERRCODE) \ + (((CX)->errcnt < UNI_MAX_ERRIE) ? \ + ((CX)->err[(CX)->errcnt].ie = (IETYPE), \ + (CX)->err[(CX)->errcnt].act = (ACT), \ + (CX)->err[(CX)->errcnt].err = (ERRCODE), \ + (CX)->err[(CX)->errcnt].man = 0, \ + (CX)->errcnt++, \ + 1) : 0) + +/* + * Traffic classification + */ +enum uni_traffic_class { + UNI_TRAFFIC_CBR1, + UNI_TRAFFIC_CBR2, + UNI_TRAFFIC_CBR3, + UNI_TRAFFIC_rtVBR1, + UNI_TRAFFIC_rtVBR2, + UNI_TRAFFIC_rtVBR3, + UNI_TRAFFIC_rtVBR4, + UNI_TRAFFIC_rtVBR5, + UNI_TRAFFIC_rtVBR6, + UNI_TRAFFIC_nrtVBR1, + UNI_TRAFFIC_nrtVBR2, + UNI_TRAFFIC_nrtVBR3, + UNI_TRAFFIC_nrtVBR4, + UNI_TRAFFIC_nrtVBR5, + UNI_TRAFFIC_nrtVBR6, + UNI_TRAFFIC_ABR, + UNI_TRAFFIC_UBR1, + UNI_TRAFFIC_UBR2, +}; + +/* classify traffic */ +int uni_classify_traffic(const struct uni_ie_bearer *, + const struct uni_ie_traffic *, + enum uni_traffic_class *, enum uni_traffic_class *, + char *, size_t); + +#endif diff --git a/sys/contrib/ngatm/netnatm/msg/uniprint.h b/sys/contrib/ngatm/netnatm/msg/uniprint.h new file mode 100644 index 000000000000..239fa2dd4076 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/uniprint.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/msg/uniprint.h,v 1.4 2004/07/08 08:22:08 brandt Exp $ + * + * Print utility functions. These are only needed if you want to hook to + * the format of the uni printing routines. + */ +#ifndef _NETNATM_MSG_UNIPRINT_H_ +#define _NETNATM_MSG_UNIPRINT_H_ + +#include <netnatm/msg/uni_config.h> + +/* + * This structure is used to define value->string mappings. + * It must be terminated by a { NULL, 0 } entry. + */ +struct uni_print_tbl { + const char *name; + u_int val; +}; +void uni_print_tbl(const char *_entry, u_int _val, + const struct uni_print_tbl *_tbl, struct unicx *_cx); + +/* initialize printing. This must be called at the start from each external + * callable printing function. */ +void uni_print_init(char *_buf, size_t _bufsiz, struct unicx *_cx); + +/* End the current (semantical) line. This takes care of indendation and + * actually print the newline in the appropriate modes. */ +void uni_print_eol(struct unicx *_cx); + +/* Push or pop a prefix. This takes care of indendation. */ +void uni_print_push_prefix(const char *_prefix, struct unicx *_cx); +void uni_print_pop_prefix(struct unicx *_cx); + +/* Print a flag taking care of the right prefixing */ +void uni_print_flag(const char *_flag, struct unicx *_cx); + +/* Print an entry taking care of the right prefixing */ +void uni_print_entry(struct unicx *_cx, const char *_entry, + const char *_fmt, ...) __printflike(3, 4); + +/* Generic printf */ +void uni_printf(struct unicx *_cx, const char *_fmt, ...) __printflike(2, 3); + +#endif diff --git a/sys/contrib/ngatm/netnatm/msg/unistruct.h b/sys/contrib/ngatm/netnatm/msg/unistruct.h new file mode 100644 index 000000000000..ceb1f5b5f8d4 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/unistruct.h @@ -0,0 +1,1371 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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/msg/unistruct.h,v 1.7 2004/07/16 18:42:22 brandt Exp $ + * + * This file defines all structures that are used by + * API users. + */ +#ifndef _NETNATM_MSG_UNISTRUCT_H_ +#define _NETNATM_MSG_UNISTRUCT_H_ + +#include <netnatm/msg/uni_config.h> + +/* + * define IE and MSG header + */ +#include <netnatm/msg/uni_hdr.h> + +/* + * define all IE's + */ +/************************************************************************* + * + * Free FORM IE + */ +struct uni_ie_unrec { + struct uni_iehdr h; + uint8_t id; /* ID of this IE */ + u_int len; /* data length */ + u_char data[128]; /* arbitrary maximum length */ +}; + +/************************************************************************* + * + * ATM adaptation layer parameters information element + */ +enum { + UNI_AAL_SUB_ID = 0x85, + UNI_AAL_CBR_ID = 0x86, + UNI_AAL_MULT_ID = 0x87, + UNI_AAL_SCREC_ID = 0x88, + UNI_AAL_ECM_ID = 0x89, + UNI_AAL_BSIZE_ID = 0x8a, + UNI_AAL_PART_ID = 0x8b, + UNI_AAL_FWDCPCS_ID = 0x8c, + UNI_AAL_BWDCPCS_ID = 0x81, + UNI_AAL_MID_ID = 0x82, + UNI_AAL_SSCS_ID = 0x84, +}; + +enum uni_aal { + UNI_AAL_0 = 0x00, /* voice */ + UNI_AAL_1 = 0x01, + UNI_AAL_2 = 0x02, + UNI_AAL_4 = 0x03, /* same as AAL 3 */ + UNI_AAL_5 = 0x05, + UNI_AAL_USER = 0x10, +}; +enum uni_aal1_subtype { + UNI_AAL1_SUB_NULL = 0x00, + UNI_AAL1_SUB_VOICE = 0x01, + UNI_AAL1_SUB_CIRCUIT = 0x02, + UNI_AAL1_SUB_HQAUDIO = 0x04, + UNI_AAL1_SUB_VIDEO = 0x05, +}; +enum uni_aal1_cbr { + UNI_AAL1_CBR_64 = 0x01, + UNI_AAL1_CBR_1544 = 0x04, + UNI_AAL1_CBR_6312 = 0x05, + UNI_AAL1_CBR_32064 = 0x06, + UNI_AAL1_CBR_44736 = 0x07, + UNI_AAL1_CBR_97728 = 0x08, + UNI_AAL1_CBR_2048 = 0x10, + UNI_AAL1_CBR_8448 = 0x11, + UNI_AAL1_CBR_34368 = 0x12, + UNI_AAL1_CBR_139264 = 0x13, + UNI_AAL1_CBR_N64 = 0x40, + UNI_AAL1_CBR_N8 = 0x41, +}; +enum uni_aal1_screc { + UNI_AAL1_SCREC_NULL = 0x00, /* synchr. circuit transport */ + UNI_AAL1_SCREC_SRTS = 0x01, /* synchr. residual timestamp */ + UNI_AAL1_SCREC_ACLK = 0x02, /* adaptive clock */ +}; +enum uni_aal1_ecm { + UNI_AAL1_ECM_NULL = 0x00, /* no error correction */ + UNI_AAL1_ECM_LOSS = 0x01, /* for loss sensitive signals */ + UNI_AAL1_ECM_DELAY = 0x02, /* for delay sensitive signals */ +}; +enum uni_aal_sscs { + UNI_AAL_SSCS_NULL = 0x00, /* Null */ + UNI_AAL_SSCS_SSCOPA = 0x01, /* assured SSCOP */ + UNI_AAL_SSCS_SSCOPU = 0x02, /* unassured SSCOP */ + UNI_AAL_SSCS_FRAME = 0x04, /* frame relay */ +}; + +struct uni_ie_aal { + struct uni_iehdr h; + enum uni_aal type; /* aal type */ + + union { +#define UNI_AAL1_MULT_P 0x01 +#define UNI_AAL1_SCREC_P 0x02 +#define UNI_AAL1_ECM_P 0x04 +#define UNI_AAL1_BSIZE_P 0x08 +#define UNI_AAL1_PART_P 0x10 + struct { + enum uni_aal1_subtype subtype; /* AAL1 subtype */ + enum uni_aal1_cbr cbr_rate; /* AAL1 CBR rate */ + u_int mult; /* AAL1 CBR mutliplier */ + enum uni_aal1_screc screc; /* AAL1 source clock recovery */ + enum uni_aal1_ecm ecm; /* AAL1 error correction */ + u_int bsize; /* AAL1 SDT blocksize */ + u_int part; /* AAL1 partial cell fill */ + } aal1; + +#define UNI_AAL4_CPCS_P 0x01 +#define UNI_AAL4_MID_P 0x02 +#define UNI_AAL4_SSCS_P 0x04 + struct { + u_int fwd_cpcs; /* max fwd cpcs blocksize */ + u_int bwd_cpcs; /* max bkw cpcs blocksize */ + u_int mid_low; /* MID low range */ + u_int mid_high; /* MID high range */ + enum uni_aal_sscs sscs; /* sscs type */ + } aal4; + +#define UNI_AAL5_CPCS_P 0x01 +#define UNI_AAL5_SSCS_P 0x02 + struct { + u_int fwd_cpcs; /* max fwd cpcs blocksize */ + u_int bwd_cpcs; /* max bkw cpcs blocksize */ + enum uni_aal_sscs sscs; /* sscs type */ + } aal5; + + struct { + u_int len; /* number of bytes */ + u_char user[4]; /* user data */ + } aalu; + } u; +}; + +/************************************************************************* + * + * Called party number information element + * Called party subaddress information element + * Calling party number information element + * Calling party subaddress information element + * Q.2951/UNI4.0 Connected number information element + * Q.2951/UNI4.0 Connected subaddress information element + */ +enum uni_addr_type { + UNI_ADDR_UNKNOWN = 0x0, + UNI_ADDR_INTERNATIONAL = 0x1, + UNI_ADDR_NATIONAL = 0x2, /* not sup */ + UNI_ADDR_NETWORK = 0x3, /* not sup */ + UNI_ADDR_SUBSCR = 0x4, /* not sup */ + UNI_ADDR_ABBR = 0x6, /* not sup */ +}; +enum uni_addr_plan { + /* UNI_ADDR_UNKNOWN = 0x0, */ /* not sup */ + UNI_ADDR_E164 = 0x1, + UNI_ADDR_ATME = 0x2, + UNI_ADDR_DATA = 0x3, /* not sup */ + UNI_ADDR_PRIVATE = 0x9, /* not sup */ +}; +enum uni_subaddr_type { + UNI_SUBADDR_NSAP = 0x0, + UNI_SUBADDR_ATME = 0x1, + UNI_SUBADDR_USER = 0x2, /* not sup */ +}; +enum uni_addr_pres { + UNI_ADDR_PRES = 0x0, + UNI_ADDR_RESTRICT = 0x1, + UNI_ADDR_NONUMBER = 0x2, +}; +enum uni_addr_screen { + UNI_ADDR_SCREEN_NOT = 0x0, + UNI_ADDR_SCREEN_PASSED = 0x1, + UNI_ADDR_SCREEN_FAILED = 0x2, + UNI_ADDR_SCREEN_NET = 0x3, +}; + +/* don't use bitfields to get a defined structure layout */ +struct uni_addr { + uint8_t type; + uint8_t plan; + uint8_t len; + u_char addr[UNI_ADDR_MAXLEN]; +}; +struct uni_subaddr { + enum uni_subaddr_type type; + u_int len; + u_char addr[UNI_SUBADDR_MAXLEN]; +}; + +struct uni_ie_called { + struct uni_iehdr h; + struct uni_addr addr; +}; + +struct uni_ie_calledsub { + struct uni_iehdr h; + struct uni_subaddr addr; +}; + +struct uni_ie_calling { + struct uni_iehdr h; +#define UNI_CALLING_SCREEN_P 0x0001 + + struct uni_addr addr; + enum uni_addr_pres pres; + enum uni_addr_screen screen; +}; + +struct uni_ie_callingsub { + struct uni_iehdr h; + struct uni_subaddr addr; +}; + +struct uni_ie_conned { + struct uni_iehdr h; +#define UNI_CONNED_SCREEN_P 0x0001 + + struct uni_addr addr; + enum uni_addr_pres pres; + enum uni_addr_screen screen; +}; + +struct uni_ie_connedsub { + struct uni_iehdr h; + struct uni_subaddr addr; +}; + +/************************************************************************* + * + * Broadband bearer capability descriptor + * On reception of an old bearer descriptor, it is automatically + * converted to a new, legal one. + */ +enum uni_bearer_class { + UNI_BEARER_A = 0x01, + UNI_BEARER_C = 0x03, + UNI_BEARER_X = 0x10, + UNI_BEARER_TVP = 0x30, +}; + +enum uni_bearer_atc { + UNI_BEARER_ATC_CBR = 0x05, + UNI_BEARER_ATC_CBR1 = 0x07, + UNI_BEARER_ATC_VBR = 0x09, + UNI_BEARER_ATC_VBR1 = 0x13, + UNI_BEARER_ATC_NVBR = 0x0a, + UNI_BEARER_ATC_NVBR1 = 0x0b, + UNI_BEARER_ATC_ABR = 0x0c, + + UNI_BEARER_ATCX_0 = 0x00, + UNI_BEARER_ATCX_1 = 0x01, + UNI_BEARER_ATCX_2 = 0x02, + UNI_BEARER_ATCX_4 = 0x04, + UNI_BEARER_ATCX_6 = 0x06, + UNI_BEARER_ATCX_8 = 0x08, +}; + +enum uni_bearer_clip { + UNI_BEARER_NOCLIP = 0x0, + UNI_BEARER_CLIP = 0x1, +}; + +enum uni_bearer_cfg { + UNI_BEARER_P2P = 0x0, + UNI_BEARER_MP = 0x1, +}; + +struct uni_ie_bearer { + struct uni_iehdr h; +#define UNI_BEARER_ATC_P 0x02 + + enum uni_bearer_class bclass; /* bearer class */ + enum uni_bearer_atc atc; /* ATM transfer capability */ + enum uni_bearer_clip clip; /* suspectibility to clipping */ + enum uni_bearer_cfg cfg; /* u-plane configuration */ +}; + +/************************************************************************* + * + * Broadband higher layer information element + */ +enum uni_bhli { + UNI_BHLI_ISO = 0x00, /* IDO defined */ + UNI_BHLI_USER = 0x01, /* user specific */ + UNI_BHLI_VENDOR = 0x03, /* vendor specific */ +}; + +struct uni_ie_bhli { + struct uni_iehdr h; + enum uni_bhli type; + u_char info[8]; + u_int len; +}; + +/************************************************************************* + * + * Boradband lower layer information element + */ +enum { + UNI_BLLI_L1_ID = 0x1, + UNI_BLLI_L2_ID = 0x2, + UNI_BLLI_L3_ID = 0x3, +}; + +enum uni_blli_l2 { + UNI_BLLI_L2_BASIC = 0x01, + UNI_BLLI_L2_Q921 = 0x02, + UNI_BLLI_L2_X25LL = 0x06, + UNI_BLLI_L2_X25ML = 0x07, + UNI_BLLI_L2_LABP = 0x08, + UNI_BLLI_L2_HDLC_ARM = 0x09, + UNI_BLLI_L2_HDLC_NRM = 0x0a, + UNI_BLLI_L2_HDLC_ABM = 0x0b, + UNI_BLLI_L2_LAN = 0x0c, + UNI_BLLI_L2_X75 = 0x0d, + UNI_BLLI_L2_Q922 = 0x0e, + UNI_BLLI_L2_USER = 0x10, + UNI_BLLI_L2_ISO7776 = 0x11, +}; + +enum uni_blli_l2_mode { + UNI_BLLI_L2NORM = 0x1, + UNI_BLLI_L2EXT = 0x2, +}; + +enum uni_blli_l3 { + UNI_BLLI_L3_X25 = 0x06, + UNI_BLLI_L3_ISO8208 = 0x07, + UNI_BLLI_L3_X223 = 0x08, + UNI_BLLI_L3_CLMP = 0x09, + UNI_BLLI_L3_T70 = 0x0a, + UNI_BLLI_L3_TR9577 = 0x0b, + UNI_BLLI_L3_H310 = 0x0c, + UNI_BLLI_L3_H321 = 0x0d, + UNI_BLLI_L3_USER = 0x10, +}; + +enum uni_blli_l3_mode { + UNI_BLLI_L3NSEQ = 0x1, /* normal sequence numbering */ + UNI_BLLI_L3ESEQ = 0x2, /* extended sequence numbering */ +}; + +enum uni_blli_l3_psiz { + UNI_BLLI_L3_16 = 0x4, /* 16 byte packets */ + UNI_BLLI_L3_32 = 0x5, /* 32 byte packets */ + UNI_BLLI_L3_64 = 0x6, /* 64 byte packets */ + UNI_BLLI_L3_128 = 0x7, /* 128 byte packets */ + UNI_BLLI_L3_256 = 0x8, /* 256 byte packets */ + UNI_BLLI_L3_512 = 0x9, /* 512 byte packets */ + UNI_BLLI_L3_1024 = 0xa, /* 1024 byte packets */ + UNI_BLLI_L3_2048 = 0xb, /* 2048 byte packets */ + UNI_BLLI_L3_4096 = 0xc, /* 4096 byte packets */ +}; + +enum uni_blli_l3_ttype { + UNI_BLLI_L3_TTYPE_RECV = 0x1, /* receive only */ + UNI_BLLI_L3_TTYPE_SEND = 0x2, /* send only */ + UNI_BLLI_L3_TTYPE_BOTH = 0x3, /* both */ +}; + +enum uni_blli_l3_mux { + UNI_BLLI_L3_MUX_NOMUX = 0, /* no multiplexing */ + UNI_BLLI_L3_MUX_TS = 1, /* transport stream */ + UNI_BLLI_L3_MUX_TSFEC = 2, /* transport stream with FEC */ + UNI_BLLI_L3_MUX_PS = 3, /* program stream */ + UNI_BLLI_L3_MUX_PSFEC = 4, /* program stream with FEC */ + UNI_BLLI_L3_MUX_H221 = 5, /* H.221 */ +}; + +enum uni_blli_l3_tcap { + UNI_BLLI_L3_TCAP_NOIND = 0, /* no indication */ + UNI_BLLI_L3_TCAP_AAL1 = 1, /* only AAL1 */ + UNI_BLLI_L3_TCAP_AAL5 = 2, /* only AAL5 */ + UNI_BLLI_L3_TCAP_AAL15 = 3, /* AAL1 and AAL5 */ +}; + +/* Value for l3_ipi: */ +enum { + UNI_BLLI_L3_SNAP = 0x80, /* IEEE 802.1 SNAP */ +}; + +struct uni_ie_blli { + struct uni_iehdr h; +#define UNI_BLLI_L1_P 0x0001 +#define UNI_BLLI_L2_P 0x0002 +#define UNI_BLLI_L2_Q933_P 0x0004 +#define UNI_BLLI_L2_WSIZ_P 0x0008 +#define UNI_BLLI_L2_USER_P 0x0010 +#define UNI_BLLI_L3_P 0x0020 +#define UNI_BLLI_L3_MODE_P 0x0040 +#define UNI_BLLI_L3_PSIZ_P 0x0080 +#define UNI_BLLI_L3_WSIZ_P 0x0100 +#define UNI_BLLI_L3_USER_P 0x0200 +#define UNI_BLLI_L3_IPI_P 0x0400 +#define UNI_BLLI_L3_SNAP_P 0x0800 +#define UNI_BLLI_L3_TTYPE_P 0x1000 +#define UNI_BLLI_L3_MUX_P 0x2000 + + u_int l1:5; /* layer 1 info */ + + enum uni_blli_l2 l2; /* layer 2 info */ + u_int l2_q933:2; /* layer 2 Q.933 use */ + enum uni_blli_l2_mode l2_mode; /* layer 2 HDLC mode */ + u_char l2_user; /* layer 2 user info */ + u_char l2_wsiz; /* layer 2 window size */ + + enum uni_blli_l3 l3; /* layer 3 info */ + enum uni_blli_l3_mode l3_mode; /* layer 3 mode */ + enum uni_blli_l3_psiz l3_psiz; /* layer 3 default packet size */ + u_char l3_wsiz; /* layer 3 window size */ + u_char l3_user; /* layer 3 user info */ + u_char l3_ipi; /* IPI byte */ + u_int oui; /* OUI bytes */ + u_int pid; /* PID bytes */ + enum uni_blli_l3_ttype l3_ttype; /* terminal bytes */ + enum uni_blli_l3_tcap l3_tcap; /* terminal capability */ + enum uni_blli_l3_mux l3_fmux; /* forward muxing */ + enum uni_blli_l3_mux l3_bmux; /* forward muxing */ +}; + +/************************************************************************* + * + * Transit network selection IE + */ +struct uni_ie_tns { + struct uni_iehdr h; + u_char net[UNI_TNS_MAXLEN]; + u_int len; +}; + +/************************************************************************* + * + * Call state information element + */ +enum uni_callstate { + UNI_CALLSTATE_U0 = 0x00, + UNI_CALLSTATE_N0 = 0x00, + UNI_CALLSTATE_NN0 = 0x00, + + UNI_CALLSTATE_U1 = 0x01, + UNI_CALLSTATE_N1 = 0x01, + UNI_CALLSTATE_NN1 = 0x01, + + UNI_CALLSTATE_U3 = 0x03, + UNI_CALLSTATE_N3 = 0x03, + UNI_CALLSTATE_NN3 = 0x03, + + UNI_CALLSTATE_U4 = 0x04, + UNI_CALLSTATE_N4 = 0x04, + UNI_CALLSTATE_NN4 = 0x04, + + UNI_CALLSTATE_U6 = 0x06, + UNI_CALLSTATE_N6 = 0x06, + UNI_CALLSTATE_NN6 = 0x06, + + UNI_CALLSTATE_U7 = 0x07, + UNI_CALLSTATE_N7 = 0x07, + UNI_CALLSTATE_NN7 = 0x07, + + UNI_CALLSTATE_U8 = 0x08, + UNI_CALLSTATE_N8 = 0x08, + + UNI_CALLSTATE_U9 = 0x09, + UNI_CALLSTATE_N9 = 0x09, + UNI_CALLSTATE_NN9 = 0x09, + + UNI_CALLSTATE_U10 = 0x0a, + UNI_CALLSTATE_N10 = 0x0a, + UNI_CALLSTATE_NN10 = 0x0a, + + UNI_CALLSTATE_U11 = 0x0b, + UNI_CALLSTATE_N11 = 0x0b, + UNI_CALLSTATE_NN11 = 0x0b, + + UNI_CALLSTATE_U12 = 0x0c, + UNI_CALLSTATE_N12 = 0x0c, + UNI_CALLSTATE_NN12 = 0x0c, + + UNI_CALLSTATE_REST0 = 0x00, + UNI_CALLSTATE_REST1 = 0x3d, + UNI_CALLSTATE_REST2 = 0x3e, + + UNI_CALLSTATE_U13 = 0x0d, + UNI_CALLSTATE_N13 = 0x0d, + + UNI_CALLSTATE_U14 = 0x0e, + UNI_CALLSTATE_N14 = 0x0e, +}; + +struct uni_ie_callstate { + struct uni_iehdr h; + enum uni_callstate state; +}; + +/************************************************************************* + * + * Cause information element + */ +enum uni_cause_loc { + UNI_CAUSE_LOC_USER = 0x0, + UNI_CAUSE_LOC_PRIVLOC = 0x1, + UNI_CAUSE_LOC_PUBLOC = 0x2, + UNI_CAUSE_LOC_TRANSIT = 0x3, + UNI_CAUSE_LOC_PUBREM = 0x4, + UNI_CAUSE_LOC_PRIVREM = 0x5, + UNI_CAUSE_LOC_INTERNAT = 0x6, + UNI_CAUSE_LOC_BEYOND = 0x7, +}; + +#define UNI_DECLARE_CAUSE_VALUES \ +D(UNALL_NUM, 0x01 /* 1*/, COND, Q.850, "Unallocated (unassigned) number") \ +D(NOROUTE_NET, 0x02 /* 2*/, TNS, Q.850, "No route to specified transit network") \ +D(NOROUTE, 0x03 /* 3*/, COND, Q.850, "No route to destination") \ +D(SPTONE, 0x04 /* 4*/, NONE, Q.850, "Send special information tone") \ +D(BADTRUNK, 0x05 /* 5*/, NONE, Q.850, "Misdialled trunk prefix") \ +D(BADCHAN, 0x06 /* 6*/, NONE, Q.850, "Channel unacceptable") \ +D(CALLAWARDED, 0x07 /* 7*/, NONE, Q.850, "Call awarded and being delivered in an established channel") \ +D(PREEMPT, 0x08 /* 8*/, NONE, Q.850, "Preemption") \ +D(PREEMPT_RES, 0x09 /* 9*/, NONE, Q.850, "Preemption - circuit reserved for reuse") \ +D(CLEARING, 0x10 /* 16*/, COND, Q.850, "Normal call clearing") \ +D(BUSY, 0x11 /* 17*/, CCBS, Q.850, "User busy") \ +D(NO_RESPONSE, 0x12 /* 18*/, NONE, Q.850, "No user responding") \ +D(NO_RESP_ALERT,0x13 /* 19*/, NONE, Q.850, "No answer from user (user alerted)") \ +D(ABSENT, 0x14 /* 20*/, NONE, Q.850, "Subscriber absent") \ +D(REJECTED, 0x15 /* 21*/, REJ, Q.850, "Call rejected") \ +D(NUMCHG, 0x16 /* 22*/, NUMBER, Q.850, "Number changed") \ +D(REDIR, 0x17 /* 23*/, NONE, Q.850, "Redirection to new destination") \ +N(CLIR_REJECTED,0x17 /* 23*/, NONE, UNI4.0, "User rejects call with calling line identification restriction (CLIR)") \ +D(EXCHG_ERR, 0x19 /* 25*/, NONE, Q.850, "Exchange routing error") \ +D(NOSEL_CLEAR, 0x1a /* 26*/, NONE, Q.850, "Non-selected user clearing") \ +D(DST_OOO, 0x1b /* 27*/, NONE, Q.850, "Destination out of order") \ +D(INV_ADDR, 0x1c /* 28*/, NONE, Q.850, "Invalid number format (address incomplete)") \ +D(FAC_REJ, 0x1d /* 29*/, FAC, Q.850, "Facility rejected") \ +D(STATUS, 0x1e /* 30*/, NONE, Q.850, "Response to STATUS ENQUIRY") \ +D(UNSPEC, 0x1f /* 31*/, NONE, Q.850, "Normal, unspecified") \ +D(TMY_PARTY, 0x20 /* 32*/, NONE, Q.2971, "Too many pending add party requests") \ +D(NOCHAN, 0x22 /* 34*/, CCBS, Q.850, "No circuit/channel available") \ +N(SOFT_NAVL, 0x22 /* 34*/, NONE, PNNI1.0,"Requested called party soft PVPC or PVCC not available")\ +D(VPCI_NAVL, 0x23 /* 35*/, NONE, Q.2610, "Requested VPCI/VCI not available") \ +D(VPCI_FAIL, 0x24 /* 36*/, NONE, Q.2610, "VPCI/VPI assignment failure") \ +D(CRATE_NAVL, 0x25 /* 37*/, CRATE, Q.2610, "User cell rate not available") \ +D(NET_OOO, 0x26 /* 38*/, NONE, Q.850, "Network out of order") \ +D(FRAME_OOS, 0x27 /* 39*/, NONE, Q.850, "Permanent frame mode connection out of service") \ +D(FRAME_OP, 0x28 /* 40*/, NONE, Q.850, "Permanent frame mode connection operational") \ +D(TEMP, 0x29 /* 41*/, NONE, Q.850, "Temporary failure") \ +D(CONG, 0x2a /* 42*/, NONE, Q.850, "Switching equipment congestion") \ +D(ACC_DISC, 0x2b /* 43*/, IE, Q.850, "Access information discarded") \ +D(REQNOCHAN, 0x2c /* 44*/, NONE, Q.850, "Requested circuit/channel not available") \ +D(NOVPCI, 0x2d /* 45*/, NONE, Q.2610, "No VPCI/VCI available") \ +D(PREC_BLOCK, 0x2e /* 46*/, NONE, Q.850, "Precedence call blocked") \ +D(RESRC_NAVL, 0x2f /* 47*/, NONE, Q.850, "Resource unavailable, unspecified") \ +D(QOS_NAVL, 0x31 /* 49*/, COND, Q.850, "Quality of service not available") \ +D(FAC_NOTSUB, 0x32 /* 50*/, FAC, Q.850, "Requested facility not subscribed") \ +D(OUT_CUG, 0x35 /* 53*/, NONE, Q.850, "Outgoing calls barred within CUG") \ +N(PGL_CHG, 0x35 /* 53*/, NONE, PNNI1.0,"Call cleared due to change in PGL") \ +D(IN_CUG, 0x37 /* 55*/, NONE, Q.850, "Incoming call barred within CUG") \ +D(BEARER_NAUTH, 0x39 /* 57*/, ATTR, Q.850, "Bearer capability not authorized") \ +D(BEARER_NAVL, 0x3a /* 58*/, ATTR, Q.850, "Bearer capability not presently available") \ +D(INCONS, 0x3e /* 62*/, NONE, Q.850, "Inconsistency in designated outgoing access information and subscriber class") \ +D(OPT_NAVL, 0x3f /* 63*/, NONE, Q.850, "Service or option not available, unspecified") \ +D(BEARER_NIMPL, 0x41 /* 65*/, ATTR, Q.850, "Bearer capability not implemented") \ +D(CHANNEL_NIMPL,0x42 /* 66*/, CHANNEL, Q.850, "Channel type not implemented") \ +D(FAC_NIMPL, 0x45 /* 69*/, FAC, Q.850, "Requested facility not implemented") \ +D(RESTR_DIG, 0x46 /* 70*/, NONE, Q.850, "Only restricted digital information bearer capability is available") \ +D(TRAFFIC_UNSUP,0x49 /* 73*/, NONE, Q.2971, "Unsupported combination of traffic parameters") \ +N(AAL_UNSUP, 0x4c /* 78*/, NONE, UNI3.1, "AAL parameters cannot be supported") \ +D(CREF_INV, 0x51 /* 81*/, NONE, Q.850, "Invalid call reference value") \ +D(CHANNEL_NEX, 0x52 /* 82*/, CHANID, Q.850, "Identified channel does not exist") \ +D(SUSPENDED, 0x53 /* 83*/, NONE, Q.850, "A suspended call exists, but this call identity does not") \ +D(CID_INUSE, 0x54 /* 84*/, NONE, Q.850, "Call identity in use") \ +D(NOTSUSP, 0x55 /* 85*/, NONE, Q.850, "No call suspended") \ +D(CLEARED, 0x56 /* 86*/, CAUSE, Q.850, "Call having requested call identity has been cleared") \ +D(NOT_MEMBER, 0x57 /* 87*/, NONE, Q.850, "User not member of CUG") \ +D(INCOMP, 0x58 /* 88*/, PARAM, Q.850, "Incompatible destination") \ +D(ENDP_INV, 0x59 /* 89*/, IE, UNI3.1, "Invalid endpoint reference") \ +D(NEX_CUG, 0x5a /* 90*/, NONE, Q.850, "Non-existend CUG") \ +D(TRANSIT_INV, 0x5b /* 91*/, NONE, Q.850, "Invalid transit network selection") \ +D(AALNOTSUPP, 0x5d /* 93*/, NONE, Q.2610, "AAL parameters cannot be supported") \ +D(INVMSG, 0x5f /* 95*/, NONE, Q.850, "Invalid message, unspecified") \ +D(MANDAT, 0x60 /* 96*/, IE, Q.850, "Mandatory information element is missing") \ +D(MTYPE_NIMPL, 0x61 /* 97*/, MTYPE, Q.850, "Message type non-existent or not implemented") \ +D(MSG_NOTCOMP, 0x62 /* 98*/, MTYPE, Q.850, "Message not compatible with call state or message type non-existent or not implemented") \ +D(IE_NIMPL, 0x63 /* 99*/, IE, Q.850, "Information element/parameter non-existent or not implemented") \ +D(IE_INV, 0x64 /*100*/, IE, Q.850, "Invalid information element contents") \ +D(MSG_INCOMP, 0x65 /*101*/, MTYPE, Q.850, "Message not compatible with call state") \ +D(RECOVER, 0x66 /*102*/, TIMER, Q.850, "Recovery on timer expiry") \ +D(PARAM_NEX, 0x67 /*103*/, PARAM, Q.850, "Parameter non-existent or not implemented, passed on") \ +N(BAD_LENGTH, 0x68 /*104*/, NONE, UNI3.1, "Incorrect message length") \ +D(PARAM_UNREC, 0x6e /*110*/, PARAM, Q.850, "Message with unrecognized parameter, discarded") \ +D(PROTO, 0x6f /*111*/, NONE, Q.850, "Protocol error, unspecified") \ +D(INTERWORKING, 0x7f /*127*/, NONE, Q.850, "Interworking, unspecified") + +#define D(NAME,VAL,DIAG,STD,STR) UNI_CAUSE_##NAME = VAL, +#define N(NAME,VAL,DIAG,STD,STR) UNI_CAUSE_##NAME = VAL, + +enum uni_cause { +UNI_DECLARE_CAUSE_VALUES +}; + +#undef D +#undef N + +enum uni_cause_class { + UNI_CAUSE_CLASS_NORM = 0x0, + UNI_CAUSE_CLASS_NORM1 = 0x1, + UNI_CAUSE_CLASS_RES = 0x2, + UNI_CAUSE_CLASS_NAVL = 0x3, + UNI_CAUSE_CLASS_NIMPL = 0x4, + UNI_CAUSE_CLASS_INV = 0x5, + UNI_CAUSE_CLASS_PROTO = 0x6, + UNI_CAUSE_CLASS_INTER = 0x7, +}; +enum uni_cause_pu { + UNI_CAUSE_PU_PROVIDER = 0, + UNI_CAUSE_PU_USER = 1, +}; +enum uni_cause_na { + UNI_CAUSE_NA_NORMAL = 0, + UNI_CAUSE_NA_ABNORMAL = 1, +}; +enum uni_cause_cond { + UNI_CAUSE_COND_UNKNOWN = 0, + UNI_CAUSE_COND_PERM = 1, + UNI_CAUSE_COND_TRANS = 2, +}; +enum uni_cause_reason { + UNI_CAUSE_REASON_USER = 0x00, + UNI_CAUSE_REASON_IEMISS = 0x01, + UNI_CAUSE_REASON_IESUFF = 0x02, +}; + +enum uni_diag { + UNI_DIAG_NONE, /* no diagnostics */ + + UNI_DIAG_COND, /* Condition */ + UNI_DIAG_TNS, /* Transit Network Selector */ + UNI_DIAG_REJ, /* Call Rejected */ + UNI_DIAG_NUMBER, /* New Destination */ + UNI_DIAG_CRATE, /* Traffic descriptor subfield */ + UNI_DIAG_ATTR, /* Attribute idendity */ + UNI_DIAG_PARAM, /* Parameter, same as one IE */ + UNI_DIAG_TIMER, /* timer in ASCII */ + UNI_DIAG_MTYPE, /* Message type */ + UNI_DIAG_IE, /* Information element */ + UNI_DIAG_CHANID, /* VPCI/VCI */ + + UNI_DIAG_CAUSE = UNI_DIAG_NONE, /* Not specified */ + UNI_DIAG_CHANNEL = UNI_DIAG_NONE, /* For N-ISDN */ + UNI_DIAG_CCBS = UNI_DIAG_NONE, /* Not used in Q.931 */ + UNI_DIAG_FAC = UNI_DIAG_NONE, /* Not specified */ +}; + +enum { + UNI_CAUSE_TRAFFIC_N = 34-6, + UNI_CAUSE_IE_N = 34-6, + UNI_CAUSE_ATTR_N = (34-6)/3, +}; + +struct uni_ie_cause { + struct uni_iehdr h; +#define UNI_CAUSE_COND_P 0x0001 +#define UNI_CAUSE_REJ_P 0x0002 +#define UNI_CAUSE_REJ_USER_P 0x0004 +#define UNI_CAUSE_REJ_IE_P 0x0008 +#define UNI_CAUSE_IE_P 0x0010 +#define UNI_CAUSE_TRAFFIC_P 0x0020 +#define UNI_CAUSE_VPCI_P 0x0040 +#define UNI_CAUSE_MTYPE_P 0x0080 +#define UNI_CAUSE_TIMER_P 0x0100 +#define UNI_CAUSE_TNS_P 0x0200 +#define UNI_CAUSE_NUMBER_P 0x0400 +#define UNI_CAUSE_ATTR_P 0x0800 +#define UNI_CAUSE_PARAM_P 0x1000 + + enum uni_cause_loc loc; + enum uni_cause cause; + + union { + struct { + enum uni_cause_pu pu; + enum uni_cause_na na; + enum uni_cause_cond cond; + } cond; + struct { + enum uni_cause_reason reason; + enum uni_cause_cond cond; + u_int user; + uint8_t ie; + } rej; + struct { + uint8_t ie[UNI_CAUSE_IE_N]; + u_int len; + } ie; + struct { + uint8_t traffic[UNI_CAUSE_TRAFFIC_N]; + u_int len; + } traffic; + struct { + uint16_t vpci; + uint16_t vci; + } vpci; + uint8_t mtype; + u_char timer[3]; + struct uni_ie_tns tns; + struct uni_ie_called number; /* TNS does not fit */ + uint8_t param; + struct { + u_int nattr; + u_char attr[UNI_CAUSE_ATTR_N][3]; + } attr; + } u; +}; +enum uni_diag uni_diag(enum uni_cause, enum uni_coding); + +/* return a string for the cause (NULL if the coding/cause are illegal) */ +const char *uni_ie_cause2str(enum uni_coding, u_int); + +/************************************************************************* + * + * Connection identifier information element + */ +enum uni_connid_type { + UNI_CONNID_VCI = 0, + UNI_CONNID_ANYVCI = 1, + UNI_CONNID_NOVCI = 4, +}; +enum uni_connid_assoc { + UNI_CONNID_ASSOC = 0, + UNI_CONNID_NONASSOC = 1, +}; +struct uni_ie_connid { + struct uni_iehdr h; + enum uni_connid_assoc assoc; + enum uni_connid_type type; + u_int vpci : 16; + u_int vci : 16; +}; + +/************************************************************************* + * + * End point reference IE + */ +struct uni_ie_epref { + struct uni_iehdr h; + u_int flag : 1; + u_int epref : 15; +}; + +/************************************************************************* + * + * End point state IE + */ +enum uni_epstate { + UNI_EPSTATE_NULL = 0x00, + UNI_EPSTATE_ADD_INIT = 0x01, + UNI_EPSTATE_ALERT_DLVD = 0x04, + UNI_EPSTATE_ADD_RCVD = 0x06, + UNI_EPSTATE_ALERT_RCVD = 0x07, + UNI_EPSTATE_ACTIVE = 0x0a, + UNI_EPSTATE_DROP_INIT = 0x0b, + UNI_EPSTATE_DROP_RCVD = 0x0c, +}; + +struct uni_ie_epstate { + struct uni_iehdr h; + enum uni_epstate state; +}; + +/************************************************************************* + * + * Q.2932 Facility IE + */ +enum { + UNI_FACILITY_ROSE = 0x11, + + UNI_FACILITY_MAXAPDU = 128, +}; + +struct uni_ie_facility { + struct uni_iehdr h; + + u_char proto; + u_char apdu[UNI_FACILITY_MAXAPDU]; + u_int len; +}; + +/************************************************************************* + * + * Notification indicator + */ +enum { + UNI_NOTIFY_MAXLEN = 128, /* maximum info length */ +}; +struct uni_ie_notify { + struct uni_iehdr h; + u_int len; + u_char notify[UNI_NOTIFY_MAXLEN]; +}; + +/************************************************************************* + * + * QoS information element + */ +enum uni_qos { + UNI_QOS_CLASS0 = 0x00, + UNI_QOS_CLASS1 = 0x01, + UNI_QOS_CLASS2 = 0x02, + UNI_QOS_CLASS3 = 0x03, + UNI_QOS_CLASS4 = 0x04, +}; + +struct uni_ie_qos { + struct uni_iehdr h; + enum uni_qos fwd; + enum uni_qos bwd; +}; + +/************************************************************************* + * + * Broadband repeat indicator information element + */ +enum uni_repeat_type { + UNI_REPEAT_PRIDESC = 0x02, + UNI_REPEAT_STACK = 0x0a, /* PNNI */ +}; + +struct uni_ie_repeat { + struct uni_iehdr h; + enum uni_repeat_type type; +}; + +/************************************************************************* + * + * Restart indicator information element + */ +enum uni_restart_type { + UNI_RESTART_CHANNEL = 0x0, + UNI_RESTART_PATH = 0x1, + UNI_RESTART_ALL = 0x2, +}; + +struct uni_ie_restart { + struct uni_iehdr h; + enum uni_restart_type rclass; +}; + +/************************************************************************* + * + * Broadband sending complete indicator information element + */ +struct uni_ie_scompl { + struct uni_iehdr h; +}; + +/************************************************************************* + * + * ATM traffic descriptor information element + */ +enum { + UNI_TRAFFIC_FMDCR_ID = 0x00, + UNI_TRAFFIC_BMDCR_ID = 0x02, + UNI_TRAFFIC_FPCR0_ID = 0x82, + UNI_TRAFFIC_BPCR0_ID = 0x83, + UNI_TRAFFIC_FPCR1_ID = 0x84, + UNI_TRAFFIC_BPCR1_ID = 0x85, + UNI_TRAFFIC_FSCR0_ID = 0x88, + UNI_TRAFFIC_BSCR0_ID = 0x89, + UNI_TRAFFIC_FSCR1_ID = 0x90, + UNI_TRAFFIC_BSCR1_ID = 0x91, + UNI_TRAFFIC_FABR1_ID = 0x92, + UNI_TRAFFIC_BABR1_ID = 0x93, + UNI_TRAFFIC_FMBS0_ID = 0xa0, + UNI_TRAFFIC_BMBS0_ID = 0xa1, + UNI_TRAFFIC_FMBS1_ID = 0xb0, + UNI_TRAFFIC_BMBS1_ID = 0xb1, + UNI_TRAFFIC_BEST_ID = 0xbe, + UNI_TRAFFIC_MOPT_ID = 0xbf, + + UNI_TRAFFIC_FTAG = 0x01, + UNI_TRAFFIC_BTAG = 0x02, + UNI_TRAFFIC_FDISC = 0x80, + UNI_TRAFFIC_BDISC = 0x40, + + UNI_MINTRAFFIC_FPCR0_ID = 0x82, + UNI_MINTRAFFIC_BPCR0_ID = 0x83, + UNI_MINTRAFFIC_FPCR1_ID = 0x84, + UNI_MINTRAFFIC_BPCR1_ID = 0x85, + UNI_MINTRAFFIC_FABR1_ID = 0x92, + UNI_MINTRAFFIC_BABR1_ID = 0x93, + + UNI_MDCR_ORIGIN_USER = 0x00, + UNI_MDCR_ORIGIN_NET = 0x01, +}; + +#define UNI_TRAFFIC_FPCR0_P 0x0001 +#define UNI_TRAFFIC_BPCR0_P 0x0002 +#define UNI_TRAFFIC_FPCR1_P 0x0004 +#define UNI_TRAFFIC_BPCR1_P 0x0008 +#define UNI_TRAFFIC_FSCR0_P 0x0010 +#define UNI_TRAFFIC_BSCR0_P 0x0020 +#define UNI_TRAFFIC_FSCR1_P 0x0040 +#define UNI_TRAFFIC_BSCR1_P 0x0080 +#define UNI_TRAFFIC_FMBS0_P 0x0100 +#define UNI_TRAFFIC_BMBS0_P 0x0200 +#define UNI_TRAFFIC_FMBS1_P 0x0400 +#define UNI_TRAFFIC_BMBS1_P 0x0800 +#define UNI_TRAFFIC_BEST_P 0x1000 +#define UNI_TRAFFIC_MOPT_P 0x2000 +#define UNI_TRAFFIC_FABR1_P 0x4000 +#define UNI_TRAFFIC_BABR1_P 0x8000 +struct uni_xtraffic { + u_int fpcr0, bpcr0; + u_int fpcr1, bpcr1; + u_int fscr0, bscr0; + u_int fscr1, bscr1; + u_int fmbs0, bmbs0; + u_int fmbs1, bmbs1; + u_int fabr1, babr1; + u_int ftag, btag; + u_int fdisc, bdisc; +}; + +struct uni_ie_traffic { + struct uni_iehdr h; + struct uni_xtraffic t; +}; +struct uni_ie_atraffic { + struct uni_iehdr h; + struct uni_xtraffic t; +}; + +/* + * Q.2961 minimum traffic descriptor + */ +struct uni_ie_mintraffic { + struct uni_iehdr h; +#define UNI_MINTRAFFIC_FPCR0_P 0x0001 +#define UNI_MINTRAFFIC_BPCR0_P 0x0002 +#define UNI_MINTRAFFIC_FPCR1_P 0x0004 +#define UNI_MINTRAFFIC_BPCR1_P 0x0008 +#define UNI_MINTRAFFIC_FABR1_P 0x0010 +#define UNI_MINTRAFFIC_BABR1_P 0x0020 + + u_int fpcr0, bpcr0; + u_int fpcr1, bpcr1; + u_int fabr1, babr1; +}; + +/* + * UNI4.0+ (af-cs-0147.000) Minimum Desired Cell Rate + */ +struct uni_ie_mdcr { + struct uni_iehdr h; + u_int origin; + u_int fmdcr, bmdcr; +}; + +/************************************************************************* + * + * User-user information information element + */ +struct uni_ie_uu { + struct uni_iehdr h; + u_int len; + u_char uu[UNI_UU_MAXLEN]; +}; + +/************************************************************************* + * + * Generic identifier transport + */ +enum uni_git_std { + UNI_GIT_STD_DSMCC = 0x01, /* DSM-CC */ + UNI_GIT_STD_H245 = 0x02, /* H.245 */ +}; +enum uni_git_type { + UNI_GIT_TYPE_SESS = 0x01, /* session id */ + UNI_GIT_TYPE_RES = 0x02, /* resource id */ +}; + +enum { + UNI_GIT_MAXSESS = 20, /* max session value length */ + UNI_GIT_MAXRES = 4, /* max resource value length */ + + UNI_GIT_MAXVAL = 20, /* the maximum of the above */ + UNI_GIT_MAXSUB = 2, /* maximum number of og. 6 */ +}; + +struct uni_ie_git { + struct uni_iehdr h; + + enum uni_git_std std; /* identifier related standard/application */ + u_int numsub; + struct { + enum uni_git_type type; + u_int len; + u_char val[UNI_GIT_MAXVAL]; + } sub[UNI_GIT_MAXSUB]; +}; + +/************************************************************************* + * + * End-to-end transit delay + */ +enum { + UNI_EETD_CTD_ID = 0x01, /* cumulative transit delay */ + UNI_EETD_MTD_ID = 0x03, /* maximum transit delay */ + UNI_EETD_NET_ID = 0x0a, /* network generated */ + UNI_EETD_PMTD_ID = 0x0b, /* PNNI acceptable forward maximum ctd */ + UNI_EETD_PCTD_ID = 0x11, /* PNNI cumulative forward maximum ctd */ + + UNI_EETD_ANYMAX = 0xffff, + UNI_EETD_MAXVAL = 0xffff, /* maximum value */ +}; + +struct uni_ie_eetd { + struct uni_iehdr h; +#define UNI_EETD_CUM_P 0x0001 +#define UNI_EETD_MAX_P 0x0002 +#define UNI_EETD_NET_P 0x0004 /* UNI4.0 9.1.2.1 */ +#define UNI_EETD_PMTD_P 0x0008 /* PNNI1.0 6.4.5.24 */ +#define UNI_EETD_PCTD_P 0x0010 /* PNNI1.0 6.4.5.24 */ + + u_int cumulative; + u_int maximum; + u_int pmtd; + u_int pctd; +}; + +/************************************************************************* + * + * Leaf-initiated-join call identifier + */ +enum uni_lij_idtype { + UNI_LIJ_IDTYPE_ROOT = 0x0, /* root created */ +}; + +struct uni_ie_lij_callid { + struct uni_iehdr h; + + enum uni_lij_idtype type; + u_int callid; +}; + +/* + * LIJ parameters + */ +enum uni_lij_screen { + UNI_LIJ_SCREEN_NETJOIN = 0x0, /* without root notification */ +}; + +struct uni_ie_lij_param { + struct uni_iehdr h; + + enum uni_lij_screen screen; +}; + +/* + * LIJ sequence number + */ +struct uni_ie_lij_seqno { + struct uni_iehdr h; + + u_int seqno; +}; + +/************************************************************************* + * + * Locking/Non-locking shift not supported + */ +struct uni_ie_lshift { + struct uni_iehdr h; + u_int set:3; +}; + +struct uni_ie_nlshift { + struct uni_iehdr h; + u_int set:3; +}; + +/************************************************************************* + * + * Externded QoS information element + */ +enum { + UNI_EXQOS_FACC_ID = 0x94, + UNI_EXQOS_BACC_ID = 0x95, + UNI_EXQOS_FCUM_ID = 0x96, + UNI_EXQOS_BCUM_ID = 0x97, + UNI_EXQOS_FCLR_ID = 0xa2, + UNI_EXQOS_BCLR_ID = 0xa3, +}; + +enum uni_exqos_origin { + UNI_EXQOS_USER = 0, + UNI_EXQOS_NET = 1, +}; + +enum { + UNI_EXQOS_ANY_CDV = 0xffffff, + UNI_EXQOS_ANY_CLR = 0xff, +}; + +struct uni_ie_exqos { + struct uni_iehdr h; +#define UNI_EXQOS_FACC_P 0x0001 +#define UNI_EXQOS_BACC_P 0x0002 +#define UNI_EXQOS_FCUM_P 0x0004 +#define UNI_EXQOS_BCUM_P 0x0008 +#define UNI_EXQOS_FCLR_P 0x0010 +#define UNI_EXQOS_BCLR_P 0x0020 + + enum uni_exqos_origin origin; + u_int facc; + u_int bacc; + u_int fcum; + u_int bcum; + u_int fclr; + u_int bclr; +}; + +/************************************************************************* + * + * Additional ABR parameters + * ABR setup parameters + */ +enum { + UNI_ABRADD_FADD_ID = 0xc2, + UNI_ABRADD_BADD_ID = 0xc3, + UNI_ABRSETUP_FICR_ID = 0xc2, + UNI_ABRSETUP_BICR_ID = 0xc3, + UNI_ABRSETUP_FTBE_ID = 0xc4, + UNI_ABRSETUP_BTBE_ID = 0xc5, + UNI_ABRSETUP_RMFRT_ID = 0xc6, + UNI_ABRSETUP_FRIF_ID = 0xc8, + UNI_ABRSETUP_BRIF_ID = 0xc9, + UNI_ABRSETUP_FRDF_ID = 0xca, + UNI_ABRSETUP_BRDF_ID = 0xcb, +}; + +struct uni_abr_rec { + u_int present; +#define UNI_ABR_REC_NRM_P 0x80000000 +#define UNI_ABR_REC_TRM_P 0x40000000 +#define UNI_ABR_REC_CDF_P 0x20000000 +#define UNI_ABR_REC_ADTF_P 0x10000000 + u_int nrm:3; + u_int trm:3; + u_int cdf:3; + u_int adtf:10; +}; + +struct uni_ie_abradd { + struct uni_iehdr h; + struct uni_abr_rec fwd, bwd; +}; + +struct uni_ie_abrsetup { + struct uni_iehdr h; +#define UNI_ABRSETUP_FICR_P 0x0001 +#define UNI_ABRSETUP_BICR_P 0x0002 +#define UNI_ABRSETUP_FTBE_P 0x0004 +#define UNI_ABRSETUP_BTBE_P 0x0008 +#define UNI_ABRSETUP_FRIF_P 0x0010 +#define UNI_ABRSETUP_BRIF_P 0x0020 +#define UNI_ABRSETUP_FRDF_P 0x0040 +#define UNI_ABRSETUP_BRDF_P 0x0080 +#define UNI_ABRSETUP_RMFRT_P 0x0100 + + u_int ficr, bicr; + u_int ftbe, btbe; + u_int rmfrt; + u_int frif, brif; + u_int frdf, brdf; +}; + +/************************************************************************* + * + * Connection scope information element + */ +enum uni_cscope { + UNI_CSCOPE_ORG = 0x01, +}; + +enum { + UNI_CSCOPE_ORG_LOC = 0x01, + UNI_CSCOPE_ORG_LOC_P1 = 0x02, + UNI_CSCOPE_ORG_LOC_P2 = 0x03, + UNI_CSCOPE_ORG_SITE_M1 = 0x04, + UNI_CSCOPE_ORG_SITE = 0x05, + UNI_CSCOPE_ORG_SITE_P1 = 0x06, + UNI_CSCOPE_ORG_ORG_M1 = 0x07, + UNI_CSCOPE_ORG_ORG = 0x08, + UNI_CSCOPE_ORG_ORG_P1 = 0x09, + UNI_CSCOPE_ORG_COMM_M1 = 0x0a, + UNI_CSCOPE_ORG_COMM = 0x0b, + UNI_CSCOPE_ORG_COMM_P1 = 0x0c, + UNI_CSCOPE_ORG_REG = 0x0d, + UNI_CSCOPE_ORG_INTER = 0x0e, + UNI_CSCOPE_ORG_GLOBAL = 0x0f, +}; + +struct uni_ie_cscope { + struct uni_iehdr h; + enum uni_cscope type; + u_int scope:8; +}; + +/************************************************************************* + * + * Connection scope information element + */ +enum uni_report { + UNI_REPORT_MODCONF = 0x01, + UNI_REPORT_CLOCK = 0x02, + UNI_REPORT_EEAVAIL = 0x04, + UNI_REPORT_EEREQ = 0x05, + UNI_REPORT_EECOMPL = 0x06, +}; + +struct uni_ie_report { + struct uni_iehdr h; + enum uni_report report; +}; + +/************************************************************************* + * + * PNNI Designated transit list information element + */ +enum { + UNI_DTL_LOGNP = 0x01, + UNI_DTL_LOGNP_SIZE = 27, +}; + +struct uni_ie_dtl { + struct uni_iehdr h; + u_int ptr:16; + u_int num; + struct { + u_char node_level; + u_char node_id[21]; + u_int port_id; + } dtl[UNI_DTL_MAXNUM]; +}; + +/************************************************************************* + * + * PNNI Crankback information element + */ +enum uni_crankback { + UNI_CRANKBACK_IF = 0x02, + UNI_CRANKBACK_NODE = 0x03, + UNI_CRANKBACK_LINK = 0x04, +}; + +enum { + UNI_CAUSE_NXNODE_UNREACH = 128, + UNI_CAUSE_DTL_NOT_MY_ID = 160, +}; + +struct uni_ie_crankback { + struct uni_iehdr h; +#define UNI_CRANKBACK_TOP_P 0x0001 +#define UNI_CRANKBACK_TOPX_P 0x0002 +#define UNI_CRANKBACK_QOS_P 0x0004 + u_int level:8; + enum uni_crankback type; + union { + struct { + u_char level; + u_char id[21]; + } node; + struct { + u_char plevel; + u_char pid[21]; + u_int port; + u_char slevel; + u_char sid[21]; + } link; + } id; + u_int cause:8; + union { + struct { + u_int dir:8; + u_int port; + u_int avcr; + u_int crm; + u_int vf; + } top; + struct { + u_int ctd:1; + u_int cdv:1; + u_int clr:1; + u_int other:1; + } qos; + } diag; +}; + +/************************************************************************* + * + * PNNI Call_ing/called party soft PVPC/PVCC information element + */ +enum uni_soft_sel { + UNI_SOFT_SEL_ANY = 0x00, + UNI_SOFT_SEL_REQ = 0x02, + UNI_SOFT_SEL_ASS = 0x04, +}; + +struct uni_ie_calling_soft { + struct uni_iehdr h; +#define UNI_CALLING_SOFT_VCI_P 0x0001 + u_int vpi:12; + u_int vci:16; +}; +struct uni_ie_called_soft { + struct uni_iehdr h; +#define UNI_CALLED_SOFT_VPI_P 0x0001 +#define UNI_CALLED_SOFT_VCI_P 0x0002 + enum uni_soft_sel sel; + u_int vpi:12; + u_int vci:16; +}; + +/*************************************************************************/ + +#include <netnatm/msg/uni_ie.h> +#include <netnatm/msg/uni_msg.h> + +struct uni_all { + enum uni_msgtype mtype; + union uni_msgall u; +}; + +struct uni_ie { + enum uni_ietype ietype; + union uni_ieall u; +}; + +#endif diff --git a/sys/contrib/ngatm/netnatm/saal/saal_sscfu.c b/sys/contrib/ngatm/netnatm/saal/saal_sscfu.c new file mode 100644 index 000000000000..80140ba03d49 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/saal/saal_sscfu.c @@ -0,0 +1,577 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/saal/saal_sscfu.c,v 1.4 2004/07/08 08:22:10 brandt Exp $ + * + * SSCF on the UNI + */ + +#include <netnatm/saal/sscfu.h> +#include <netnatm/saal/sscfupriv.h> + +#define MKSTR(S) #S + +static const char *const sscf_sigs[] = { + MKSTR(SAAL_ESTABLISH_request), + MKSTR(SAAL_ESTABLISH_indication), + MKSTR(SAAL_ESTABLISH_confirm), + MKSTR(SAAL_RELEASE_request), + MKSTR(SAAL_RELEASE_confirm), + MKSTR(SAAL_RELEASE_indication), + MKSTR(SAAL_DATA_request), + MKSTR(SAAL_DATA_indication), + MKSTR(SAAL_UDATA_request), + MKSTR(SAAL_UDATA_indication), +}; + +static const char *const sscf_states[] = { + MKSTR(SSCF_RELEASED), + MKSTR(SSCF_AWAITING_ESTABLISH), + MKSTR(SSCF_AWAITING_RELEASE), + MKSTR(SSCF_ESTABLISHED), + MKSTR(SSCF_RESYNC), +}; + +#define AA_SIG(S,G,M) \ + ((S)->funcs->send_upper((S), (S)->aarg, (G), (M))) + +#define SSCOP_AASIG(S,G,M,P) \ + ((S)->funcs->send_lower((S), (S)->aarg, (G), (M), (P))) + +MEMINIT(); + +static void sscfu_unqueue(struct sscfu *sscf); + +/************************************************************/ +/* + * INSTANCE AND CLASS MANAGEMENT + */ + +/* + * Initialize SSCF. + */ +struct sscfu * +sscfu_create(void *a, const struct sscfu_funcs *funcs) +{ + struct sscfu *sscf; + + MEMZALLOC(sscf, struct sscfu *, sizeof(struct sscfu)); + if (sscf == NULL) + return (NULL); + + sscf->funcs = funcs; + sscf->aarg = a; + sscf->state = SSCFU_RELEASED; + sscf->inhand = 0; + SIGQ_INIT(&sscf->sigs); + sscf->debug = 0; + + return (sscf); +} + +/* + * Reset the instance. Call only if you know, what you're doing. + */ +void +sscfu_reset(struct sscfu *sscf) +{ + sscf->state = SSCFU_RELEASED; + sscf->inhand = 0; + SIGQ_CLEAR(&sscf->sigs); +} + +/* + * Destroy SSCF + */ +void +sscfu_destroy(struct sscfu *sscf) +{ + SIGQ_CLEAR(&sscf->sigs); + MEMFREE(sscf); +} + +enum sscfu_state +sscfu_getstate(const struct sscfu *sscf) +{ + return (sscf->state); +} + +u_int +sscfu_getdefparam(struct sscop_param *p) +{ + memset(p, 0, sizeof(*p)); + + p->timer_cc = 1000; + p->timer_poll = 750; + p->timer_keep_alive = 2000; + p->timer_no_response = 7000; + p->timer_idle = 15000; + p->maxk = 4096; + p->maxj = 4096; + p->maxcc = 4; + p->maxpd = 25; + + return (SSCOP_SET_TCC | SSCOP_SET_TPOLL | SSCOP_SET_TKA | + SSCOP_SET_TNR | SSCOP_SET_TIDLE | SSCOP_SET_MAXK | + SSCOP_SET_MAXJ | SSCOP_SET_MAXCC | SSCOP_SET_MAXPD); +} + +const char * +sscfu_signame(enum saal_sig sig) +{ + static char str[40]; + + if (sig >= sizeof(sscf_sigs)/sizeof(sscf_sigs[0])) { + sprintf(str, "BAD SAAL_SIGNAL %u", sig); + return (str); + } else { + return (sscf_sigs[sig]); + } +} + +const char * +sscfu_statename(enum sscfu_state s) +{ + static char str[40]; + + if (s >= sizeof(sscf_states)/sizeof(sscf_states[0])) { + sprintf(str, "BAD SSCFU state %u", s); + return (str); + } else { + return (sscf_states[s]); + } +} + +/************************************************************/ +/* + * EXTERNAL INPUT SIGNAL MAPPING + */ +static __inline void +set_state(struct sscfu *sscf, enum sscfu_state state) +{ + VERBOSE(sscf, SSCFU_DBG_STATE, (sscf, sscf->aarg, + "change state from %s to %s", + sscf_states[sscf->state], sscf_states[state])); + sscf->state = state; +} + +/* + * signal from SSCOP to SSCF + * Message must be freed by the user specified handler, if + * it is passed. + */ +void +sscfu_input(struct sscfu *sscf, enum sscop_aasig sig, + struct SSCFU_MBUF_T *m, u_int arg __unused) +{ + sscf->inhand = 1; + + VERBOSE(sscf, SSCFU_DBG_LSIG, (sscf, sscf->aarg, + "SSCF got signal %d. in state %s", sig, sscf_states[sscf->state])); + + switch (sig) { + + case SSCOP_RELEASE_indication: + /* arg is: UU, SRC */ + switch (sscf->state) { + + case SSCFU_RELEASED: + if (m) + MBUF_FREE(m); + goto badsig; + + case SSCFU_AWAITING_ESTABLISH: + set_state(sscf, SSCFU_RELEASED); + AA_SIG(sscf, SAAL_RELEASE_indication, m); + break; + + case SSCFU_AWAITING_RELEASE: + if (m) + MBUF_FREE(m); + goto badsig; + + case SSCFU_ESTABLISHED: + set_state(sscf, SSCFU_RELEASED); + AA_SIG(sscf, SAAL_RELEASE_indication, m); + break; + + case SSCFU_RESYNC: + set_state(sscf, SSCFU_RELEASED); + AA_SIG(sscf, SAAL_RELEASE_indication, m); + break; + } + break; + + case SSCOP_ESTABLISH_indication: + /* arg is: UU */ + switch (sscf->state) { + + case SSCFU_RELEASED: + set_state(sscf, SSCFU_ESTABLISHED); + SSCOP_AASIG(sscf, SSCOP_ESTABLISH_response, NULL, 1); + AA_SIG(sscf, SAAL_ESTABLISH_indication, m); + break; + + case SSCFU_AWAITING_ESTABLISH: + case SSCFU_AWAITING_RELEASE: + case SSCFU_ESTABLISHED: + case SSCFU_RESYNC: + if (m) + MBUF_FREE(m); + goto badsig; + } + break; + + case SSCOP_ESTABLISH_confirm: + /* arg is: UU */ + switch (sscf->state) { + + case SSCFU_RELEASED: + if (m) + MBUF_FREE(m); + goto badsig; + + case SSCFU_AWAITING_ESTABLISH: + set_state(sscf, SSCFU_ESTABLISHED); + AA_SIG(sscf, SAAL_ESTABLISH_confirm, m); + break; + + case SSCFU_AWAITING_RELEASE: + case SSCFU_ESTABLISHED: + case SSCFU_RESYNC: + if (m) + MBUF_FREE(m); + goto badsig; + } + break; + + case SSCOP_RELEASE_confirm: + /* arg is: */ + switch (sscf->state) { + + case SSCFU_RELEASED: + case SSCFU_AWAITING_ESTABLISH: + goto badsig; + + case SSCFU_AWAITING_RELEASE: + set_state(sscf, SSCFU_RELEASED); + AA_SIG(sscf, SAAL_RELEASE_confirm, NULL); + break; + + case SSCFU_ESTABLISHED: + case SSCFU_RESYNC: + goto badsig; + } + break; + + case SSCOP_DATA_indication: + /* arg is: MU */ + sscf->funcs->window(sscf, sscf->aarg, 1); + switch (sscf->state) { + + case SSCFU_RELEASED: + case SSCFU_AWAITING_ESTABLISH: + case SSCFU_AWAITING_RELEASE: + MBUF_FREE(m); + goto badsig; + + case SSCFU_ESTABLISHED: + AA_SIG(sscf, SAAL_DATA_indication, m); + break; + + case SSCFU_RESYNC: + MBUF_FREE(m); + goto badsig; + } + break; + + case SSCOP_RECOVER_indication: + /* arg is: */ + switch (sscf->state) { + + case SSCFU_RELEASED: + case SSCFU_AWAITING_ESTABLISH: + case SSCFU_AWAITING_RELEASE: + goto badsig; + + case SSCFU_ESTABLISHED: + SSCOP_AASIG(sscf, SSCOP_RECOVER_response, NULL, 0); + AA_SIG(sscf, SAAL_ESTABLISH_indication, NULL); + break; + + case SSCFU_RESYNC: + goto badsig; + } + break; + + case SSCOP_RESYNC_indication: + /* arg is: UU */ + switch (sscf->state) { + + case SSCFU_RELEASED: + case SSCFU_AWAITING_ESTABLISH: + case SSCFU_AWAITING_RELEASE: + if (m) + MBUF_FREE(m); + goto badsig; + + case SSCFU_ESTABLISHED: + SSCOP_AASIG(sscf, SSCOP_RESYNC_response, NULL, 0); + AA_SIG(sscf, SAAL_ESTABLISH_indication, m); + break; + + case SSCFU_RESYNC: + if (m) + MBUF_FREE(m); + goto badsig; + } + break; + + case SSCOP_RESYNC_confirm: + /* arg is: */ + switch (sscf->state) { + + case SSCFU_RELEASED: + case SSCFU_AWAITING_ESTABLISH: + case SSCFU_AWAITING_RELEASE: + case SSCFU_ESTABLISHED: + + case SSCFU_RESYNC: + set_state(sscf, SSCFU_ESTABLISHED); + AA_SIG(sscf, SAAL_ESTABLISH_confirm, NULL); + break; + } + break; + + case SSCOP_UDATA_indication: + /* arg is: MD */ + AA_SIG(sscf, SAAL_UDATA_indication, m); + break; + + + case SSCOP_RETRIEVE_indication: + if (m) + MBUF_FREE(m); + goto badsig; + + case SSCOP_RETRIEVE_COMPL_indication: + goto badsig; + + case SSCOP_ESTABLISH_request: + case SSCOP_RELEASE_request: + case SSCOP_ESTABLISH_response: + case SSCOP_DATA_request: + case SSCOP_RECOVER_response: + case SSCOP_RESYNC_request: + case SSCOP_RESYNC_response: + case SSCOP_UDATA_request: + case SSCOP_RETRIEVE_request: + ASSERT(0); + break; + } + + sscfu_unqueue(sscf); + return; + + badsig: + VERBOSE(sscf, SSCFU_DBG_ERR, (sscf, sscf->aarg, + "bad signal %d. in state %s", sig, sscf_states[sscf->state])); + sscfu_unqueue(sscf); +} + + +/* + * Handle signals from the user + */ +static void +sscfu_dosig(struct sscfu *sscf, enum saal_sig sig, struct SSCFU_MBUF_T *m) +{ + VERBOSE(sscf, SSCFU_DBG_EXEC, (sscf, sscf->aarg, + "executing signal %s(%s)", + sscf_sigs[sig], sscf_states[sscf->state])); + + switch (sig) { + + case SAAL_ESTABLISH_request: + /* arg is opt UU */ + switch (sscf->state) { + + case SSCFU_RELEASED: + set_state(sscf, SSCFU_AWAITING_ESTABLISH); + SSCOP_AASIG(sscf, SSCOP_ESTABLISH_request, m, 1); + break; + + case SSCFU_AWAITING_ESTABLISH: + if (m) + MBUF_FREE(m); + goto badsig; + + case SSCFU_AWAITING_RELEASE: + set_state(sscf, SSCFU_AWAITING_ESTABLISH); + SSCOP_AASIG(sscf, SSCOP_ESTABLISH_request, m, 1); + break; + + case SSCFU_ESTABLISHED: + set_state(sscf, SSCFU_RESYNC); + SSCOP_AASIG(sscf, SSCOP_RESYNC_request, m, 0); + break; + + case SSCFU_RESYNC: + if (m) + MBUF_FREE(m); + goto badsig; + } + break; + + case SAAL_RELEASE_request: + /* arg is opt UU */ + switch(sscf->state) { + + case SSCFU_RELEASED: + if (m) + MBUF_FREE(m); + AA_SIG(sscf, SAAL_RELEASE_confirm, NULL); + break; + + case SSCFU_AWAITING_ESTABLISH: + set_state(sscf, SSCFU_AWAITING_RELEASE); + SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0); + break; + + case SSCFU_AWAITING_RELEASE: + if (m) + MBUF_FREE(m); + goto badsig; + + case SSCFU_ESTABLISHED: + set_state(sscf, SSCFU_AWAITING_RELEASE); + SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0); + break; + + case SSCFU_RESYNC: + set_state(sscf, SSCFU_AWAITING_RELEASE); + SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0); + break; + } + break; + + case SAAL_DATA_request: + /* arg is DATA */ + switch (sscf->state) { + + case SSCFU_RELEASED: + case SSCFU_AWAITING_ESTABLISH: + case SSCFU_AWAITING_RELEASE: + MBUF_FREE(m); + goto badsig; + + case SSCFU_ESTABLISHED: + SSCOP_AASIG(sscf, SSCOP_DATA_request, m, 0); + break; + + case SSCFU_RESYNC: + MBUF_FREE(m); + goto badsig; + } + break; + + case SAAL_UDATA_request: + /* arg is UDATA */ + SSCOP_AASIG(sscf, SSCOP_UDATA_request, m, 0); + break; + + case SAAL_ESTABLISH_indication: + case SAAL_ESTABLISH_confirm: + case SAAL_RELEASE_confirm: + case SAAL_RELEASE_indication: + case SAAL_DATA_indication: + case SAAL_UDATA_indication: + ASSERT(0); + break; + } + return; + + badsig: + VERBOSE(sscf, SSCFU_DBG_ERR, (sscf, sscf->aarg, + "bad signal %s in state %s", sscf_sigs[sig], + sscf_states[sscf->state])); +} + +/* + * Handle user signal. + */ +int +sscfu_saalsig(struct sscfu *sscf, enum saal_sig sig, struct SSCFU_MBUF_T *m) +{ + struct sscfu_sig *s; + + if (sscf->inhand) { + VERBOSE(sscf, SSCFU_DBG_EXEC, (sscf, sscf->aarg, + "queuing user signal %s(%s)", + sscf_sigs[sig], sscf_states[sscf->state])); + SIG_ALLOC(s); + if (s == NULL) + return (ENOMEM); + s->sig = sig; + s->m = m; + SIGQ_APPEND(&sscf->sigs, s); + return (0); + } + + sscf->inhand = 1; + sscfu_dosig(sscf, sig, m); + sscfu_unqueue(sscf); + return (0); +} + +/* + * Unqueue all qeueued signals. Must be called with inhand==1. + */ +static void +sscfu_unqueue(struct sscfu *sscf) +{ + struct sscfu_sig *s; + + while ((s = SIGQ_GET(&sscf->sigs)) != NULL) { + sscfu_dosig(sscf, s->sig, s->m); + SIG_FREE(s); + } + sscf->inhand = 0; +} + +void +sscfu_setdebug(struct sscfu *sscf, u_int n) +{ + sscf->debug = n; +} + +u_int +sscfu_getdebug(const struct sscfu *sscf) +{ + return (sscf->debug); +} diff --git a/sys/contrib/ngatm/netnatm/saal/saal_sscop.c b/sys/contrib/ngatm/netnatm/saal/saal_sscop.c new file mode 100644 index 000000000000..0776eda9e4f0 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/saal/saal_sscop.c @@ -0,0 +1,4946 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/saal/saal_sscop.c,v 1.11 2004/07/08 08:22:13 brandt Exp $ + * + * Core SSCOP code (ITU-T Q.2110) + */ + +#include <netnatm/saal/sscop.h> +#include <netnatm/saal/sscoppriv.h> + +#ifndef FAILURE +#define FAILURE(S) +#endif + +#define MKSTR(S) #S + +static const char *const sscop_sigs[] = { + MKSTR(SSCOP_ESTABLISH_request), + MKSTR(SSCOP_ESTABLISH_indication), + MKSTR(SSCOP_ESTABLISH_response), + MKSTR(SSCOP_ESTABLISH_confirm), + MKSTR(SSCOP_RELEASE_request), + MKSTR(SSCOP_RELEASE_indication), + MKSTR(SSCOP_RELEASE_confirm), + MKSTR(SSCOP_DATA_request), + MKSTR(SSCOP_DATA_indication), + MKSTR(SSCOP_UDATA_request), + MKSTR(SSCOP_UDATA_indication), + MKSTR(SSCOP_RECOVER_indication), + MKSTR(SSCOP_RECOVER_response), + MKSTR(SSCOP_RESYNC_request), + MKSTR(SSCOP_RESYNC_indication), + MKSTR(SSCOP_RESYNC_response), + MKSTR(SSCOP_RESYNC_confirm), + MKSTR(SSCOP_RETRIEVE_request), + MKSTR(SSCOP_RETRIEVE_indication), + MKSTR(SSCOP_RETRIEVE_COMPL_indication), +}; + +static const char *const sscop_msigs[] = { + MKSTR(SSCOP_MDATA_request), + MKSTR(SSCOP_MDATA_indication), + MKSTR(SSCOP_MERROR_indication), +}; + +static const char *const states[] = { + MKSTR(SSCOP_IDLE), + MKSTR(SSCOP_OUT_PEND), + MKSTR(SSCOP_IN_PEND), + MKSTR(SSCOP_OUT_DIS_PEND), + MKSTR(SSCOP_OUT_RESYNC_PEND), + MKSTR(SSCOP_IN_RESYNC_PEND), + MKSTR(SSCOP_OUT_REC_PEND), + MKSTR(SSCOP_REC_PEND), + MKSTR(SSCOP_IN_REC_PEND), + MKSTR(SSCOP_READY), +}; + +#ifdef SSCOP_DEBUG +static const char *const events[] = { + MKSTR(SIG_BGN), + MKSTR(SIG_BGAK), + MKSTR(SIG_END), + MKSTR(SIG_ENDAK), + MKSTR(SIG_RS), + MKSTR(SIG_RSAK), + MKSTR(SIG_BGREJ), + MKSTR(SIG_SD), + MKSTR(SIG_ER), + MKSTR(SIG_POLL), + MKSTR(SIG_STAT), + MKSTR(SIG_USTAT), + MKSTR(SIG_UD), + MKSTR(SIG_MD), + MKSTR(SIG_ERAK), + + MKSTR(SIG_T_CC), + MKSTR(SIG_T_POLL), + MKSTR(SIG_T_KA), + MKSTR(SIG_T_NR), + MKSTR(SIG_T_IDLE), + + MKSTR(SIG_PDU_Q), + MKSTR(SIG_USER_DATA), + MKSTR(SIG_ESTAB_REQ), + MKSTR(SIG_ESTAB_RESP), + MKSTR(SIG_RELEASE_REQ), + MKSTR(SIG_RECOVER), + MKSTR(SIG_SYNC_REQ), + MKSTR(SIG_SYNC_RESP), + MKSTR(SIG_UDATA), + MKSTR(SIG_MDATA), + MKSTR(SIG_UPDU_Q), + MKSTR(SIG_MPDU_Q), + MKSTR(SIG_RETRIEVE), +}; + +static const char *const pdus[] = { + "illegale PDU type 0", /* no PDU type 0 */ + MKSTR(PDU_BGN), + MKSTR(PDU_BGAK), + MKSTR(PDU_END), + MKSTR(PDU_ENDAK), + MKSTR(PDU_RS), + MKSTR(PDU_RSAK), + MKSTR(PDU_BGREJ), + MKSTR(PDU_SD), + MKSTR(PDU_ER), + MKSTR(PDU_POLL), + MKSTR(PDU_STAT), + MKSTR(PDU_USTAT), + MKSTR(PDU_UD), + MKSTR(PDU_MD), + MKSTR(PDU_ERAK), +}; +#endif + +MEMINIT(); + +static void sscop_signal(struct sscop *, u_int, struct sscop_msg *); +static void sscop_save_signal(struct sscop *, u_int, struct sscop_msg *); +static void handle_sigs(struct sscop *); +static void sscop_set_state(struct sscop *, u_int); + +/************************************************************/ + + +/************************************************************/ +/* + * Queue macros + */ +#define SSCOP_MSG_FREE(MSG) \ + do { \ + if(MSG) { \ + MBUF_FREE((MSG)->m); \ + MSG_FREE((MSG)); \ + } \ + } while(0) + +static inline struct sscop_msg *QFIND(sscop_msgq_head_t *q, u_int rn) +{ + struct sscop_msg *msg = NULL, *m; + MSGQ_FOREACH(m, q) { + if(m->seqno == rn) { + msg = m; + break; + } + } + return msg; +} + +#define QINSERT(Q,M) \ + do { \ + struct sscop_msg *_msg = NULL, *_m; \ + MSGQ_FOREACH(_m, (Q)) { \ + if (_m->seqno > (M)->seqno) { \ + _msg = _m; \ + break; \ + } \ + } \ + if (_msg != NULL) \ + MSGQ_INSERT_BEFORE(_msg, (M)); \ + else \ + MSGQ_APPEND((Q), (M)); \ + } while (0) + + +/* + * Send an error indication to the management plane. + */ +#define MAAL_ERROR(S,E,C) \ + do { \ + VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \ + "MAA-Signal %s in state %s", \ + sscop_msigs[SSCOP_MERROR_indication], states[(S)->state])); \ + (S)->funcs->send_manage((S), (S)->aarg, \ + SSCOP_MERROR_indication, NULL, (E), (C)); \ + } while(0) + +#define MAAL_DATA(S,M) \ + do { \ + VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \ + "MAA-Signal %s in state %s", \ + sscop_msigs[SSCOP_MDATA_indication], states[(S)->state])); \ + (S)->funcs->send_manage((S), (S)->aarg, \ + SSCOP_MDATA_indication, (M), 0, 0); \ + } while(0) + +#define AAL_DATA(S,D,M,N) \ + do { \ + VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \ + "AA-Signal %s in state %s", \ + sscop_sigs[D], states[(S)->state])); \ + (S)->funcs->send_upper((S), (S)->aarg, (D), (M), (N)); \ + } while(0) + +#define AAL_SIG(S,D) \ + do { \ + VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \ + "AA-Signal %s in state %s", \ + sscop_sigs[D], states[(S)->state])); \ + (S)->funcs->send_upper((S), (S)->aarg, (D), NULL, 0); \ + } while(0) + +#ifdef SSCOP_DEBUG +#define AAL_SEND(S,M) do { \ + if (ISVERBOSE(S, SSCOP_DBG_PDU)) \ + sscop_dump_pdu(S, "tx", (M)); \ + (S)->funcs->send_lower((S), (S)->aarg, (M)); \ + } while(0) +#else +#define AAL_SEND(S,M) (S)->funcs->send_lower((S), (S)->aarg, (M)) +#endif + + +/* + * Free a save user-to-user data buffer and set the pointer to zero + * to signal, that it is free. + */ +#define FREE_UU(F) \ + do { \ + if(sscop->F) { \ + MBUF_FREE(sscop->F); \ + sscop->F = NULL; \ + } \ + } while(0) + +#define SET_UU(F,U) \ + do { \ + FREE_UU(F); \ + sscop->F = U->m; \ + U->m = NULL; \ + SSCOP_MSG_FREE(U); \ + } while(0) + +#define AAL_UU_SIGNAL(S, SIG, M, PL, SN) \ + do { \ + if(MBUF_LEN((M)->m) > 0) { \ + MBUF_UNPAD((M)->m,(PL)); \ + AAL_DATA((S), (SIG), (M)->m, (SN)); \ + (M)->m = NULL; \ + } else { \ + AAL_DATA((S), (SIG), NULL, (SN)); \ + } \ + SSCOP_MSG_FREE((M)); \ + } while(0) + + + +TIMER_FUNC(cc, CC) +TIMER_FUNC(nr, NR) +TIMER_FUNC(ka, KA) +TIMER_FUNC(poll, POLL) +TIMER_FUNC(idle, IDLE) + +/************************************************************/ +/* + * INSTANCE AND TYPE HANDLING. + */ +#ifdef SSCOP_DEBUG +static void +sscop_dump_pdu(struct sscop *sscop, const char *dir, + const struct SSCOP_MBUF_T *m) +{ + u_int32_t v1, v2, v3, v4; + u_int size = MBUF_LEN(m); + u_int n, i; + + if (size < 8) + return; + + v1 = MBUF_TRAIL32(m, -1); + v2 = MBUF_TRAIL32(m, -2); + + switch ((v1 >> 24) & 0xf) { + + case 0: + return; + + case PDU_BGN: + sscop->funcs->verbose(sscop, sscop->aarg, + "%s BGN n(mr)=%u n(sq)=%u pl=%u", + dir, v1 & 0xffffff, v2 & 0xff, (v1 >> 30) & 0x3); + return; + + case PDU_BGAK: + sscop->funcs->verbose(sscop, sscop->aarg, + "%s BGAK n(mr)=%u pl=%u", + dir, v1 & 0xffffff, (v1 >> 30) & 0x3); + return; + + case PDU_END: + sscop->funcs->verbose(sscop, sscop->aarg, + "%s END r=%u s=%u pl=%u", + dir, (v1 >> 29) & 1, (v1 >> 28) & 1, (v1 >> 30) & 0x3); + return; + + case PDU_ENDAK: + sscop->funcs->verbose(sscop, sscop->aarg, "%s ENDAK", dir); + return; + + case PDU_RS: + sscop->funcs->verbose(sscop, sscop->aarg, + "%s RS n(mr)=%u n(sq)=%u pl=%u", + dir, v1 & 0xffffff, v2 & 0xff, (v1 >> 30) & 0x3); + return; + + case PDU_RSAK: + sscop->funcs->verbose(sscop, sscop->aarg, "%s RSAK n(mr)=%u", + dir, v1 & 0xffffff); + return; + + case PDU_BGREJ: + sscop->funcs->verbose(sscop, sscop->aarg, "%s BGREJ pl=%u", + dir, (v1 >> 30) & 0x3); + return; + + case PDU_SD: + sscop->funcs->verbose(sscop, sscop->aarg, "%s SD n(s)=%u pl=%u", + dir, v1 & 0xffffff, (v1 >> 30) & 0x3); + return; + + case PDU_ER: + sscop->funcs->verbose(sscop, sscop->aarg, "%s ER n(mr)=%u n(sq)=%u", + dir, v1 & 0xffffff, v2 & 0xff); + return; + + case PDU_POLL: + sscop->funcs->verbose(sscop, sscop->aarg, "%s POLL n(s)=%u n(ps)=%u", + dir, v1 & 0xffffff, v2 & 0xffffff); + return; + + case PDU_STAT: + if (size < 12) + return; + v3 = MBUF_TRAIL32(m, -3); + sscop->funcs->verbose(sscop, sscop->aarg, + "%s STAT n(r)=%u n(mr)=%u n(ps)=%u", + dir, v1 & 0xffffff, v2 & 0xffffff, v3 & 0xffffff); + n = (size - 12) / 4; + for (i = 0; i < (size - 12) / 4; i++, n--) { + v4 = MBUF_TRAIL32(m, -4 - (int)i); + sscop->funcs->verbose(sscop, sscop->aarg, + " LE(%u)=%u", n, v4 & 0xffffff); + } + return; + + case PDU_USTAT: + if (size < 16) + return; + sscop->funcs->verbose(sscop, sscop->aarg, + "%s STAT n(r)=%u n(mr)=%u LE1=%u LE2=%u", + dir, v1 & 0xffffff, v2 & 0xffffff, + MBUF_TRAIL32(m, -4) & 0xffffff, + MBUF_TRAIL32(m, -3) & 0xffffff); + return; + + case PDU_UD: + sscop->funcs->verbose(sscop, sscop->aarg, + "%s UD pl=%u", dir, (v1 >> 30) & 0x3); + return; + + case PDU_MD: + sscop->funcs->verbose(sscop, sscop->aarg, + "%s MD pl=%u", dir, (v1 >> 30) & 0x3); + return; + + case PDU_ERAK: + sscop->funcs->verbose(sscop, sscop->aarg, + "%s ERAK n(mr)=%u", dir, v1 & 0xffffff); + return; + } +} +#endif + + +/* + * Initialize state of variables + */ +static void +sscop_init(struct sscop *sscop) +{ + sscop->state = SSCOP_IDLE; + + sscop->vt_sq = 0; + sscop->vr_sq = 0; + sscop->clear_buffers = 1; + + sscop->ll_busy = 0; + + sscop->rxq = 0; +} + +static void +sscop_clear(struct sscop *sscop) +{ + TIMER_STOP(sscop, cc); + TIMER_STOP(sscop, ka); + TIMER_STOP(sscop, nr); + TIMER_STOP(sscop, idle); + TIMER_STOP(sscop, poll); + + FREE_UU(uu_bgn); + FREE_UU(uu_bgak); + FREE_UU(uu_bgrej); + FREE_UU(uu_end); + FREE_UU(uu_rs); + + MSGQ_CLEAR(&sscop->xq); + MSGQ_CLEAR(&sscop->uxq); + MSGQ_CLEAR(&sscop->mxq); + MSGQ_CLEAR(&sscop->xbuf); + MSGQ_CLEAR(&sscop->rbuf); + + SIGQ_CLEAR(&sscop->sigs); + SIGQ_CLEAR(&sscop->saved_sigs); +} + + +/* + * Allocate instance memory, initialize the state of all variables. + */ +struct sscop * +sscop_create(void *a, const struct sscop_funcs *funcs) +{ + struct sscop *sscop; + + MEMZALLOC(sscop, struct sscop *, sizeof(struct sscop)); + if (sscop == NULL) + return (NULL); + + if (a == NULL) + sscop->aarg = sscop; + else + sscop->aarg = a; + sscop->funcs = funcs; + + sscop->maxk = MAXK; + sscop->maxj = MAXJ; + sscop->maxcc = MAXCC; + sscop->maxpd = MAXPD; + sscop->maxstat = MAXSTAT; + sscop->timercc = TIMERCC; + sscop->timerka = TIMERKA; + sscop->timernr = TIMERNR; + sscop->timerpoll = TIMERPOLL; + sscop->timeridle = TIMERIDLE; + sscop->robustness = 0; + sscop->poll_after_rex = 0; + sscop->mr = MAXMR; + + TIMER_INIT(sscop, cc); + TIMER_INIT(sscop, nr); + TIMER_INIT(sscop, ka); + TIMER_INIT(sscop, poll); + TIMER_INIT(sscop, idle); + + MSGQ_INIT(&sscop->xq); + MSGQ_INIT(&sscop->uxq); + MSGQ_INIT(&sscop->mxq); + MSGQ_INIT(&sscop->rbuf); + MSGQ_INIT(&sscop->xbuf); + + SIGQ_INIT(&sscop->sigs); + SIGQ_INIT(&sscop->saved_sigs); + + sscop_init(sscop); + + return (sscop); +} + +/* + * Free all resources in a sscop instance + */ +void +sscop_destroy(struct sscop *sscop) +{ + sscop_reset(sscop); + + MEMFREE(sscop); +} + +/* + * Reset the SSCOP instance. + */ +void +sscop_reset(struct sscop *sscop) +{ + sscop_clear(sscop); + sscop_init(sscop); +} + +void +sscop_getparam(const struct sscop *sscop, struct sscop_param *p) +{ + p->timer_cc = sscop->timercc; + p->timer_poll = sscop->timerpoll; + p->timer_keep_alive = sscop->timerka; + p->timer_no_response = sscop->timernr; + p->timer_idle = sscop->timeridle; + p->maxk = sscop->maxk; + p->maxj = sscop->maxj; + p->maxcc = sscop->maxcc; + p->maxpd = sscop->maxpd; + p->maxstat = sscop->maxstat; + p->mr = sscop->mr; + p->flags = 0; + if(sscop->robustness) + p->flags |= SSCOP_ROBUST; + if(sscop->poll_after_rex) + p->flags |= SSCOP_POLLREX; +} + +int +sscop_setparam(struct sscop *sscop, struct sscop_param *p, u_int *pmask) +{ + u_int mask = *pmask; + + /* can change only in idle state */ + if (sscop->state != SSCOP_IDLE) + return (EISCONN); + + *pmask = 0; + + /* + * first check all parameters + */ + if ((mask & SSCOP_SET_TCC) && p->timer_cc == 0) + *pmask |= SSCOP_SET_TCC; + if ((mask & SSCOP_SET_TPOLL) && p->timer_poll == 0) + *pmask |= SSCOP_SET_TPOLL; + if ((mask & SSCOP_SET_TKA) && p->timer_keep_alive == 0) + *pmask |= SSCOP_SET_TKA; + if ((mask & SSCOP_SET_TNR) && p->timer_no_response == 0) + *pmask |= SSCOP_SET_TNR; + if ((mask & SSCOP_SET_TIDLE) && p->timer_idle == 0) + *pmask |= SSCOP_SET_TIDLE; + if ((mask & SSCOP_SET_MAXK) && p->maxk > MAXMAXK) + *pmask |= SSCOP_SET_MAXK; + if ((mask & SSCOP_SET_MAXJ) && p->maxj > MAXMAXJ) + *pmask |= SSCOP_SET_MAXJ; + if ((mask & SSCOP_SET_MAXCC) && p->maxcc > 255) + *pmask |= SSCOP_SET_MAXCC; + if ((mask & SSCOP_SET_MAXPD) && p->maxpd >= (1 << 24)) + *pmask |= SSCOP_SET_MAXPD; + if ((mask & SSCOP_SET_MAXSTAT) && + ((p->maxstat & 1) == 0 || p->maxstat == 1 || p->maxstat == 2 || + p->maxstat * 4 > MAXMAXK - 8)) + *pmask |= SSCOP_SET_MAXSTAT; + if ((mask & SSCOP_SET_MR) && p->mr >= (1 << 24) - 1) + *pmask |= SSCOP_SET_MR; + + if (*pmask) + return (EINVAL); + + + /* + * now set it + */ + if (mask & SSCOP_SET_TCC) + sscop->timercc = p->timer_cc; + + if (mask & SSCOP_SET_TPOLL) + sscop->timerpoll = p->timer_poll; + + if (mask & SSCOP_SET_TKA) + sscop->timerka = p->timer_keep_alive; + + if (mask & SSCOP_SET_TNR) + sscop->timernr = p->timer_no_response; + + if (mask & SSCOP_SET_TIDLE) + sscop->timeridle = p->timer_idle; + + if (mask & SSCOP_SET_MAXK) + sscop->maxk = p->maxk; + if (mask & SSCOP_SET_MAXJ) + sscop->maxj = p->maxj; + + if (mask & SSCOP_SET_MAXCC) + sscop->maxcc = p->maxcc; + if (mask & SSCOP_SET_MAXPD) + sscop->maxpd = p->maxpd; + if (mask & SSCOP_SET_MAXSTAT) + sscop->maxstat = p->maxstat; + + if (mask & SSCOP_SET_MR) + sscop->mr = p->mr; + + if (mask & SSCOP_SET_ROBUST) + sscop->robustness = ((p->flags & SSCOP_ROBUST) != 0); + + if (mask & SSCOP_SET_POLLREX) + sscop->poll_after_rex = ((p->flags & SSCOP_POLLREX) != 0); + + return (0); +} + +enum sscop_state +sscop_getstate(const struct sscop *sscop) +{ + return (sscop->state); +} + + +/************************************************************/ +/* + * EXTERNAL INPUT SIGNAL MAPPING + */ + +/* + * Map AA signal to SSCOP internal signal + */ +int +sscop_aasig(struct sscop *sscop, enum sscop_aasig sig, + struct SSCOP_MBUF_T *m, u_int arg) +{ + struct sscop_msg *msg; + + if (sig >= sizeof(sscop_sigs)/sizeof(sscop_sigs[0])) { + VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg, + "AA-Signal %u - bad signal", sig)); + MBUF_FREE(m); + return (EINVAL); + } + VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg, + "AA-Signal %s in state %s with%s message", + sscop_sigs[sig], states[sscop->state], m ? "" : "out")); + + MSG_ALLOC(msg); + if (msg == NULL) { + FAILURE("sscop: cannot allocate aasig"); + MBUF_FREE(m); + return (ENOMEM); + } + + switch(sig) { + + case SSCOP_ESTABLISH_request: + msg->m = m; + msg->rexmit = arg; + sscop_signal(sscop, SIG_ESTAB_REQ, msg); + break; + + case SSCOP_ESTABLISH_response: + msg->m = m; + msg->rexmit = arg; + sscop_signal(sscop, SIG_ESTAB_RESP, msg); + break; + + case SSCOP_RELEASE_request: + msg->m = m; + sscop_signal(sscop, SIG_RELEASE_REQ, msg); + break; + + case SSCOP_DATA_request: + msg->m = m; + sscop_signal(sscop, SIG_USER_DATA, msg); + break; + + case SSCOP_UDATA_request: + msg->m = m; + sscop_signal(sscop, SIG_UDATA, msg); + break; + + case SSCOP_RECOVER_response: + MBUF_FREE(m); + MSG_FREE(msg); + sscop_signal(sscop, SIG_RECOVER, NULL); + break; + + case SSCOP_RESYNC_request: + msg->m = m; + sscop_signal(sscop, SIG_SYNC_REQ, msg); + break; + + case SSCOP_RESYNC_response: + MBUF_FREE(m); + MSG_FREE(msg); + sscop_signal(sscop, SIG_SYNC_RESP, NULL); + break; + + case SSCOP_RETRIEVE_request: + MBUF_FREE(m); + msg->rexmit = arg; + sscop_signal(sscop, SIG_RETRIEVE, msg); + break; + + case SSCOP_ESTABLISH_indication: + case SSCOP_ESTABLISH_confirm: + case SSCOP_RELEASE_indication: + case SSCOP_RELEASE_confirm: + case SSCOP_DATA_indication: + case SSCOP_UDATA_indication: + case SSCOP_RECOVER_indication: + case SSCOP_RESYNC_indication: + case SSCOP_RESYNC_confirm: + case SSCOP_RETRIEVE_indication: + case SSCOP_RETRIEVE_COMPL_indication: + MBUF_FREE(m); + MSG_FREE(msg); + return EINVAL; + } + + return 0; +} + +/* + * Signal from layer management. + */ +int +sscop_maasig(struct sscop *sscop, enum sscop_maasig sig, struct SSCOP_MBUF_T *m) +{ + struct sscop_msg *msg; + + if (sig >= sizeof(sscop_msigs)/sizeof(sscop_msigs[0])) { + VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg, + "MAA-Signal %u - bad signal", sig)); + MBUF_FREE(m); + return (EINVAL); + } + VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg, + "MAA-Signal %s in state %s with%s message", + sscop_msigs[sig], states[sscop->state], m ? "" : "out")); + + MSG_ALLOC(msg); + if (msg == NULL) { + FAILURE("sscop: cannot allocate maasig"); + MBUF_FREE(m); + return (ENOMEM); + } + + switch (sig) { + + case SSCOP_MDATA_request: + msg->m = m; + sscop_signal(sscop, SIG_MDATA, msg); + break; + + case SSCOP_MDATA_indication: + case SSCOP_MERROR_indication: + MBUF_FREE(m); + MSG_FREE(msg); + return (EINVAL); + } + return (0); +} + +/* + * Map PDU to SSCOP signal. + */ +void +sscop_input(struct sscop *sscop, struct SSCOP_MBUF_T *m) +{ + struct sscop_msg *msg; + union pdu pdu; + u_int size; + + MSG_ALLOC(msg); + if(msg == NULL) { + FAILURE("sscop: cannot allocate in pdu msg"); + MBUF_FREE(m); + return; + } + + msg->m = m; + msg->rexmit = 0; + + size = MBUF_LEN(m); + + if(size % 4 != 0 || size < 4) + goto err; + + pdu.sscop_null = MBUF_TRAIL32(m, -1); + + VERBOSE(sscop, SSCOP_DBG_PDU, (sscop, sscop->aarg, + "got %s, size=%u", pdus[pdu.sscop_type], size)); + +#ifdef SSCOP_DEBUG +#define ENSURE(C,F) if(!(C)) { VERBOSE(sscop, SSCOP_DBG_PDU, F); goto err; } +#else +#define ENSURE(C,F) if(!(C)) goto err +#endif + +#ifdef SSCOP_DEBUG + if (ISVERBOSE(sscop, SSCOP_DBG_PDU)) + sscop_dump_pdu(sscop, "rx", m); +#endif + + switch(pdu.sscop_type) { + + default: + ENSURE(0, (sscop, sscop->aarg, + "Bad PDU type %u", pdu.sscop_type)); + break; + + case PDU_BGN: + ENSURE(size >= 8U, (sscop, sscop->aarg, + "PDU_BGN size=%u", size)); + ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg, + "PDU_BGN size=%u pl=%u", size, pdu.sscop_pl)); + ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg, + "PDU_BGN size=%u", size)); + sscop_signal(sscop, SIG_BGN, msg); + break; + + case PDU_BGAK: + ENSURE(size >= 8U, (sscop, sscop->aarg, + "PDU_BGAK size=%u", size)); + ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg, + "PDU_BGAK size=%u pl=%u", size, pdu.sscop_pl)); + ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg, + "PDU_BGAK size=%u", size)); + sscop_signal(sscop, SIG_BGAK, msg); + break; + + case PDU_END: + ENSURE(size >= 8U, (sscop, sscop->aarg, + "PDU_END size=%u", size)); + ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg, + "PDU_END size=%u pl=%u", size, pdu.sscop_pl)); + ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg, + "PDU_END size=%u", size)); + sscop_signal(sscop, SIG_END, msg); + break; + + case PDU_ENDAK: + ENSURE(size == 8U, (sscop, sscop->aarg, + "PDU_ENDAK size=%u", size)); + sscop_signal(sscop, SIG_ENDAK, msg); + break; + + case PDU_BGREJ: + ENSURE(size >= 8U, (sscop, sscop->aarg, + "PDU_BGREJ size=%u", size)); + ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg, + "PDU_BGREJ size=%u pl=%u", size, pdu.sscop_pl)); + ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg, + "PDU_BGREJ size=%u", size)); + sscop_signal(sscop, SIG_BGREJ, msg); + break; + + case PDU_SD: + ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg, + "PDU_SD size=%u pl=%u", size, pdu.sscop_pl)); + ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg, + "PDU_SD size=%u", size)); + sscop_signal(sscop, SIG_SD, msg); + break; + + case PDU_UD: + ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg, + "PDU_UD size=%u pl=%u", size, pdu.sscop_pl)); + ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg, + "PDU_UD size=%u", size)); + sscop_signal(sscop, SIG_UD, msg); + break; + + case PDU_MD: + ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg, + "PDU_MD size=%u pl=%u", size, pdu.sscop_pl)); + ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg, + "PDU_MD size=%u", size)); + sscop_signal(sscop, SIG_MD, msg); + break; + + case PDU_POLL: + ENSURE(size == 8U, (sscop, sscop->aarg, + "PDU_POLL size=%u", size)); + sscop_signal(sscop, SIG_POLL, msg); + break; + + case PDU_STAT: + ENSURE(size >= 12U, (sscop, sscop->aarg, + "PDU_STAT size=%u", size)); + ENSURE(size <= 12U + 4 * sscop->maxstat, (sscop, sscop->aarg, + "PDU_STAT size=%u", size)); + sscop_signal(sscop, SIG_STAT, msg); + break; + + case PDU_RS: + ENSURE(size >= 8U, (sscop, sscop->aarg, + "PDU_RS size=%u", size)); + ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg, + "PDU_RS size=%u pl=%u", size, pdu.sscop_pl)); + ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg, + "PDU_RS size=%u", size)); + sscop_signal(sscop, SIG_RS, msg); + break; + + case PDU_RSAK: + ENSURE(size == 8U, (sscop, sscop->aarg, + "PDU_RSAK size=%u", size)); + sscop_signal(sscop, SIG_RSAK, msg); + break; + + case PDU_ER: + ENSURE(size == 8U, (sscop, sscop->aarg, + "PDU_ER size=%u", size)); + sscop_signal(sscop, SIG_ER, msg); + break; + + case PDU_ERAK: + ENSURE(size == 8U, (sscop, sscop->aarg, + "PDU_ERAK size=%u", size)); + sscop_signal(sscop, SIG_ERAK, msg); + break; + + case PDU_USTAT: + ENSURE(size == 16U, (sscop, sscop->aarg, + "PDU_ERAK size=%u", size)); + sscop_signal(sscop, SIG_USTAT, msg); + break; + } +#undef ENSURE + return; + + err: + MAAL_ERROR(sscop, 'U', 0); + SSCOP_MSG_FREE(msg); +} + +/************************************************************/ +/* + * UTILITIES + */ + +/* + * Move the receiver window by N packets + */ +u_int +sscop_window(struct sscop *sscop, u_int n) +{ + sscop->vr_mr += n; + return (SEQNO_DIFF(sscop->vr_mr, sscop->vr_r)); +} + +/* + * Lower layer busy handling + */ +u_int +sscop_setbusy(struct sscop *sscop, int busy) +{ + u_int old = sscop->ll_busy; + + if (busy > 0) + sscop->ll_busy = 1; + else if (busy == 0) { + sscop->ll_busy = 0; + if(old) + handle_sigs(sscop); + } + + return (old); +} + +const char * +sscop_signame(enum sscop_aasig sig) +{ + static char str[40]; + + if (sig >= sizeof(sscop_sigs)/sizeof(sscop_sigs[0])) { + sprintf(str, "BAD SSCOP_AASIG %u", sig); + return (str); + } else { + return (sscop_sigs[sig]); + } +} + +const char * +sscop_msigname(enum sscop_maasig sig) +{ + static char str[40]; + + if (sig >= sizeof(sscop_msigs)/sizeof(sscop_msigs[0])) { + sprintf(str, "BAD SSCOP_MAASIG %u", sig); + return (str); + } else { + return (sscop_msigs[sig]); + } +} + +const char * +sscop_statename(enum sscop_state s) +{ + static char str[40]; + + if (s >= sizeof(states)/sizeof(states[0])) { + sprintf(str, "BAD SSCOP_STATE %u", s); + return (str); + } else { + return (states[s]); + } +} + + +/************************************************************/ +/* + * MACROS + */ + +/* + * p 75: release buffers + */ +static void +m_release_buffers(struct sscop *sscop) +{ + MSGQ_CLEAR(&sscop->xq); + MSGQ_CLEAR(&sscop->xbuf); + sscop->rxq = 0; + MSGQ_CLEAR(&sscop->rbuf); +} + +/* + * P 75: Prepare retrival + */ +static void +m_prepare_retrieval(struct sscop *sscop) +{ + struct sscop_msg *msg; + + if (sscop->clear_buffers) { + MSGQ_CLEAR(&sscop->xq); + MSGQ_CLEAR(&sscop->xbuf); + } + MSGQ_FOREACH(msg, &sscop->xbuf) + msg->rexmit = 0; + sscop->rxq = 0; + + MSGQ_CLEAR(&sscop->rbuf); +} + +/* + * P 75: Prepare retrival + */ +static void +m_prepare_recovery(struct sscop *sscop) +{ + struct sscop_msg *msg; + + if(sscop->clear_buffers) { + MSGQ_CLEAR(&sscop->xq); + MSGQ_CLEAR(&sscop->xbuf); + } + MSGQ_FOREACH(msg, &sscop->xbuf) + msg->rexmit = 0; + sscop->rxq = 0; +} + + +/* + * P 75: Clear transmitter + */ +static void +m_clear_transmitter(struct sscop *sscop) +{ + if(!sscop->clear_buffers) { + MSGQ_CLEAR(&sscop->xq); + MSGQ_CLEAR(&sscop->xbuf); + } +} + + +/* + * p 75: Deliver data + * Freeing the message is the responibility of the handler function. + */ +static void +m_deliver_data(struct sscop *sscop) +{ + struct sscop_msg *msg; + u_int sn; + + if ((msg = MSGQ_GET(&sscop->rbuf)) == NULL) + return; + + if (sscop->clear_buffers) { + MSGQ_CLEAR(&sscop->rbuf); + return; + } + + sn = msg->seqno + 1; + AAL_DATA(sscop, SSCOP_DATA_indication, msg->m, msg->seqno); + MSG_FREE(msg); + + while ((msg = MSGQ_GET(&sscop->rbuf)) != NULL) { + ASSERT(msg->seqno == sn); + if (++sn == SSCOP_MAXSEQNO) + sn = 0; + AAL_DATA(sscop, SSCOP_DATA_indication, msg->m, msg->seqno); + MSG_FREE(msg); + } +} + +/* + * P 75: Initialize state variables + */ +static void +m_initialize_state(struct sscop *sscop) +{ + sscop->vt_s = 0; + sscop->vt_ps = 0; + sscop->vt_a = 0; + + sscop->vt_pa = 1; + sscop->vt_pd = 0; + sscop->credit = 1; + + sscop->vr_r = 0; + sscop->vr_h = 0; +} + +/* + * p 76: Data retrieval + */ +static void +m_data_retrieval(struct sscop *sscop, u_int rn) +{ + struct sscop_msg *s; + + if (rn != SSCOP_RETRIEVE_UNKNOWN) { + if(rn >= SSCOP_RETRIEVE_TOTAL) + rn = sscop->vt_a; + else + rn++; + while(rn >= sscop->vt_a && rn < sscop->vt_s) { + if(rn == SSCOP_MAXSEQNO) rn = 0; + if((s = QFIND(&sscop->xbuf, rn)) != NULL) { + MSGQ_REMOVE(&sscop->xbuf, s); + AAL_DATA(sscop, SSCOP_RETRIEVE_indication, + s->m, 0); + MSG_FREE(s); + } + rn++; + } + } + + while((s = MSGQ_GET(&sscop->xq)) != NULL) { + AAL_DATA(sscop, SSCOP_RETRIEVE_indication, s->m, 0); + MSG_FREE(s); + } + AAL_SIG(sscop, SSCOP_RETRIEVE_COMPL_indication); +} + +/* + * P 76: Detect retransmission. PDU type must already be stripped. + */ +static int +m_detect_retransmission(struct sscop *sscop, struct sscop_msg *msg) +{ + union bgn bgn; + + bgn.sscop_null = MBUF_TRAIL32(msg->m, -1); + + if (sscop->vr_sq == bgn.sscop_bgns) + return (1); + + sscop->vr_sq = bgn.sscop_bgns; + return (0); +} + +/* + * P 76: Set POLL timer + */ +static void +m_set_poll_timer(struct sscop *sscop) +{ + if(MSGQ_EMPTY(&sscop->xq) && sscop->vt_s == sscop->vt_a) + TIMER_RESTART(sscop, ka); + else + TIMER_RESTART(sscop, poll); +} + +/* + * P 77: Reset data transfer timers + */ +static void +m_reset_data_xfer_timers(struct sscop *sscop) +{ + TIMER_STOP(sscop, ka); + TIMER_STOP(sscop, nr); + TIMER_STOP(sscop, idle); + TIMER_STOP(sscop, poll); +} + +/* + * P 77: Set data transfer timers + */ +static void +m_set_data_xfer_timers(struct sscop *sscop) +{ + TIMER_RESTART(sscop, poll); + TIMER_RESTART(sscop, nr); +} + +/* + * P 77: Initialize VR(MR) + */ +static void +m_initialize_mr(struct sscop *sscop) +{ + sscop->vr_mr = sscop->mr; +} + +/************************************************************/ +/* + * CONDITIONS + */ +static int +c_ready_pduq(struct sscop *sscop) +{ + if (!sscop->ll_busy && + (sscop->rxq != 0 || + sscop->vt_s < sscop->vt_ms || + TIMER_ISACT(sscop, idle))) + return (1); + return (0); +} + +/************************************************************/ +/* + * SEND PDUS + */ + +/* + * Send BG PDU. + */ +static void +send_bgn(struct sscop *sscop, struct SSCOP_MBUF_T *uu) +{ + union pdu pdu; + union bgn bgn; + struct SSCOP_MBUF_T *m; + + pdu.sscop_null = 0; + pdu.sscop_type = PDU_BGN; + pdu.sscop_ns = sscop->vr_mr; + + bgn.sscop_null = 0; + bgn.sscop_bgns = sscop->vt_sq; + + if(uu) { + if ((m = MBUF_DUP(uu)) == NULL) { + FAILURE("sscop: cannot allocate BGN"); + return; + } + pdu.sscop_pl += MBUF_PAD4(m); + } else { + if ((m = MBUF_ALLOC(8)) == NULL) { + FAILURE("sscop: cannot allocate BGN"); + return; + } + } + + MBUF_APPEND32(m, bgn.sscop_null); + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send BGREJ PDU. + */ +static void +send_bgrej(struct sscop *sscop, struct SSCOP_MBUF_T *uu) +{ + union pdu pdu; + union bgn bgn; + struct SSCOP_MBUF_T *m; + + pdu.sscop_null = 0; + pdu.sscop_type = PDU_BGREJ; + bgn.sscop_null = 0; + + if(uu) { + if((m = MBUF_DUP(uu)) == NULL) { + FAILURE("sscop: cannot allocate BGREJ"); + return; + } + pdu.sscop_pl += MBUF_PAD4(m); + } else { + if((m = MBUF_ALLOC(8)) == NULL) { + FAILURE("sscop: cannot allocate BGREJ"); + return; + } + } + + MBUF_APPEND32(m, bgn.sscop_null); + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send BGAK PDU. + */ +static void +send_bgak(struct sscop *sscop, struct SSCOP_MBUF_T *uu) +{ + union pdu pdu; + union bgn bgn; + struct SSCOP_MBUF_T *m; + + pdu.sscop_null = 0; + pdu.sscop_type = PDU_BGAK; + pdu.sscop_ns = sscop->vr_mr; + bgn.sscop_null = 0; + + if(uu) { + if((m = MBUF_DUP(uu)) == NULL) { + FAILURE("sscop: cannot allocate BGAK"); + return; + } + pdu.sscop_pl += MBUF_PAD4(m); + } else { + if((m = MBUF_ALLOC(8)) == NULL) { + FAILURE("sscop: cannot allocate BGAK"); + return; + } + } + + MBUF_APPEND32(m, bgn.sscop_null); + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send SD PDU. The function makes a duplicate of the message. + */ +static void +send_sd(struct sscop *sscop, struct SSCOP_MBUF_T *m, u_int seqno) +{ + union pdu pdu; + + if((m = MBUF_DUP(m)) == NULL) { + FAILURE("sscop: cannot allocate SD"); + return; + } + + pdu.sscop_null = 0; + pdu.sscop_pl = 0; + pdu.sscop_type = PDU_SD; + pdu.sscop_ns = seqno; + + pdu.sscop_pl += MBUF_PAD4(m); + + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send a UD PDU. The caller must free the sscop msg part. + */ +static void +send_ud(struct sscop *sscop, struct SSCOP_MBUF_T *m) +{ + union pdu pdu; + + pdu.sscop_null = 0; + pdu.sscop_type = PDU_UD; + + pdu.sscop_pl += MBUF_PAD4(m); + + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send a MD PDU. The caller must free the sscop msg part. + */ +static void +send_md(struct sscop *sscop, struct SSCOP_MBUF_T *m) +{ + union pdu pdu; + + pdu.sscop_null = 0; + pdu.sscop_type = PDU_MD; + + pdu.sscop_pl += MBUF_PAD4(m); + + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send END PDU. + */ +static void +send_end(struct sscop *sscop, int src, struct SSCOP_MBUF_T *uu) +{ + union pdu pdu; + struct SSCOP_MBUF_T *m; + + sscop->last_end_src = src; + + pdu.sscop_null = 0; + pdu.sscop_s = src; + pdu.sscop_type = PDU_END; + + if(uu) { + if((m = MBUF_DUP(uu)) == NULL) { + FAILURE("sscop: cannot allocate END"); + return; + } + pdu.sscop_pl += MBUF_PAD4(m); + } else { + if((m = MBUF_ALLOC(8)) == NULL) { + FAILURE("sscop: cannot allocate END"); + return; + } + } + + MBUF_APPEND32(m, 0); + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send USTAT PDU. List must be terminated by -1. + */ +static void +send_ustat(struct sscop *sscop, ...) +{ + va_list ap; + int f; + u_int n; + union pdu pdu; + union seqno seqno; + struct SSCOP_MBUF_T *m; + + va_start(ap, sscop); + n = 0; + while((f = va_arg(ap, int)) >= 0) + n++; + va_end(ap); + + if((m = MBUF_ALLOC(n * 4 + 8)) == NULL) { + FAILURE("sscop: cannot allocate USTAT"); + return; + } + + va_start(ap, sscop); + while((f = va_arg(ap, int)) >= 0) { + seqno.sscop_null = 0; + seqno.sscop_n = f; + MBUF_APPEND32(m, seqno.sscop_null); + } + va_end(ap); + + seqno.sscop_null = 0; + seqno.sscop_n = sscop->vr_mr; + MBUF_APPEND32(m, seqno.sscop_null); + + pdu.sscop_null = 0; + pdu.sscop_type = PDU_USTAT; + pdu.sscop_ns = sscop->vr_r; + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send ER PDU. + */ +static void +send_er(struct sscop *sscop) +{ + union pdu pdu; + union bgn bgn; + struct SSCOP_MBUF_T *m; + + pdu.sscop_null = 0; + pdu.sscop_type = PDU_ER; + pdu.sscop_ns = sscop->vr_mr; + + bgn.sscop_null = 0; + bgn.sscop_bgns = sscop->vt_sq; + + if((m = MBUF_ALLOC(8)) == NULL) { + FAILURE("sscop: cannot allocate ER"); + return; + } + MBUF_APPEND32(m, bgn.sscop_null); + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send POLL PDU. + */ +static void +send_poll(struct sscop *sscop) +{ + union pdu pdu; + union seqno seqno; + struct SSCOP_MBUF_T *m; + + seqno.sscop_null = 0; + seqno.sscop_n = sscop->vt_ps; + + pdu.sscop_null = 0; + pdu.sscop_ns = sscop->vt_s; + pdu.sscop_type = PDU_POLL; + + if((m = MBUF_ALLOC(8)) == NULL) { + FAILURE("sscop: cannot allocate POLL"); + return; + } + MBUF_APPEND32(m, seqno.sscop_null); + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send STAT PDU. List is already in buffer. + */ +static void +send_stat(struct sscop *sscop, u_int nps, struct SSCOP_MBUF_T *m) +{ + union pdu pdu; + union seqno seqno; + + seqno.sscop_null = 0; + seqno.sscop_n = nps; + MBUF_APPEND32(m, seqno.sscop_null); + + seqno.sscop_null = 0; + seqno.sscop_n = sscop->vr_mr; + MBUF_APPEND32(m, seqno.sscop_null); + + pdu.sscop_null = 0; + pdu.sscop_type = PDU_STAT; + pdu.sscop_ns = sscop->vr_r; + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send ENDAK PDU. + */ +static void +send_endak(struct sscop *sscop) +{ + union pdu pdu; + union seqno seqno; + struct SSCOP_MBUF_T *m; + + seqno.sscop_null = 0; + pdu.sscop_null = 0; + pdu.sscop_type = PDU_ENDAK; + + if((m = MBUF_ALLOC(8)) == NULL) { + FAILURE("sscop: cannot allocate ENDAK"); + return; + } + MBUF_APPEND32(m, seqno.sscop_null); + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send ERAK PDU. + */ +static void +send_erak(struct sscop *sscop) +{ + union pdu pdu; + union seqno seqno; + struct SSCOP_MBUF_T *m; + + seqno.sscop_null = 0; + pdu.sscop_null = 0; + pdu.sscop_type = PDU_ERAK; + pdu.sscop_ns = sscop->vr_mr; + + if((m = MBUF_ALLOC(8)) == NULL) { + FAILURE("sscop: cannot allocate ERAK"); + return; + } + MBUF_APPEND32(m, seqno.sscop_null); + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send RS PDU + */ +static void +send_rs(struct sscop *sscop, int resend, struct SSCOP_MBUF_T *uu) +{ + union pdu pdu; + union bgn bgn; + struct SSCOP_MBUF_T *m; + + pdu.sscop_null = 0; + pdu.sscop_type = PDU_RS; + pdu.sscop_ns = resend ? sscop->rs_mr : sscop->vr_mr; + + bgn.sscop_null = 0; + bgn.sscop_bgns = resend ? sscop->rs_sq : sscop->vt_sq; + + sscop->rs_mr = pdu.sscop_ns; + sscop->rs_sq = bgn.sscop_bgns; + + if(uu) { + if((m = MBUF_DUP(uu)) == NULL) { + FAILURE("sscop: cannot allocate RS"); + return; + } + pdu.sscop_pl += MBUF_PAD4(m); + } else { + if((m = MBUF_ALLOC(8)) == NULL) { + FAILURE("sscop: cannot allocate RS"); + return; + } + } + + MBUF_APPEND32(m, bgn.sscop_null); + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/* + * Send RSAK pdu + */ +static void +send_rsak(struct sscop *sscop) +{ + union pdu pdu; + union seqno seqno; + struct SSCOP_MBUF_T *m; + + seqno.sscop_null = 0; + pdu.sscop_null = 0; + pdu.sscop_type = PDU_RSAK; + pdu.sscop_ns = sscop->vr_mr; + + if((m = MBUF_ALLOC(8)) == NULL) { + FAILURE("sscop: cannot allocate RSAK"); + return; + } + + MBUF_APPEND32(m, seqno.sscop_null); + MBUF_APPEND32(m, pdu.sscop_null); + + AAL_SEND(sscop, m); +} + +/************************************************************/ +/* + * P 31; IDLE && AA-ESTABLISH-request + * arg is UU data (opt). + */ +static void +sscop_idle_establish_req(struct sscop *sscop, struct sscop_msg *uu) +{ + u_int br = uu->rexmit; + + SET_UU(uu_bgn, uu); + + m_clear_transmitter(sscop); + + sscop->clear_buffers = br; + + sscop->vt_cc = 1; + sscop->vt_sq++; + + m_initialize_mr(sscop); + + send_bgn(sscop, sscop->uu_bgn); + + TIMER_RESTART(sscop, cc); + + sscop_set_state(sscop, SSCOP_OUT_PEND); +} + +/* + * P 31: IDLE && BGN PDU + * arg is the received PDU (freed). + */ +static void +sscop_idle_bgn(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + union bgn bgn; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(sscop->robustness) { + bgn.sscop_null = MBUF_STRIP32(msg->m); + sscop->vr_sq = bgn.sscop_bgns; + } else { + if(m_detect_retransmission(sscop, msg)) { + send_bgrej(sscop, sscop->uu_bgrej); + SSCOP_MSG_FREE(msg); + return; + } + (void)MBUF_STRIP32(msg->m); + } + + sscop->vt_ms = pdu.sscop_ns; + sscop_set_state(sscop, SSCOP_IN_PEND); + + AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); +} + +/* + * p 31: IDLE && ENDAK PDU + * p 34: OUT_PEND && ENDAK PDU + * p 34: OUT_PEND && SD PDU + * p 34: OUT_PEND && ERAK PDU + * p 34: OUT_PEND && END PDU + * p 34: OUT_PEND && STAT PDU + * p 34: OUT_PEND && USTAT PDU + * p 34: OUT_PEND && POLL PDU + * p 36: OUT_PEND && RS PDU + * p 36: OUT_PEND && RSAK PDU + * p 40: OUTGOING_DISCONNECT_PENDING && SD PDU + * p 40: OUTGOING_DISCONNECT_PENDING && BGAK PDU + * p 40: OUTGOING_DISCONNECT_PENDING && POLL PDU + * p 40: OUTGOING_DISCONNECT_PENDING && STAT PDU + * p 40: OUTGOING_DISCONNECT_PENDING && USTAT PDU + * p 41: OUTGOING_DISCONNECT_PENDING && ERAK PDU + * p 42: OUTGOING_DISCONNECT_PENDING && ER PDU + * p 42: OUTGOING_DISCONNECT_PENDING && RS PDU + * p 42: OUTGOING_DISCONNECT_PENDING && RSAK PDU + * p 43: OUTGOING_RESYNC && ER PDU + * p 43: OUTGOING_RESYNC && POLL PDU + * p 44: OUTGOING_RESYNC && STAT PDU + * p 44: OUTGOING_RESYNC && USTAT PDU + * p 45: OUTGOING_RESYNC && BGAK PDU + * p 45: OUTGOING_RESYNC && SD PDU + * p 45: OUTGOING_RESYNC && ERAK PDU + * P 60: READY && BGAK PDU + * P 60: READY && ERAK PDU + * arg is pdu (freed). + */ +static void +sscop_ignore_pdu(struct sscop *sscop __unused, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); +} + +/* + * p 31: IDLE && END PDU + * arg is pdu (freed). + */ +static void +sscop_idle_end(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + send_endak(sscop); +} + +/* + * p 31: IDLE && ER PDU + * arg is pdu (freed). + */ +static void +sscop_idle_er(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'L', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); +} + +/* + * p 31: IDLE && BGREJ PDU + * arg is pdu (freed). + */ +static void +sscop_idle_bgrej(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'D', 0); + FREE_UU(uu_end); +} + +/* + * p 32: IDLE && POLL PDU + * arg is pdu (freed). + */ +static void +sscop_idle_poll(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'G', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); +} + +/* + * p 32: IDLE && SD PDU + * arg is pdu (freed). + */ +static void +sscop_idle_sd(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'A', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); +} + +/* + * p 32: IDLE && BGAK PDU + * arg is pdu (freed). + */ +static void +sscop_idle_bgak(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'C', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); +} + +/* + * p 32: IDLE && ERAK PDU + * arg is pdu (freed). + */ +static void +sscop_idle_erak(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'M', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); +} + +/* + * p 32: IDLE && STAT PDU + * arg is pdu (freed). + */ +static void +sscop_idle_stat(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'H', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); +} + +/* + * p 32: IDLE && USTAT PDU + * arg is pdu (freed). + */ +static void +sscop_idle_ustat(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'I', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); +} + +/* + * p 33: IDLE & RS PDU + * arg is pdu (freed). + */ +static void +sscop_idle_rs(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'J', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); +} + +/* + * p 33: IDLE & RSAK PDU + * arg is pdu (freed). + */ +static void +sscop_idle_rsak(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'K', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); +} + +/* + * p 33: IDLE && PDU_Q + * p XX: OUTPEND && PDU_Q + * p 39: IN_PEND && PDU_Q + * p 45: OUT_RESYNC_PEND && PDU_Q + * p 48: IN_RESYNC_PEND && PDU_Q + * no arg + */ +static void +sscop_flush_pduq(struct sscop *sscop __unused, struct sscop_msg *unused __unused) +{ +#if 0 + MSGQ_CLEAR(&sscop->xq); +#endif +} + +/* + * p 34: OUT_PEND && BGAK PDU + * arg is pdu (freed). + */ +static void +sscop_outpend_bgak(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + sscop->vt_ms = pdu.sscop_ns; + + AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_confirm, msg, pdu.sscop_pl, 0); + + m_initialize_state(sscop); + m_set_data_xfer_timers(sscop); + + sscop_set_state(sscop, SSCOP_READY); +} + +/* + * P 34: OUT_PEND && BGREJ PDU + */ +static void +sscop_outpend_bgrej(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + + AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, 0); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * P 35: OUT_PEND && TIMER_CC expiry + * no arg + */ +static void +sscop_outpend_tcc(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + if(sscop->vt_cc >= sscop->maxcc) { + MAAL_ERROR(sscop, 'O', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + + sscop_set_state(sscop, SSCOP_IDLE); + } else { + sscop->vt_cc++; + send_bgn(sscop, sscop->uu_bgn); + TIMER_RESTART(sscop, cc); + } +} + +/* + * P 35: OUT_PEND && RELEASE_REQ + * arg is UU + */ +static void +sscop_outpend_release_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_end, uu); + + TIMER_STOP(sscop, cc); + sscop->vt_cc = 1; + send_end(sscop, 0, sscop->uu_end); + TIMER_RESTART(sscop, cc); + + sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); +} + +/* + * P 36: OUT_PEND && BGN PDU + * arg is the received PDU (freed). + */ +static void +sscop_outpend_bgn(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + SSCOP_MSG_FREE(msg); + return; + } + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + + sscop->vt_ms = pdu.sscop_ns; + + m_initialize_mr(sscop); + + send_bgak(sscop, sscop->uu_bgak); + + AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_confirm, msg, pdu.sscop_pl, 0); + + m_initialize_state(sscop); + + m_set_data_xfer_timers(sscop); + + sscop_set_state(sscop, SSCOP_READY); +} + +/* + * p 37: IN_PEND && AA-ESTABLISH.response + * arg is UU + */ +static void +sscop_inpend_establish_resp(struct sscop *sscop, struct sscop_msg *uu) +{ + u_int br = uu->rexmit; + + SET_UU(uu_bgak, uu); + + m_clear_transmitter(sscop); + sscop->clear_buffers = br; + m_initialize_mr(sscop); + send_bgak(sscop, sscop->uu_bgak); + m_initialize_state(sscop); + m_set_data_xfer_timers(sscop); + + sscop_set_state(sscop, SSCOP_READY); +} + +/* + * p 37: IN_PEND && AA-RELEASE.request + * arg is uu. + */ +static void +sscop_inpend_release_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_bgrej, uu); + + send_bgrej(sscop, sscop->uu_bgrej); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 37: IN_PEND && BGN PDU + * arg is pdu. (freed) + */ +static void +sscop_inpend_bgn(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + SSCOP_MSG_FREE(msg); + return; + } + (void)MBUF_STRIP32(msg->m); + + sscop->vt_ms = pdu.sscop_ns; + + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); + AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); +} + +/* + * p 37: IN_PEND && ER PDU + * arg is pdu (freed). + */ +static void +sscop_inpend_er(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'L', 0); + SSCOP_MSG_FREE(msg); +} + +/* + * p 37: IN_PEND && ENDAK PDU + * arg is pdu (freed). + */ +static void +sscop_inpend_endak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'F', 0); + + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + + sscop_set_state(sscop, SSCOP_IDLE); + + SSCOP_MSG_FREE(msg); +} + +/* + * p 38: IN_PEND && BGAK PDU + * arg is pdu (freed). + */ +static void +sscop_inpend_bgak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'C', 0); + + SSCOP_MSG_FREE(msg); +} + +/* + * p 38: IN_PEND && BGREJ PDU + * arg is pdu (freed). + */ +static void +sscop_inpend_bgrej(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'D', 0); + + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + + SSCOP_MSG_FREE(msg); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 38: IN_PEND && SD PDU + * arg is pdu (freed). + */ +static void +sscop_inpend_sd(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'A', 0); + + SSCOP_MSG_FREE(msg); + + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 38: IN_PEND && USTAT PDU + * arg is pdu (freed). + */ +static void +sscop_inpend_ustat(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'I', 0); + + SSCOP_MSG_FREE(msg); + + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 38: IN_PEND && STAT PDU + * arg is pdu (freed). + */ +static void +sscop_inpend_stat(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'H', 0); + + SSCOP_MSG_FREE(msg); + + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 38: IN_PEND && POLL PDU + * arg is pdu (freed). + */ +static void +sscop_inpend_poll(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'G', 0); + + SSCOP_MSG_FREE(msg); + + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 39: IN_PEND && ERAK PDU + * arg is pdu (freed). + */ +static void +sscop_inpend_erak(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'M', 0); +} + +/* + * p 39: IN_PEND & RS PDU + * arg is pdu (freed). + */ +static void +sscop_inpend_rs(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'J', 0); +} + +/* + * p 39: IN_PEND & RSAK PDU + * arg is pdu (freed). + */ +static void +sscop_inpend_rsak(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'K', 0); +} + +/* + * p 39: IN_PEND && END PDU + * arg is pdu (freed). + * no uui + */ +static void +sscop_inpend_end(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + (void)MBUF_STRIP32(msg->m); + + send_endak(sscop); + + AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, + msg, pdu.sscop_pl, (u_int)pdu.sscop_s); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 40: OUT_DIS_PEND && SSCOP_ESTABLISH_request + * no arg. + * no uui. + */ +static void +sscop_outdis_establish_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_bgn, uu); + + TIMER_STOP(sscop, cc); + m_clear_transmitter(sscop); + sscop->clear_buffers = 1; + sscop->vt_cc = 1; + sscop->vt_sq++; + m_initialize_mr(sscop); + send_bgn(sscop, sscop->uu_bgn); + TIMER_RESTART(sscop, cc); + + sscop_set_state(sscop, SSCOP_OUT_PEND); +} + +/* + * p 41: OUT_DIS_PEND && END PDU + * arg is pdu (freed). + */ +static void +sscop_outdis_end(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + send_endak(sscop); + + AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_confirm, msg, pdu.sscop_pl, 0); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 41: OUT_DIS_PEND && ENDAK PDU + * p 41: OUT_DIS_PEND && BGREJ PDU + * arg is pdu (freed) + */ +static void +sscop_outdis_endak(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + + AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_confirm, msg, pdu.sscop_pl, 0); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 41: OUT_DIS_PEND && TIMER CC expiry + * no arg + */ +static void +sscop_outdis_cc(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + if(sscop->vt_cc >= sscop->maxcc) { + MAAL_ERROR(sscop, 'O', 0); + AAL_SIG(sscop, SSCOP_RELEASE_confirm); + sscop_set_state(sscop, SSCOP_IDLE); + } else { + sscop->vt_cc++; + send_end(sscop, sscop->last_end_src, sscop->uu_end); + TIMER_RESTART(sscop, cc); + } +} + +/* + * p 42: OUT_DIS_PEND && BGN PDU + * arg is pdu (freed). + */ +static void +sscop_outdis_bgn(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + FREE_UU(uu_bgak); + send_bgak(sscop, NULL); + send_end(sscop, sscop->last_end_src, sscop->uu_end); + SSCOP_MSG_FREE(msg); + + } else { + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + sscop->vt_ms = pdu.sscop_ns; + AAL_SIG(sscop, SSCOP_RELEASE_confirm); + AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, + msg, pdu.sscop_pl, 0); + sscop_set_state(sscop, SSCOP_IN_PEND); + } +} + +/* + * p 43: OUT_RESYNC_PEND && BGN PDU + * arg is pdu (freed). + */ +static void +sscop_outsync_bgn(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + send_bgak(sscop, sscop->uu_bgak); + send_rs(sscop, 1, sscop->uu_rs); + SSCOP_MSG_FREE(msg); + } else { + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + sscop->vt_ms = pdu.sscop_ns; + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); + AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, + msg, pdu.sscop_pl, 0); + sscop_set_state(sscop, SSCOP_IN_PEND); + } +} + +/* + * p 43: OUT_RESYNC_PEND && ENDAK PDU + * arg is pdu (freed). + */ +static void +sscop_outsync_endak(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + TIMER_STOP(sscop, cc); + MAAL_ERROR(sscop, 'F', 0); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 43: OUT_RESYNC_PEND && BGREJ PDU + * arg is pdu (freed). + */ +static void +sscop_outsync_bgrej(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + TIMER_STOP(sscop, cc); + MAAL_ERROR(sscop, 'D', 0); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 43: OUT_RESYNC_PEND && END PDU + * arg is pdu (freed). + * no UU-data + */ +static void +sscop_outsync_end(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + send_endak(sscop); + AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, + (u_int)pdu.sscop_s); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 44: OUT_RESYNC && TIMER CC expiry + */ +static void +sscop_outsync_cc(struct sscop *sscop, struct sscop_msg *msg __unused) +{ + if(sscop->vt_cc == sscop->maxcc) { + MAAL_ERROR(sscop, 'O', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); + } else { + sscop->vt_cc++; + send_rs(sscop, 1, sscop->uu_rs); + TIMER_RESTART(sscop, cc); + } +} + +/* + * p 44: OUT_RESYNC && AA-RELEASE.request + * arg is UU + */ +static void +sscop_outsync_release_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_end, uu); + + TIMER_STOP(sscop, cc); + sscop->vt_cc = 1; + send_end(sscop, 0, sscop->uu_end); + TIMER_RESTART(sscop, cc); + sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); +} + +/* + * p 45: OUT_RESYNC && RS PDU + * arg is pdu (freed). + */ +static void +sscop_outsync_rs(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + SSCOP_MSG_FREE(msg); + return; + } + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + sscop->vt_ms = pdu.sscop_ns; + m_initialize_mr(sscop); + send_rsak(sscop); + AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_confirm, msg, pdu.sscop_pl, 0); + m_initialize_state(sscop); + m_set_data_xfer_timers(sscop); + sscop_set_state(sscop, SSCOP_READY); +} + +/* + * p 45: OUT_RESYNC && RSAK PDU + * arg is pdu (freed). + */ +static void +sscop_outsync_rsak(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + SSCOP_MSG_FREE(msg); + + TIMER_STOP(sscop, cc); + sscop->vt_ms = pdu.sscop_ns; + AAL_SIG(sscop, SSCOP_RESYNC_confirm); + m_initialize_state(sscop); + m_set_data_xfer_timers(sscop); + sscop_set_state(sscop, SSCOP_READY); +} + +/* + * p 46: IN_RESYNC_PEND && AA-RESYNC.response + */ +static void +sscop_insync_sync_resp(struct sscop *sscop, struct sscop_msg *noarg __unused) +{ + m_initialize_mr(sscop); + send_rsak(sscop); + m_clear_transmitter(sscop); + m_initialize_state(sscop); + m_set_data_xfer_timers(sscop); + sscop_set_state(sscop, SSCOP_READY); +} + +/* + * p 46: IN_RESYNC_PEND && AA-RELEASE.request + * arg is uu + */ +static void +sscop_insync_release_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_end, uu); + + sscop->vt_cc = 1; + send_end(sscop, 0, sscop->uu_end); + TIMER_RESTART(sscop, cc); + sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); +} + +/* + * p 46: IN_RESYNC_PEND && ENDAK PDU + * arg is pdu (freed). + */ +static void +sscop_insync_endak(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'F', 0); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 46: IN_RESYNC_PEND && BGREJ PDU + * arg is pdu (freed). + */ +static void +sscop_insync_bgrej(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'D', 0); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 46: IN_RESYNC_PEND && END PDU + * arg is pdu (freed). + */ +static void +sscop_insync_end(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + (void)MBUF_STRIP32(msg->m); + + send_endak(sscop); + AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, + msg, pdu.sscop_pl, (u_int)pdu.sscop_s); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 47: IN_RESYNC_PEND && ER PDU + * arg is pdu (freed). + */ +static void +sscop_insync_er(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'L', 0); +} + +/* + * p 47: IN_RESYNC_PEND && BGN PDU + * arg is pdu (freed). + */ +static void +sscop_insync_bgn(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + MAAL_ERROR(sscop, 'B', 0); + SSCOP_MSG_FREE(msg); + return; + } + (void)MBUF_STRIP32(msg->m); + + sscop->vt_ms = pdu.sscop_ns; + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); + AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); + + sscop_set_state(sscop, SSCOP_IN_PEND); +} + +/* + * p 47: IN_RESYNC_PEND && SD PDU + * arg is pdu (freed). + */ +static void +sscop_insync_sd(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'A', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 47: IN_RESYNC_PEND && POLL PDU + * arg is pdu (freed). + */ +static void +sscop_insync_poll(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'G', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 47: IN_RESYNC_PEND && STAT PDU + * arg is pdu (freed). + */ +static void +sscop_insync_stat(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'H', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 47: IN_RESYNC_PEND && USTAT PDU + * arg is pdu (freed). + */ +static void +sscop_insync_ustat(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'I', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 48: IN_RESYNC_PEND && BGAK PDU + * arg is pdu (freed). + */ +static void +sscop_insync_bgak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'C', 0); + SSCOP_MSG_FREE(msg); +} + +/* + * p 48: IN_RESYNC_PEND && ERAK PDU + * arg is pdu (freed). + */ +static void +sscop_insync_erak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'M', 0); + SSCOP_MSG_FREE(msg); +} + +/* + * p 48: IN_RESYNC_PEND && RS PDU + * arg is pdu (freed). + */ +static void +sscop_insync_rs(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + SSCOP_MSG_FREE(msg); + return; + } + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'J', 0); +} + +/* + * p 48: IN_RESYNC_PEND && RSAK PDU + * arg is pdu (freed). + */ +static void +sscop_insync_rsak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'K', 0); + SSCOP_MSG_FREE(msg); +} + + +/* + * p 49: OUT_REC_PEND && AA-DATA.request + * arg is message (queued). + */ +static void +sscop_outrec_userdata(struct sscop *sscop, struct sscop_msg *msg) +{ + if(!sscop->clear_buffers) { + MSGQ_APPEND(&sscop->xq, msg); + sscop_signal(sscop, SIG_PDU_Q, msg); + } else { + SSCOP_MSG_FREE(msg); + } +} + +/* + * p 49: OUT_REC_PEND && BGAK PDU + * arg is pdu (freed) + */ +static void +sscop_outrec_bgak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'C', 0); + + SSCOP_MSG_FREE(msg); +} + +/* + * p 49: OUT_REC_PEND && ERAK PDU + * arg is pdu (freed) + */ +static void +sscop_outrec_erak(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + sscop->vt_ms = pdu.sscop_ns; + m_deliver_data(sscop); + + AAL_SIG(sscop, SSCOP_RECOVER_indication); + + sscop_set_state(sscop, SSCOP_REC_PEND); + + SSCOP_MSG_FREE(msg); +} + +/* + * p 49: OUT_REC_PEND && END PDU + * arg is pdu (freed) + */ +static void +sscop_outrec_end(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + send_endak(sscop); + AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, + msg, pdu.sscop_pl, (u_int)pdu.sscop_s); + + MSGQ_CLEAR(&sscop->rbuf); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 49: OUT_REC_PEND && ENDAK PDU + * arg is pdu (freed) + */ +static void +sscop_outrec_endak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'F', 0); + TIMER_STOP(sscop, cc); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + MSGQ_CLEAR(&sscop->rbuf); + + sscop_set_state(sscop, SSCOP_IDLE); + + SSCOP_MSG_FREE(msg); +} + +/* + * p 49: OUT_REC_PEND && BGREJ PDU + * arg is pdu (freed) + */ +static void +sscop_outrec_bgrej(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'D', 0); + TIMER_STOP(sscop, cc); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + MSGQ_CLEAR(&sscop->rbuf); + + sscop_set_state(sscop, SSCOP_IDLE); + + SSCOP_MSG_FREE(msg); +} + +/* + * p 50: OUT_REC_PEND && TIMER CC expiry + * no arg. + */ +static void +sscop_outrec_cc(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + if(sscop->vt_cc >= sscop->maxcc) { + MAAL_ERROR(sscop, 'O', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + MSGQ_CLEAR(&sscop->rbuf); + sscop_set_state(sscop, SSCOP_IDLE); + } else { + sscop->vt_cc++; + send_er(sscop); + TIMER_RESTART(sscop, cc); + } +} + +/* + * p 50: OUT_REC_PEND && SSCOP_RELEASE_request + * arg is UU + */ +static void +sscop_outrec_release_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_end, uu); + + TIMER_STOP(sscop, cc); + sscop->vt_cc = 1; + send_end(sscop, 0, sscop->uu_end); + MSGQ_CLEAR(&sscop->rbuf); + TIMER_RESTART(sscop, cc); + + sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); +} + +/* + * p 51: OUT_REC_PEND && AA-RESYNC.request + * arg is uu + */ +static void +sscop_outrec_sync_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_rs, uu); + + TIMER_STOP(sscop, cc); + sscop->vt_cc = 1; + sscop->vt_sq++; + m_initialize_mr(sscop); + send_rs(sscop, 0, sscop->uu_rs); + m_clear_transmitter(sscop); + MSGQ_CLEAR(&sscop->rbuf); + TIMER_RESTART(sscop, cc); +} + +/* + * p 51: OUT_REC_PEND && BGN PDU + * arg is pdu (freed). + * no uui + */ +static void +sscop_outrec_bgn(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + MAAL_ERROR(sscop, 'B', 0); + SSCOP_MSG_FREE(msg); + } else { + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + sscop->vt_ms = pdu.sscop_ns; + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); + AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, + msg, pdu.sscop_pl, 0); + MSGQ_CLEAR(&sscop->rbuf); + + sscop_set_state(sscop, SSCOP_IN_PEND); + } +} + +/* + * p 51: OUT_REC_PEND && ER PDU + * arg is pdu (freed). + */ +static void +sscop_outrec_er(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + MAAL_ERROR(sscop, 'L', 0); + } else { + TIMER_STOP(sscop, cc); + sscop->vt_ms = pdu.sscop_ns; + m_initialize_mr(sscop); + send_erak(sscop); + m_deliver_data(sscop); + + AAL_SIG(sscop, SSCOP_RECOVER_indication); + + sscop_set_state(sscop, SSCOP_REC_PEND); + } + + SSCOP_MSG_FREE(msg); +} + +/* + * p 52: OUT_REC_PEND && SD PDU queued + * no arg. + */ +static void +sscop_outrec_pduq(struct sscop *sscop, struct sscop_msg *msg) +{ + sscop_save_signal(sscop, SIG_PDU_Q, msg); +} + +/* + * p 52: OUT_REC_PEND && RSAK PDU + * arg is pdu (freed). + */ +static void +sscop_outrec_rsak(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'K', 0); +} + +/* + * p 52: OUT_REC_PEND && RS PDU + * arg is pdu (freed). + */ +static void +sscop_outrec_rs(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'J', 0); + return; + } + (void)MBUF_STRIP32(msg->m); + + TIMER_STOP(sscop, cc); + sscop->vt_ms = pdu.sscop_ns; + AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0); + MSGQ_CLEAR(&sscop->rbuf); + sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND); +} + +/* + * p 53: REC_PEND && BGAK PDU + * arg is pdu (freed) + */ +static void +sscop_rec_bgak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'C', 0); + + SSCOP_MSG_FREE(msg); +} + +/* + * p 53: REC_PEND && END PDU + * arg is pdu (freed) + * no uui + */ +static void +sscop_rec_end(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + (void)MBUF_STRIP32(msg->m); + + send_endak(sscop); + AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, + msg, pdu.sscop_pl, (u_int)pdu.sscop_s); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 53: REC_PEND && ENDAK PDU + * arg is pdu (freed) + */ +static void +sscop_rec_endak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'F', 0); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); + SSCOP_MSG_FREE(msg); +} + +/* + * p 53: REC_PEND && BGREJ PDU + * arg is pdu (freed) + */ +static void +sscop_rec_bgrej(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'D', 0); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); + SSCOP_MSG_FREE(msg); +} + +/* + * p 54: REC_PEND && RELEASE + * arg is UU + */ +static void +sscop_rec_release_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_end, uu); + + sscop->vt_cc = 1; + send_end(sscop, 0, sscop->uu_end); + TIMER_RESTART(sscop, cc); + + sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); +} + +/* + * p 54: REC_PEND && RSAK PDU + * arg is pdu (freed). + */ +static void +sscop_rec_rsak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'K', 0); + SSCOP_MSG_FREE(msg); +} + + +/* + * p 54: REC_PEND && RS PDU + * arg is pdu (freed). + */ +static void +sscop_rec_rs(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'J', 0); + return; + } + (void)MBUF_STRIP32(msg->m); + + sscop->vt_ms = pdu.sscop_ns; + AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0); + + sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND); +} + +/* + * p 54: REC_PEND && RECOVER response + * no arg + */ +static void +sscop_rec_recover(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + if(!sscop->clear_buffers) { + MSGQ_CLEAR(&sscop->xbuf); + } + m_initialize_state(sscop); + m_set_data_xfer_timers(sscop); + + sscop_set_state(sscop, SSCOP_READY); +} + +/* + * p 54: REC_PEND && RESYNC request + * arg is uu + */ +static void +sscop_rec_sync_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_rs, uu); + + m_clear_transmitter(sscop); + sscop->vt_cc = 1; + sscop->vt_sq++; + m_initialize_mr(sscop); + send_rs(sscop, 0, sscop->uu_rs); + TIMER_RESTART(sscop, cc); + + sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND); +} + +/* + * p 55: REC_PEND && SD PDU queued + * no arg + */ +static void +sscop_rec_pduq(struct sscop *sscop, struct sscop_msg *msg) +{ + sscop_save_signal(sscop, SIG_PDU_Q, msg); +} + +/* + * p 55: REC_PEND && ER PDU + * arg is pdu (freed). + */ +static void +sscop_rec_er(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + send_erak(sscop); + } else { + MAAL_ERROR(sscop, 'L', 0); + } + SSCOP_MSG_FREE(msg); +} + +/* + * p 55: REC_PEND && BGN PDU + * arg is pdu (freed) + * no uui + */ +static void +sscop_rec_bgn(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + MAAL_ERROR(sscop, 'B', 0); + SSCOP_MSG_FREE(msg); + return; + } + (void)MBUF_STRIP32(msg->m); + + sscop->vt_ms = pdu.sscop_ns; + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); + AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); + + sscop_set_state(sscop, SSCOP_IN_PEND); +} + +/* + * p 55: REC_PEND && STAT PDU + * arg is pdu (freed) + */ +static void +sscop_rec_stat(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'H', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); + SSCOP_MSG_FREE(msg); +} + +/* + * p 55: REC_PEND && USTAT PDU + * arg is pdu (freed) + */ +static void +sscop_rec_ustat(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'I', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + sscop_set_state(sscop, SSCOP_IDLE); + SSCOP_MSG_FREE(msg); +} + +/* + * p 56: IN_REC_PEND && AA-RECOVER.response + * no arg + */ +static void +sscop_inrec_recover(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + if(!sscop->clear_buffers) { + MSGQ_CLEAR(&sscop->xbuf); + } + m_initialize_mr(sscop); + send_erak(sscop); + m_initialize_state(sscop); + m_set_data_xfer_timers(sscop); + + sscop_set_state(sscop, SSCOP_READY); +} + +/* + * p 56: IN_REC_PEND && SD PDU queued + * no arg + */ +static void +sscop_inrec_pduq(struct sscop *sscop, struct sscop_msg *msg) +{ + sscop_save_signal(sscop, SIG_PDU_Q, msg); +} + +/* + * p 56: IN_REC_PEND && AA-RELEASE.request + * arg is UU + */ +static void +sscop_inrec_release_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_end, uu); + + sscop->vt_cc = 1; + send_end(sscop, 0, sscop->uu_end); + TIMER_RESTART(sscop, cc); + + sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); +} + +/* + * p 56: IN_REC_PEND && END PDU + * arg is pdu (freed). + * no uui + */ +static void +sscop_inrec_end(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + (void)MBUF_STRIP32(msg->m); + + send_endak(sscop); + AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, + msg, pdu.sscop_pl, (u_int)pdu.sscop_s); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 56: IN_REC_PEND && RESYNC_REQ + */ +static void +sscop_inrec_sync_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_rs, uu); + + m_clear_transmitter(sscop); + sscop->vt_cc = 1; + sscop->vt_sq++; + m_initialize_mr(sscop); + send_rs(sscop, 0, sscop->uu_rs); + TIMER_RESTART(sscop, cc); + + sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND); +} + + +/* + * p 57: IN_REC_PEND && ENDAK PDU + * arg is pdu (freed) + */ +static void +sscop_inrec_endak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'F', 0); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + SSCOP_MSG_FREE(msg); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 57: IN_REC_PEND && BGREJ PDU + * arg is pdu (freed) + */ +static void +sscop_inrec_bgrej(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'D', 0); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + SSCOP_MSG_FREE(msg); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 57: IN_REC_PEND && USTAT PDU + * arg is pdu (freed) + */ +static void +sscop_inrec_ustat(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'I', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + SSCOP_MSG_FREE(msg); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 57: IN_REC_PEND && STAT PDU + * arg is pdu (freed) + */ +static void +sscop_inrec_stat(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'H', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + SSCOP_MSG_FREE(msg); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 57: IN_REC_PEND && POLL PDU + * arg is pdu (freed) + */ +static void +sscop_inrec_poll(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'G', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + SSCOP_MSG_FREE(msg); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 57: IN_REC_PEND && SD PDU + * arg is pdu (freed) + */ +static void +sscop_inrec_sd(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'A', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + SSCOP_MSG_FREE(msg); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 58: IN_REC_PEND && RSAK PDU + * arg is pdu (freed). + */ +static void +sscop_inrec_rsak(struct sscop *sscop, struct sscop_msg *msg) +{ + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'K', 0); +} + +/* + * p 58: IN_REC_PEND && RS PDU + * arg is pdu (freed). + */ +static void +sscop_inrec_rs(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + SSCOP_MSG_FREE(msg); + MAAL_ERROR(sscop, 'J', 0); + return; + } + (void)MBUF_STRIP32(msg->m); + + sscop->vt_ms = pdu.sscop_ns; + AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0); + + sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND); +} + +/* + * p 59: IN_REC_PEND && ER PDU + * arg is pdu (freed) + */ +static void +sscop_inrec_er(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(!m_detect_retransmission(sscop, msg)) { + MAAL_ERROR(sscop, 'L', 0); + } + + SSCOP_MSG_FREE(msg); +} + +/* + * p 59: IN_REC_PEND && BGN PDU + * arg is pdu (freed). + * no uui + */ +static void +sscop_inrec_bgn(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + MAAL_ERROR(sscop, 'B', 0); + SSCOP_MSG_FREE(msg); + return; + } + (void)MBUF_STRIP32(msg->m); + + sscop->vt_ms = pdu.sscop_ns; + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); + AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); + + sscop_set_state(sscop, SSCOP_IN_PEND); +} + +/* + * p 59: IN_REC_PEND && BGAK PDU + * arg is pdu (freed) + * no uui + */ +static void +sscop_inrec_bgak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'C', 0); + SSCOP_MSG_FREE(msg); +} + +/* + * p 59: IN_REC_PEND && ERAK PDU + * arg is pdu (freed) + * no uui + */ +static void +sscop_inrec_erak(struct sscop *sscop, struct sscop_msg *msg) +{ + MAAL_ERROR(sscop, 'M', 0); + SSCOP_MSG_FREE(msg); +} + +/* + * p 60: READY && RESYNC request + * arg is UU + */ +static void +sscop_ready_sync_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_rs, uu); + + m_reset_data_xfer_timers(sscop); + sscop->vt_cc = 1; + sscop->vt_sq++; + m_initialize_mr(sscop); + send_rs(sscop, 0, sscop->uu_rs); + m_release_buffers(sscop); + TIMER_RESTART(sscop, cc); + + sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND); +} + + +/* + * p 60: READY && AA-RELEASE.request + * arg is uu. + */ +static void +sscop_ready_release_req(struct sscop *sscop, struct sscop_msg *uu) +{ + SET_UU(uu_end, uu); + + m_reset_data_xfer_timers(sscop); + sscop->vt_cc = 1; + send_end(sscop, 0, sscop->uu_end); + m_prepare_retrieval(sscop); + TIMER_RESTART(sscop, cc); + + sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); +} + +/* + * p 61: READY && ER PDU + * arg is pdu (freed). + */ +static void +sscop_ready_er(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + TIMER_RESTART(sscop, nr); + send_erak(sscop); + } else { + m_reset_data_xfer_timers(sscop); + sscop->vt_ms = pdu.sscop_ns; + m_prepare_recovery(sscop); + m_deliver_data(sscop); + + AAL_SIG(sscop, SSCOP_RECOVER_indication); + + sscop_set_state(sscop, SSCOP_IN_REC_PEND); + } + + SSCOP_MSG_FREE(msg); +} + +/* + * p 61: READY && BGN PDU + * arg is pdu (freed) + */ +static void +sscop_ready_bgn(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + TIMER_RESTART(sscop, nr); + send_bgak(sscop, sscop->uu_bgak); + SSCOP_MSG_FREE(msg); + return; + } + (void)MBUF_STRIP32(msg->m); + + m_reset_data_xfer_timers(sscop); + sscop->vt_ms = pdu.sscop_ns; + + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); + AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); + + m_prepare_retrieval(sscop); + + sscop_set_state(sscop, SSCOP_IN_PEND); +} + +/* + * p 62: READY && ENDAK PDU + * arg is pdu (freed) + */ +static void +sscop_ready_endak(struct sscop *sscop, struct sscop_msg *msg) +{ + m_reset_data_xfer_timers(sscop); + MAAL_ERROR(sscop, 'F', 0); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + m_prepare_retrieval(sscop); + SSCOP_MSG_FREE(msg); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 62: READY && BGREJ PDU + * arg is pdu (freed) + */ +static void +sscop_ready_bgrej(struct sscop *sscop, struct sscop_msg *msg) +{ + m_reset_data_xfer_timers(sscop); + MAAL_ERROR(sscop, 'D', 0); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + m_prepare_retrieval(sscop); + SSCOP_MSG_FREE(msg); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 62: READY && RS PDU + * arg is pdu (freed) + */ +static void +sscop_ready_rs(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + if(m_detect_retransmission(sscop, msg)) { + SSCOP_MSG_FREE(msg); + TIMER_RESTART(sscop, nr); + send_rsak(sscop); + return; + } + (void)MBUF_STRIP32(msg->m); + + m_reset_data_xfer_timers(sscop); + sscop->vt_ms = pdu.sscop_ns; + AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0); + m_prepare_retrieval(sscop); + + sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND); +} + +/* + * p 62: READY && END PDU + * arg is pdu (freed) + */ +static void +sscop_ready_end(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + (void)MBUF_STRIP32(msg->m); + + m_reset_data_xfer_timers(sscop); + send_endak(sscop); + AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, + msg, pdu.sscop_pl, (u_int)pdu.sscop_s); + m_prepare_retrieval(sscop); + + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 63: READY && POLL expiry + */ +static void +sscop_ready_tpoll(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + sscop->vt_ps++; + send_poll(sscop); + sscop->vt_pd = 0; + m_set_poll_timer(sscop); +} + +/* + * p 63: READY && KEEP_ALIVE expiry + */ +static void +sscop_ready_tka(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + sscop->vt_ps++; + send_poll(sscop); + sscop->vt_pd = 0; + m_set_poll_timer(sscop); +} + +/* + * p 63: READY && IDLE expiry + */ +static void +sscop_ready_tidle(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + TIMER_RESTART(sscop, nr); + sscop->vt_ps++; + send_poll(sscop); + sscop->vt_pd = 0; + m_set_poll_timer(sscop); +} + +/* + * p 63: READY && NO_RESPONSE expiry + * no arg + */ +static void +sscop_ready_nr(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + m_reset_data_xfer_timers(sscop); + MAAL_ERROR(sscop, 'P', 0); + FREE_UU(uu_end); + send_end(sscop, 1, NULL); + AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); + m_prepare_retrieval(sscop); + sscop_set_state(sscop, SSCOP_IDLE); +} + +/* + * p 63: READY && AA-DATA.request + * arg is message (queued). + */ +static void +sscop_ready_userdata(struct sscop *sscop, struct sscop_msg *msg) +{ + MSGQ_APPEND(&sscop->xq, msg); + + sscop_signal(sscop, SIG_PDU_Q, msg); +} + +/* + * p 64: READY && SD PDU queued up + * arg is unused. + */ +static void +sscop_ready_pduq(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + struct sscop_msg *msg; + + if(sscop->rxq != 0) { + TAILQ_FOREACH(msg, &sscop->xbuf, link) + if(msg->rexmit) + break; + ASSERT(msg != NULL); + msg->rexmit = 0; + sscop->rxq--; + send_sd(sscop, msg->m, msg->seqno); + msg->poll_seqno = sscop->vt_ps; + if(sscop->poll_after_rex && sscop->rxq == 0) + goto poll; /* -> A */ + else + goto maybe_poll; /* -> B */ + + } + if(MSGQ_EMPTY(&sscop->xq)) + return; + + if(sscop->vt_s >= sscop->vt_ms) { + /* Send windows closed */ + TIMER_STOP(sscop, idle); + TIMER_RESTART(sscop, nr); + goto poll; /* -> A */ + + } else { + msg = MSGQ_GET(&sscop->xq); + msg->seqno = sscop->vt_s; + send_sd(sscop, msg->m, msg->seqno); + msg->poll_seqno = sscop->vt_ps; + sscop->vt_s++; + MSGQ_APPEND(&sscop->xbuf, msg); + goto maybe_poll; /* -> B */ + } + + /* + * p 65: Poll handling + */ + maybe_poll: /* label B */ + sscop->vt_pd++; + if(TIMER_ISACT(sscop, poll)) { + if(sscop->vt_pd < sscop->maxpd) + return; + } else { + if(TIMER_ISACT(sscop, idle)) { + TIMER_STOP(sscop, idle); + TIMER_RESTART(sscop, nr); + } else { + TIMER_STOP(sscop, ka); + } + if(sscop->vt_pd < sscop->maxpd) { + TIMER_RESTART(sscop, poll); + return; + } + } + poll: /* label A */ + sscop->vt_ps++; + send_poll(sscop); + sscop->vt_pd = 0; + TIMER_RESTART(sscop, poll); +} + +/* + * p 67: common recovery start + */ +static void +sscop_recover(struct sscop *sscop) +{ + sscop->vt_cc = 1; + sscop->vt_sq++; + + m_initialize_mr(sscop); + send_er(sscop); + m_prepare_recovery(sscop); + + TIMER_RESTART(sscop, cc); + + sscop_set_state(sscop, SSCOP_OUT_REC_PEND); +} + +/* + * p 66: READY && SD PDU + * arg is received message. + */ +static void +sscop_ready_sd(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + u_int sn; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + msg->seqno = pdu.sscop_ns; + + /* Fix padding */ + MBUF_UNPAD(msg->m, pdu.sscop_pl); + + if(msg->seqno >= sscop->vr_mr) { + /* message outside window */ + if(sscop->vr_h < sscop->vr_mr) { + send_ustat(sscop, sscop->vr_h, sscop->vr_mr, -1); + sscop->vr_h = sscop->vr_mr; + } + SSCOP_MSG_FREE(msg); + return; + } + + if(msg->seqno == sscop->vr_r) { + if(msg->seqno == sscop->vr_h) { + sscop->vr_r = msg->seqno + 1; + sscop->vr_h = msg->seqno + 1; + + AAL_DATA(sscop, SSCOP_DATA_indication, + msg->m, msg->seqno); + msg->m = NULL; + SSCOP_MSG_FREE(msg); + + return; + } + for(;;) { + AAL_DATA(sscop, SSCOP_DATA_indication, + msg->m, msg->seqno); + msg->m = NULL; + SSCOP_MSG_FREE(msg); + + sscop->vr_r++; + if((msg = MSGQ_PEEK(&sscop->rbuf)) == NULL) + break; + sn = msg->seqno; + ASSERT(sn >= sscop->vr_r); + if(sn != sscop->vr_r) + break; + msg = MSGQ_GET(&sscop->rbuf); + } + return; + } + + /* Messages were lost */ + + /* XXX Flow control */ + if(msg->seqno == sscop->vr_h) { + QINSERT(&sscop->rbuf, msg); + sscop->vr_h++; + return; + } + if(sscop->vr_h < msg->seqno) { + QINSERT(&sscop->rbuf, msg); + send_ustat(sscop, sscop->vr_h, msg->seqno, -1); + sscop->vr_h = msg->seqno + 1; + return; + } + + if(QFIND(&sscop->rbuf, msg->seqno) == NULL) { + QINSERT(&sscop->rbuf, msg); + return; + } + + /* error: start recovery */ + SSCOP_MSG_FREE(msg); + m_reset_data_xfer_timers(sscop); + MAAL_ERROR(sscop, 'Q', 0); + sscop_recover(sscop); +} + +/* + * p 67: READY && POLL PDU + */ +static void +sscop_ready_poll(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + union seqno seqno; + u_int sn, nps; + struct SSCOP_MBUF_T *m; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + seqno.sscop_null = MBUF_STRIP32(msg->m); + + if((u_int)pdu.sscop_ns < sscop->vr_h) { + SSCOP_MSG_FREE(msg); + m_reset_data_xfer_timers(sscop); + MAAL_ERROR(sscop, 'Q', 0); + sscop_recover(sscop); + return; + } + nps = seqno.sscop_n; + + if((u_int)pdu.sscop_ns > sscop->vr_mr) + sscop->vr_h = sscop->vr_mr; + else + sscop->vr_h = pdu.sscop_ns; + + SSCOP_MSG_FREE(msg); + + /* build stat pdu */ + if((m = MBUF_ALLOC(sscop->maxstat * 4 + 12)) == NULL) { + FAILURE("sscop: cannot allocate STAT"); + return; + } + sn = sscop->vr_r; + + while(sn != sscop->vr_h) { + /* loop through burst we already have */ + for(;;) { + if(sn >= sscop->vr_h) { + seqno.sscop_null = 0; + seqno.sscop_n = sn; + MBUF_APPEND32(m, seqno.sscop_null); + goto out; + } + if(QFIND(&sscop->rbuf, sn) == NULL) + break; + sn++; + } + + /* start of a hole */ + seqno.sscop_null = 0; + seqno.sscop_n = sn; + MBUF_APPEND32(m, seqno.sscop_null); + if(MBUF_LEN(m)/4 >= sscop->maxstat) { + send_stat(sscop, nps, m); + if((m = MBUF_ALLOC(sscop->maxstat * 4 + 12)) == NULL) { + FAILURE("sscop: cannot allocate STAT"); + return; + } + seqno.sscop_null = 0; + seqno.sscop_n = sn; + MBUF_APPEND32(m, seqno.sscop_null); + } + do { + sn++; + } while(sn < sscop->vr_h && !QFIND(&sscop->rbuf, sn)); + seqno.sscop_null = 0; + seqno.sscop_n = sn; + MBUF_APPEND32(m, seqno.sscop_null); + } + out: + send_stat(sscop, nps, m); +} + +/* + * p 69: READY && USTAT PDU + * arg is msg (freed) + */ +static void +sscop_ready_ustat(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + union seqno nmr, sq1, sq2; + u_int cnt; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + nmr.sscop_null = MBUF_STRIP32(msg->m); + sq2.sscop_null = MBUF_STRIP32(msg->m); + sq1.sscop_null = MBUF_STRIP32(msg->m); + + SSCOP_MSG_FREE(msg); + + cnt = sq1.sscop_n - sq2.sscop_n; + + if((u_int)pdu.sscop_ns < sscop->vt_a || (u_int)pdu.sscop_ns >= sscop->vt_s) { + VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, + "USTAT: N(R) outside VT(A)...VT(S)-1: N(R)=%u VT(A)=%u " + "VT(S)=%u", (u_int)pdu.sscop_ns, sscop->vt_a, sscop->vt_s)); + goto err_f; + } + + /* Acknowledge all messages between VT(A) and N(R)-1. N(R) is the new + * next in sequence-SD-number of the receiver and means, it has all + * messages below N(R). Remove all message below N(R) from the + * transmission buffer. It may already be removed because of an + * earlier selective ACK in a STAT message. + */ + while((msg = MSGQ_PEEK(&sscop->xbuf)) != NULL && msg->seqno < (u_int)pdu.sscop_ns) { + ASSERT(msg->seqno >= sscop->vt_a); + MSGQ_REMOVE(&sscop->xbuf, msg); + SSCOP_MSG_FREE(msg); + } + + /* Update the in-sequence acknowledge and the send window */ + sscop->vt_a = pdu.sscop_ns; + sscop->vt_ms = nmr.sscop_n; + + /* check, that the range of requested re-transmissions is between + * the in-sequence-ack and the highest up-to-now transmitted SD + */ + if(sq1.sscop_n >= sq2.sscop_n + || (u_int)sq1.sscop_n < sscop->vt_a + || (u_int)sq2.sscop_n >= sscop->vt_s) { + VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, + "USTAT: seq1 or seq2 outside VT(A)...VT(S)-1 or seq1>=seq2:" + " seq1=%u seq2=%u VT(A)=%u VT(S)=%u", + sq1.sscop_n, sq2.sscop_n, sscop->vt_a, sscop->vt_s)); + goto err_f; + } + + /* + * Retransmit all messages from seq1 to seq2-1 + */ + do { + /* + * The message may not be in the transmit buffer if it was + * already acked by a STAT. This means, the receiver is + * confused. + */ + if((msg = QFIND(&sscop->xbuf, sq1.sscop_n)) == NULL) { + VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, + "USTAT: message %u not found in xmit buffer", + sq1.sscop_n)); + goto err_f; + } + + /* + * If it is not yet in the re-transmission queue, put it there + */ + if(!msg->rexmit) { + msg->rexmit = 1; + sscop->rxq++; + sscop_signal(sscop, SIG_PDU_Q, msg); + } + sq1.sscop_n++; + } while(sq1.sscop_n != sq2.sscop_n); + + /* + * report the re-transmission to the management + */ + MAAL_ERROR(sscop, 'V', cnt); + return; + + err_f: + m_reset_data_xfer_timers(sscop); + MAAL_ERROR(sscop, 'T', 0); + sscop_recover(sscop); +} + +/* + * p 70: READY && STAT PDU + * arg is msg (freed). + */ +static void +sscop_ready_stat(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + union seqno nps, nmr; + u_int len, seq1, seq2, cnt; + struct sscop_msg *m; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + nmr.sscop_null = MBUF_STRIP32(msg->m); + nps.sscop_null = MBUF_STRIP32(msg->m); + + len = MBUF_LEN(msg->m) / 4; + + if((u_int)nps.sscop_n < sscop->vt_pa + || (u_int)nps.sscop_n > sscop->vt_ps) { + SSCOP_MSG_FREE(msg); + m_reset_data_xfer_timers(sscop); + MAAL_ERROR(sscop, 'R', 0); + sscop_recover(sscop); + return; + } + + if((u_int)pdu.sscop_ns < sscop->vt_a + || (u_int)pdu.sscop_ns > sscop->vt_s) { + /* + * The in-sequence acknowledge, i.e. the receivers's next + * expected in-sequence msg is outside the window between + * the transmitters in-sequence ack and highest seqno - + * the receiver seems to be confused. + */ + VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, + "STAT: N(R) outside VT(A)...VT(S)-1: N(R)=%u VT(A)=%u " + "VT(S)=%u", (u_int)pdu.sscop_ns, sscop->vt_a, sscop->vt_s)); + err_H: + SSCOP_MSG_FREE(msg); + m_reset_data_xfer_timers(sscop); + MAAL_ERROR(sscop, 'S', 0); + sscop_recover(sscop); + return; + } + + /* Acknowledge all messages between VT(A) and N(R)-1. N(R) is the new + * next in sequence-SD-number of the receiver and means, it has all + * messages below N(R). Remove all message below N(R) from the + * transmission buffer. It may already be removed because of an + * earlier selective ACK in a STAT message. + */ + while((m = MSGQ_PEEK(&sscop->xbuf)) != NULL + && m->seqno < (u_int)pdu.sscop_ns) { + ASSERT(m->seqno >= sscop->vt_a); + MSGQ_REMOVE(&sscop->xbuf, m); + SSCOP_MSG_FREE(m); + } + + /* + * Update in-sequence ack, poll-ack and send window. + */ + sscop->vt_a = pdu.sscop_ns; + sscop->vt_pa = nps.sscop_n; + sscop->vt_ms = nmr.sscop_n; + + cnt = 0; + if(len > 1) { + seq1 = MBUF_GET32(msg->m); + len--; + if(seq1 >= sscop->vt_s) { + VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, + "STAT: seq1 >= VT(S): seq1=%u VT(S)=%u", + seq1, sscop->vt_s)); + goto err_H; + } + + for(;;) { + seq2 = MBUF_GET32(msg->m); + len--; + if(seq1 >= seq2 || seq2 > sscop->vt_s) { + VERBERR(sscop, SSCOP_DBG_ERR, (sscop, + sscop->aarg, "STAT: seq1 >= seq2 or " + "seq2 > VT(S): seq1=%u seq2=%u VT(S)=%u", + seq1, seq2, sscop->vt_s)); + goto err_H; + } + + do { + /* + * The receiver requests the re-transmission + * of some message, but has acknowledged it + * already in an earlier STAT (it isn't in the + * transmitt buffer anymore). + */ + if((m = QFIND(&sscop->xbuf, seq1)) == NULL) { + VERBERR(sscop, SSCOP_DBG_ERR, + (sscop, sscop->aarg, "STAT: message" + " %u not found in xmit buffer", + seq1)); + goto err_H; + } + if(m->poll_seqno < (u_int)nps.sscop_n + && (u_int)nps.sscop_n <= sscop->vt_ps) + if(!m->rexmit) { + m->rexmit = 1; + sscop->rxq++; + cnt++; + sscop_signal(sscop, SIG_PDU_Q, msg); + } + } while(++seq1 < seq2); + + if(len == 0) + break; + + seq2 = MBUF_GET32(msg->m); + len--; + + if(seq1 >= seq2 || seq2 > sscop->vt_s) { + VERBERR(sscop, SSCOP_DBG_ERR, (sscop, + sscop->aarg, "STAT: seq1 >= seq2 or " + "seq2 > VT(S): seq1=%u seq2=%u VT(S)=%u", + seq1, seq2, sscop->vt_s)); + goto err_H; + } + + /* OK now the sucessful transmitted messages. Note, that + * some messages may already be out of the buffer because + * of earlier STATS */ + do { + if(sscop->clear_buffers) { + if((m = QFIND(&sscop->xbuf, seq1)) != NULL) { + MSGQ_REMOVE(&sscop->xbuf, m); + SSCOP_MSG_FREE(m); + } + } + } while(++seq1 != seq2); + + if(len == 0) + break; + } + MAAL_ERROR(sscop, 'V', cnt); + } + SSCOP_MSG_FREE(msg); + + /* label L: */ + if(sscop->vt_s >= sscop->vt_ms) { + /* + * The receiver has closed the window: report to management + */ + if(sscop->credit) { + sscop->credit = 0; + MAAL_ERROR(sscop, 'W', 0); + } + } else if(!sscop->credit) { + /* + * The window was forcefully closed above, but + * now re-opened. Report to management. + */ + sscop->credit = 1; + MAAL_ERROR(sscop, 'X', 0); + } + + if(TIMER_ISACT(sscop, poll)) { + TIMER_RESTART(sscop, nr); + } else if(!TIMER_ISACT(sscop, idle)) { + TIMER_STOP(sscop, ka); + TIMER_STOP(sscop, nr); + TIMER_RESTART(sscop, idle); + } +} + +/* + * P. 73: any state & UDATA_REQUEST + * arg is pdu (queued) + */ +static void +sscop_udata_req(struct sscop *sscop, struct sscop_msg *msg) +{ + MSGQ_APPEND(&sscop->uxq, msg); + sscop_signal(sscop, SIG_UPDU_Q, msg); +} + +/* + * P. 73: any state & MDATA_REQUEST + * arg is pdu (queued) + */ +static void +sscop_mdata_req(struct sscop *sscop, struct sscop_msg *msg) +{ + MSGQ_APPEND(&sscop->mxq, msg); + sscop_signal(sscop, SIG_MPDU_Q, msg); +} + +/* + * P. 74: any state & UDATA queued + * no arg. + */ +static void +sscop_upduq(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + struct sscop_msg *msg; + + if(sscop->ll_busy) + return; + while((msg = MSGQ_GET(&sscop->uxq)) != NULL) { + send_ud(sscop, msg->m); + msg->m = NULL; + SSCOP_MSG_FREE(msg); + } +} + +/* + * P. 74: any state & MDATA queued + * no arg. + */ +static void +sscop_mpduq(struct sscop *sscop, struct sscop_msg *unused __unused) +{ + struct sscop_msg *msg; + + if(sscop->ll_busy) + return; + while((msg = MSGQ_GET(&sscop->mxq)) != NULL) { + send_md(sscop, msg->m); + msg->m = NULL; + SSCOP_MSG_FREE(msg); + } +} + +/* + * p 73: MD PDU + * arg is PDU + */ +static void +sscop_md(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + MBUF_UNPAD(msg->m, pdu.sscop_pl); + + MAAL_DATA(sscop, msg->m); + msg->m = NULL; + SSCOP_MSG_FREE(msg); +} + +/* + * p 73: UD PDU + * arg is PDU + */ +static void +sscop_ud(struct sscop *sscop, struct sscop_msg *msg) +{ + union pdu pdu; + + pdu.sscop_null = MBUF_STRIP32(msg->m); + + MBUF_UNPAD(msg->m, pdu.sscop_pl); + + AAL_DATA(sscop, SSCOP_UDATA_indication, msg->m, 0); + msg->m = NULL; + SSCOP_MSG_FREE(msg); +} + + +/* + * p 33: IDLE & RETRIEVE + * p 39: IN_PEND & RETRIEVE + * p 42: OUT_DIS_PEND & RETRIEVE + * p 48: IN_RESYNC_PEND & RETRIEVE + * p 53: REC_PEND & RETRIEVE + * p 58: IN_REC_PEND & RETRIEVE + */ +static void +sscop_retrieve(struct sscop *sscop, struct sscop_msg *msg) +{ + m_data_retrieval(sscop, msg->rexmit); + SSCOP_MSG_FREE(msg); +} + +/************************************************************/ +/* + * GENERAL EVENT HANDLING + */ + +/* + * State/event matrix. + * + * Entries marked with Z are not specified in Q.2110, but are added for + * the sake of stability. + */ +static struct { + void (*func)(struct sscop *, struct sscop_msg *); + int (*cond)(struct sscop *); +} state_matrix[SSCOP_NSTATES][SIG_NUM] = { + /* SSCOP_IDLE */ { + /* SIG_BGN */ { sscop_idle_bgn, NULL }, + /* SIG_BGAK */ { sscop_idle_bgak, NULL }, + /* SIG_END */ { sscop_idle_end, NULL }, + /* SIG_ENDAK */ { sscop_ignore_pdu, NULL }, + /* SIG_RS */ { sscop_idle_rs, NULL }, + /* SIG_RSAK */ { sscop_idle_rsak, NULL }, + /* SIG_BGREJ */ { sscop_idle_bgrej, NULL }, + /* SIG_SD */ { sscop_idle_sd, NULL }, + /* SIG_ER */ { sscop_idle_er, NULL }, + /* SIG_POLL */ { sscop_idle_poll, NULL }, + /* SIG_STAT */ { sscop_idle_stat, NULL }, + /* SIG_USTAT */ { sscop_idle_ustat, NULL }, + /* SIG_UD */ { sscop_ud, NULL }, + /* SIG_MD */ { sscop_md, NULL }, + /* SIG_ERAK */ { sscop_idle_erak, NULL }, + /* SIG_T_CC */ { NULL, NULL }, + /* SIG_T_POLL */ { NULL, NULL }, + /* SIG_T_KA */ { NULL, NULL }, + /* SIG_T_NR */ { NULL, NULL }, + /* SIG_T_IDLE */ { NULL, NULL }, + /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, + /* SIG_USER_DATA */ { NULL, NULL }, + /* SIG_ESTAB_REQ */ { sscop_idle_establish_req, NULL }, + /* SIG_ESTAB_RESP */ { NULL, NULL }, + /* SIG_RELEASE_REQ */ { NULL, NULL }, + /* SIG_RECOVER */ { NULL, NULL }, + /* SIG_SYNC_REQ */ { NULL, NULL }, + /* SIG_SYNC_RESP */ { NULL, NULL }, + /* SIG_UDATA */ { sscop_udata_req, NULL }, + /* SIG_MDATA */ { sscop_mdata_req, NULL }, + /* SIG_UPDU_Q */ { sscop_upduq, NULL }, + /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, + /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, + }, + /* SSCOP_OUT_PEND */ { + /* SIG_BGN */ { sscop_outpend_bgn, NULL }, + /* SIG_BGAK */ { sscop_outpend_bgak, NULL }, + /* SIG_END */ { sscop_ignore_pdu, NULL }, + /* SIG_ENDAK */ { sscop_ignore_pdu, NULL }, + /* SIG_RS */ { sscop_ignore_pdu, NULL }, + /* SIG_RSAK */ { sscop_ignore_pdu, NULL }, + /* SIG_BGREJ */ { sscop_outpend_bgrej, NULL }, + /* SIG_SD */ { sscop_ignore_pdu, NULL }, + /* SIG_ER */ { sscop_ignore_pdu, NULL }, + /* SIG_POLL */ { sscop_ignore_pdu, NULL }, + /* SIG_STAT */ { sscop_ignore_pdu, NULL }, + /* SIG_USTAT */ { sscop_ignore_pdu, NULL }, + /* SIG_UD */ { sscop_ud, NULL }, + /* SIG_MD */ { sscop_md, NULL }, + /* SIG_ERAK */ { sscop_ignore_pdu, NULL }, + /* SIG_T_CC */ { sscop_outpend_tcc, NULL }, + /* SIG_T_POLL */ { NULL, NULL }, + /* SIG_T_KA */ { NULL, NULL }, + /* SIG_T_NR */ { NULL, NULL }, + /* SIG_T_IDLE */ { NULL, NULL }, + /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, + /* SIG_USER_DATA */ { NULL, NULL }, + /* SIG_ESTAB_REQ */ { NULL, NULL }, + /* SIG_ESTAB_RESP */ { NULL, NULL }, + /* SIG_RELEASE_REQ */ { sscop_outpend_release_req, NULL }, + /* SIG_RECOVER */ { NULL, NULL }, + /* SIG_SYNC_REQ */ { NULL, NULL }, + /* SIG_SYNC_RESP */ { NULL, NULL }, + /* SIG_UDATA */ { sscop_udata_req, NULL }, + /* SIG_MDATA */ { sscop_mdata_req, NULL }, + /* SIG_UPDU_Q */ { sscop_upduq, NULL }, + /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, + /* SIG_RETRIEVE */ { NULL, NULL }, + }, + /* SSCOP_IN_PEND */ { + /* SIG_BGN */ { sscop_inpend_bgn, NULL }, + /* SIG_BGAK */ { sscop_inpend_bgak, NULL }, + /* SIG_END */ { sscop_inpend_end, NULL }, + /* SIG_ENDAK */ { sscop_inpend_endak, NULL }, + /* SIG_RS */ { sscop_inpend_rs, NULL }, + /* SIG_RSAK */ { sscop_inpend_rsak, NULL }, + /* SIG_BGREJ */ { sscop_inpend_bgrej, NULL }, + /* SIG_SD */ { sscop_inpend_sd, NULL }, + /* SIG_ER */ { sscop_inpend_er, NULL }, + /* SIG_POLL */ { sscop_inpend_poll, NULL }, + /* SIG_STAT */ { sscop_inpend_stat, NULL }, + /* SIG_USTAT */ { sscop_inpend_ustat, NULL }, + /* SIG_UD */ { sscop_ud, NULL }, + /* SIG_MD */ { sscop_md, NULL }, + /* SIG_ERAK */ { sscop_inpend_erak, NULL }, + /* SIG_T_CC */ { NULL, NULL }, + /* SIG_T_POLL */ { NULL, NULL }, + /* SIG_T_KA */ { NULL, NULL }, + /* SIG_T_NR */ { NULL, NULL }, + /* SIG_T_IDLE */ { NULL, NULL }, + /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, + /* SIG_USER_DATA */ { NULL, NULL }, + /* SIG_ESTAB_REQ */ { NULL, NULL }, + /* SIG_ESTAB_RESP */ { sscop_inpend_establish_resp, NULL }, + /* SIG_RELEASE_REQ */ { sscop_inpend_release_req, NULL }, + /* SIG_RECOVER */ { NULL, NULL }, + /* SIG_SYNC_REQ */ { NULL, NULL }, + /* SIG_SYNC_RESP */ { NULL, NULL }, + /* SIG_UDATA */ { sscop_udata_req, NULL }, + /* SIG_MDATA */ { sscop_mdata_req, NULL }, + /* SIG_UPDU_Q */ { sscop_upduq, NULL }, + /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, + /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, + }, + /* SSCOP_OUT_DIS_PEND */ { + /* SIG_BGN */ { sscop_outdis_bgn, NULL }, + /* SIG_BGAK */ { sscop_ignore_pdu, NULL }, + /* SIG_END */ { sscop_outdis_end, NULL }, + /* SIG_ENDAK */ { sscop_outdis_endak, NULL }, + /* SIG_RS */ { sscop_ignore_pdu, NULL }, + /* SIG_RSAK */ { sscop_ignore_pdu, NULL }, + /* SIG_BGREJ */ { sscop_outdis_endak, NULL }, + /* SIG_SD */ { sscop_ignore_pdu, NULL }, + /* SIG_ER */ { sscop_ignore_pdu, NULL }, + /* SIG_POLL */ { sscop_ignore_pdu, NULL }, + /* SIG_STAT */ { sscop_ignore_pdu, NULL }, + /* SIG_USTAT */ { sscop_ignore_pdu, NULL }, + /* SIG_UD */ { sscop_ud, NULL }, + /* SIG_MD */ { sscop_md, NULL }, + /* SIG_ERAK */ { sscop_ignore_pdu, NULL }, + /* SIG_T_CC */ { sscop_outdis_cc, NULL }, + /* SIG_T_POLL */ { NULL, NULL }, + /* SIG_T_KA */ { NULL, NULL }, + /* SIG_T_NR */ { NULL, NULL }, + /* SIG_T_IDLE */ { NULL, NULL }, + /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, + /* SIG_USER_DATA */ { NULL, NULL }, + /* SIG_ESTAB_REQ */ { sscop_outdis_establish_req, NULL }, + /* SIG_ESTAB_RESP */ { NULL, NULL }, + /* SIG_RELEASE_REQ */ { NULL, NULL }, + /* SIG_RECOVER */ { NULL, NULL }, + /* SIG_SYNC_REQ */ { NULL, NULL }, + /* SIG_SYNC_RESP */ { NULL, NULL }, + /* SIG_UDATA */ { sscop_udata_req, NULL }, + /* SIG_MDATA */ { sscop_mdata_req, NULL }, + /* SIG_UPDU_Q */ { sscop_upduq, NULL }, + /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, + /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, + }, + /* SSCOP_OUT_RESYNC_PEND */ { + /* SIG_BGN */ { sscop_outsync_bgn, NULL }, + /* SIG_BGAK */ { sscop_ignore_pdu, NULL }, + /* SIG_END */ { sscop_outsync_end, NULL }, + /* SIG_ENDAK */ { sscop_outsync_endak, NULL }, + /* SIG_RS */ { sscop_outsync_rs, NULL }, + /* SIG_RSAK */ { sscop_outsync_rsak, NULL }, + /* SIG_BGREJ */ { sscop_outsync_bgrej, NULL }, + /* SIG_SD */ { sscop_ignore_pdu, NULL }, + /* SIG_ER */ { sscop_ignore_pdu, NULL }, + /* SIG_POLL */ { sscop_ignore_pdu, NULL }, + /* SIG_STAT */ { sscop_ignore_pdu, NULL }, + /* SIG_USTAT */ { sscop_ignore_pdu, NULL }, + /* SIG_UD */ { sscop_ud, NULL }, + /* SIG_MD */ { sscop_md, NULL }, + /* SIG_ERAK */ { sscop_ignore_pdu, NULL }, + /* SIG_T_CC */ { sscop_outsync_cc, NULL }, + /* SIG_T_POLL */ { NULL, NULL }, + /* SIG_T_KA */ { NULL, NULL }, + /* SIG_T_NR */ { NULL, NULL }, + /* SIG_T_IDLE */ { NULL, NULL }, + /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, + /* SIG_USER_DATA */ { NULL, NULL }, + /* SIG_ESTAB_REQ */ { NULL, NULL }, + /* SIG_ESTAB_RESP */ { NULL, NULL }, + /* SIG_RELEASE_REQ */ { sscop_outsync_release_req, NULL }, + /* SIG_RECOVER */ { NULL, NULL }, + /* SIG_SYNC_REQ */ { NULL, NULL }, + /* SIG_SYNC_RESP */ { NULL, NULL }, + /* SIG_UDATA */ { sscop_udata_req, NULL }, + /* SIG_MDATA */ { sscop_mdata_req, NULL }, + /* SIG_UPDU_Q */ { sscop_upduq, NULL }, + /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, + /* SIG_RETRIEVE */ { NULL, NULL }, + }, + /* SSCOP_IN_RESYNC_PEND */ { + /* SIG_BGN */ { sscop_insync_bgn, NULL }, + /* SIG_BGAK */ { sscop_insync_bgak, NULL }, + /* SIG_END */ { sscop_insync_end, NULL }, + /* SIG_ENDAK */ { sscop_insync_endak, NULL }, + /* SIG_RS */ { sscop_insync_rs, NULL }, + /* SIG_RSAK */ { sscop_insync_rsak, NULL }, + /* SIG_BGREJ */ { sscop_insync_bgrej, NULL }, + /* SIG_SD */ { sscop_insync_sd, NULL }, + /* SIG_ER */ { sscop_insync_er, NULL }, + /* SIG_POLL */ { sscop_insync_poll, NULL }, + /* SIG_STAT */ { sscop_insync_stat, NULL }, + /* SIG_USTAT */ { sscop_insync_ustat, NULL }, + /* SIG_UD */ { sscop_ud, NULL }, + /* SIG_MD */ { sscop_md, NULL }, + /* SIG_ERAK */ { sscop_insync_erak, NULL }, + /* SIG_T_CC */ { NULL, NULL }, + /* SIG_T_POLL */ { NULL, NULL }, + /* SIG_T_KA */ { NULL, NULL }, + /* SIG_T_NR */ { NULL, NULL }, + /* SIG_T_IDLE */ { NULL, NULL }, + /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, + /* SIG_USER_DATA */ { NULL, NULL }, + /* SIG_ESTAB_REQ */ { NULL, NULL }, + /* SIG_ESTAB_RESP */ { NULL, NULL }, + /* SIG_RELEASE_REQ */ { sscop_insync_release_req, NULL }, + /* SIG_RECOVER */ { NULL, NULL }, + /* SIG_SYNC_REQ */ { NULL, NULL }, + /* SIG_SYNC_RESP */ { sscop_insync_sync_resp, NULL }, + /* SIG_UDATA */ { sscop_udata_req, NULL }, + /* SIG_MDATA */ { sscop_mdata_req, NULL }, + /* SIG_UPDU_Q */ { sscop_upduq, NULL }, + /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, + /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, + }, + /* SSCOP_OUT_REC_PEND */ { + /* SIG_BGN */ { sscop_outrec_bgn, NULL }, + /* SIG_BGAK */ { sscop_outrec_bgak, NULL }, + /* SIG_END */ { sscop_outrec_end, NULL }, + /* SIG_ENDAK */ { sscop_outrec_endak, NULL }, + /* SIG_RS */ { sscop_outrec_rs, NULL }, + /* SIG_RSAK */ { sscop_outrec_rsak, NULL }, + /* SIG_BGREJ */ { sscop_outrec_bgrej, NULL }, + /* SIG_SD */ { sscop_ignore_pdu, NULL }, + /* SIG_ER */ { sscop_outrec_er, NULL }, + /* SIG_POLL */ { sscop_ignore_pdu, NULL }, + /* SIG_STAT */ { sscop_ignore_pdu, NULL }, + /* SIG_USTAT */ { sscop_ignore_pdu, NULL }, + /* SIG_UD */ { sscop_ud, NULL }, + /* SIG_MD */ { sscop_md, NULL }, + /* SIG_ERAK */ { sscop_outrec_erak, NULL }, + /* SIG_T_CC */ { sscop_outrec_cc, NULL }, + /* SIG_T_POLL */ { NULL, NULL }, + /* SIG_T_KA */ { NULL, NULL }, + /* SIG_T_NR */ { NULL, NULL }, + /* SIG_T_IDLE */ { NULL, NULL }, + /* SIG_PDU_Q */ { sscop_outrec_pduq, NULL }, + /* SIG_USER_DATA */ { sscop_outrec_userdata, NULL }, + /* SIG_ESTAB_REQ */ { NULL, NULL }, + /* SIG_ESTAB_RESP */ { NULL, NULL }, + /* SIG_RELEASE_REQ */ { sscop_outrec_release_req, NULL }, + /* SIG_RECOVER */ { NULL, NULL }, + /* SIG_SYNC_REQ */ { sscop_outrec_sync_req, NULL }, + /* SIG_SYNC_RESP */ { NULL, NULL }, + /* SIG_UDATA */ { sscop_udata_req, NULL }, + /* SIG_MDATA */ { sscop_mdata_req, NULL }, + /* SIG_UPDU_Q */ { sscop_upduq, NULL }, + /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, + /* SIG_RETRIEVE */ { NULL, NULL }, + }, + /* SSCOP_REC_PEND */ { + /* SIG_BGN */ { sscop_rec_bgn, NULL }, + /* SIG_BGAK */ { sscop_rec_bgak, NULL }, + /* SIG_END */ { sscop_rec_end, NULL }, + /* SIG_ENDAK */ { sscop_rec_endak, NULL }, + /* SIG_RS */ { sscop_rec_rs, NULL }, + /* SIG_RSAK */ { sscop_rec_rsak, NULL }, + /* SIG_BGREJ */ { sscop_rec_bgrej, NULL }, + /* SIG_SD */ { sscop_ignore_pdu, NULL }, + /* SIG_ER */ { sscop_rec_er, NULL }, + /* SIG_POLL */ { sscop_ignore_pdu, NULL }, + /* SIG_STAT */ { sscop_rec_stat, NULL }, + /* SIG_USTAT */ { sscop_rec_ustat, NULL }, + /* SIG_UD */ { sscop_ud, NULL }, + /* SIG_MD */ { sscop_md, NULL }, + /* SIG_ERAK */ { sscop_ignore_pdu, NULL }, + /* SIG_T_CC */ { NULL, NULL }, + /* SIG_T_POLL */ { NULL, NULL }, + /* SIG_T_KA */ { NULL, NULL }, + /* SIG_T_NR */ { NULL, NULL }, + /* SIG_T_IDLE */ { NULL, NULL }, + /* SIG_PDU_Q */ { sscop_rec_pduq, NULL }, + /* SIG_USER_DATA */ { NULL, NULL }, + /* SIG_ESTAB_REQ */ { NULL, NULL }, + /* SIG_ESTAB_RESP */ { NULL, NULL }, + /* SIG_RELEASE_REQ */ { sscop_rec_release_req, NULL }, + /* SIG_RECOVER */ { sscop_rec_recover, NULL }, + /* SIG_SYNC_REQ */ { sscop_rec_sync_req, NULL }, + /* SIG_SYNC_RESP */ { NULL, NULL }, + /* SIG_UDATA */ { sscop_udata_req, NULL }, + /* SIG_MDATA */ { sscop_mdata_req, NULL }, + /* SIG_UPDU_Q */ { sscop_upduq, NULL }, + /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, + /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, + }, + /* SSCOP_IN_REC_PEND */ { + /* SIG_BGN */ { sscop_inrec_bgn, NULL }, + /* SIG_BGAK */ { sscop_inrec_bgak, NULL }, + /* SIG_END */ { sscop_inrec_end, NULL }, + /* SIG_ENDAK */ { sscop_inrec_endak, NULL }, + /* SIG_RS */ { sscop_inrec_rs, NULL }, + /* SIG_RSAK */ { sscop_inrec_rsak, NULL }, + /* SIG_BGREJ */ { sscop_inrec_bgrej, NULL }, + /* SIG_SD */ { sscop_inrec_sd, NULL }, + /* SIG_ER */ { sscop_inrec_er, NULL }, + /* SIG_POLL */ { sscop_inrec_poll, NULL }, + /* SIG_STAT */ { sscop_inrec_stat, NULL }, + /* SIG_USTAT */ { sscop_inrec_ustat, NULL }, + /* SIG_UD */ { sscop_ud, NULL }, + /* SIG_MD */ { sscop_md, NULL }, + /* SIG_ERAK */ { sscop_inrec_erak, NULL }, + /* SIG_T_CC */ { NULL, NULL }, + /* SIG_T_POLL */ { NULL, NULL }, + /* SIG_T_KA */ { NULL, NULL }, + /* SIG_T_NR */ { NULL, NULL }, + /* SIG_T_IDLE */ { NULL, NULL }, + /* SIG_PDU_Q */ { sscop_inrec_pduq, NULL }, + /* SIG_USER_DATA */ { NULL, NULL }, + /* SIG_ESTAB_REQ */ { NULL, NULL }, + /* SIG_ESTAB_RESP */ { NULL, NULL }, + /* SIG_RELEASE_REQ */ { sscop_inrec_release_req, NULL }, + /* SIG_RECOVER */ { sscop_inrec_recover, NULL }, + /* SIG_SYNC_REQ */ { sscop_inrec_sync_req, NULL }, + /* SIG_SYNC_RESP */ { NULL, NULL }, + /* SIG_UDATA */ { sscop_udata_req, NULL }, + /* SIG_MDATA */ { sscop_mdata_req, NULL }, + /* SIG_UPDU_Q */ { sscop_upduq, NULL }, + /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, + /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, + }, + /* SSCOP_READY */ { + /* SIG_BGN */ { sscop_ready_bgn, NULL }, + /* SIG_BGAK */ { sscop_ignore_pdu, NULL }, + /* SIG_END */ { sscop_ready_end, NULL }, + /* SIG_ENDAK */ { sscop_ready_endak, NULL }, + /* SIG_RS */ { sscop_ready_rs, NULL }, + /* SIG_RSAK */ { sscop_ignore_pdu, NULL }, + /* SIG_BGREJ */ { sscop_ready_bgrej, NULL }, + /* SIG_SD */ { sscop_ready_sd, NULL }, + /* SIG_ER */ { sscop_ready_er, NULL }, + /* SIG_POLL */ { sscop_ready_poll, NULL }, + /* SIG_STAT */ { sscop_ready_stat, NULL }, + /* SIG_USTAT */ { sscop_ready_ustat, NULL }, + /* SIG_UD */ { sscop_ud, NULL }, + /* SIG_MD */ { sscop_md, NULL }, + /* SIG_ERAK */ { sscop_ignore_pdu, NULL }, + /* SIG_T_CC */ { NULL, NULL }, + /* SIG_T_POLL */ { sscop_ready_tpoll, NULL }, + /* SIG_T_KA */ { sscop_ready_tka, NULL }, + /* SIG_T_NR */ { sscop_ready_nr, NULL }, + /* SIG_T_IDLE */ { sscop_ready_tidle, NULL }, + /* SIG_PDU_Q */ { sscop_ready_pduq, c_ready_pduq }, + /* SIG_USER_DATA */ { sscop_ready_userdata, NULL }, + /* SIG_ESTAB_REQ */ { NULL, NULL }, + /* SIG_ESTAB_RESP */ { NULL, NULL }, + /* SIG_RELEASE_REQ */ { sscop_ready_release_req, NULL }, + /* SIG_RECOVER */ { NULL, NULL }, + /* SIG_SYNC_REQ */ { sscop_ready_sync_req, NULL }, + /* SIG_SYNC_RESP */ { NULL, NULL }, + /* SIG_UDATA */ { sscop_udata_req, NULL }, + /* SIG_MDATA */ { sscop_mdata_req, NULL }, + /* SIG_UPDU_Q */ { sscop_upduq, NULL }, + /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, + /* SIG_RETRIEVE */ { NULL, NULL }, + } +}; + +/* + * Try to execute a signal. It is executed if + * - it is illegal (in this case it is effectively ignored) + * - it has no condition + * - its condition is true + * If it has a condition and that is false, the function does nothing and + * returns 0. + * If the signal gets executed, the signal function is responsible to release + * the message (if any). + */ +static int +sig_exec(struct sscop *sscop, u_int sig, struct sscop_msg *msg) +{ + void (*func)(struct sscop *, struct sscop_msg *); + int (*cond)(struct sscop *); + + func = state_matrix[sscop->state][sig].func; + cond = state_matrix[sscop->state][sig].cond; + + if(func == NULL) { + VERBOSE(sscop, SSCOP_DBG_BUG, (sscop, sscop->aarg, + "no handler for %s in state %s - ignored", + events[sig], states[sscop->state])); + SSCOP_MSG_FREE(msg); + return 1; + } + if(cond == NULL || (*cond)(sscop)) { + VERBOSE(sscop, SSCOP_DBG_EXEC, (sscop, sscop->aarg, + "executing %s in %s", events[sig], + states[sscop->state])); + (*func)(sscop, msg); + return 1; + } + VERBOSE(sscop, SSCOP_DBG_EXEC, (sscop, sscop->aarg, + "delaying %s in %s", events[sig], + states[sscop->state])); + + return 0; +} + +/* + * Deliver a signal to the given sscop + * If it is delivered from inside a signal handler - queue it. If not, + * execute it. After execution loop through the queue and execute all + * pending signals. Signals, that cannot be executed because of entry + * conditions are skipped. + */ +static void +sscop_signal(struct sscop *sscop, u_int sig, struct sscop_msg *msg) +{ + struct sscop_sig *s; + + VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg, + "got signal %s in state %s%s", events[sig], + states[sscop->state], sscop->in_sig ? " -- queuing" : "")); + + SIG_ALLOC(s); + if(s == NULL) { + FAILURE("sscop: cannot allocate signal"); + SSCOP_MSG_FREE(msg); + return; + } + s->sig = sig; + s->msg = msg; + SIGQ_APPEND(&sscop->sigs, s); + + if(!sscop->in_sig) + handle_sigs(sscop); +} + +/* + * Loop through the signal queue until we can't execute any signals. + */ +static void +handle_sigs(struct sscop *sscop) +{ + struct sscop_sig *s; + sscop_sigq_head_t dsigs, q; + int exec; + + sscop->in_sig++; + + /* + * Copy the current signal queue to the local one and empty + * the signal queue. Then loop through the signals. After one + * pass we have a list of delayed signals because of entry + * conditions and a new list of signals. Merge them. Repeat until + * the signal queue is either empty or contains only delayed signals. + */ + SIGQ_INIT(&q); + SIGQ_INIT(&dsigs); + do { + exec = 0; + + /* + * Copy signal list and make sscop list empty + */ + SIGQ_MOVE(&sscop->sigs, &q); + + /* + * Loop through the list + */ + while((s = SIGQ_GET(&q)) != NULL) { + if(sig_exec(sscop, s->sig, s->msg)) { + exec = 1; + SIG_FREE(s); + } else { + SIGQ_APPEND(&dsigs, s); + } + } + + /* + * Merge lists by inserting delayed signals in front of + * the signal list. preserving the order. + */ + SIGQ_PREPEND(&dsigs, &sscop->sigs); + } while(exec); + sscop->in_sig--; +} + +/* + * Save a signal that should be executed only if state changes. + */ +static void +sscop_save_signal(struct sscop *sscop, u_int sig, struct sscop_msg *msg) +{ + struct sscop_sig *s; + + SIG_ALLOC(s); + if(s == NULL) { + FAILURE("sscop: cannot allocate signal"); + SSCOP_MSG_FREE(msg); + return; + } + s->sig = sig; + s->msg = msg; + SIGQ_APPEND(&sscop->saved_sigs, s); +} + +/* + * Set a new state. If signals are waiting for a state change - append them to + * the signal queue, so they get executed. + */ +static void +sscop_set_state(struct sscop *sscop, u_int nstate) +{ + VERBOSE(sscop, SSCOP_DBG_STATE, (sscop, sscop->aarg, + "changing state from %s to %s", + states[sscop->state], states[nstate])); + + sscop->state = nstate; + SIGQ_MOVE(&sscop->saved_sigs, &sscop->sigs); +} + +void +sscop_setdebug(struct sscop *sscop, u_int n) +{ + sscop->debug = n; +} + +u_int +sscop_getdebug(const struct sscop *sscop) +{ + return (sscop->debug); +} diff --git a/sys/contrib/ngatm/netnatm/saal/sscfu.h b/sys/contrib/ngatm/netnatm/saal/sscfu.h new file mode 100644 index 000000000000..3aaa9270d3ff --- /dev/null +++ b/sys/contrib/ngatm/netnatm/saal/sscfu.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/saal/sscfu.h,v 1.4 2004/07/08 08:22:15 brandt Exp $ + * + * Public include file for UNI SSCF + */ +#ifndef _NETNATM_SAAL_SSCFU_H_ +#define _NETNATM_SAAL_SSCFU_H_ + +#include <sys/types.h> +#include <netnatm/saal/sscopdef.h> +#include <netnatm/saal/sscfudef.h> + +/* + * Define how a buffer looks like. + */ +#ifdef _KERNEL +#ifdef __FreeBSD__ +#define SSCFU_MBUF_T mbuf +#endif +#else +#define SSCFU_MBUF_T uni_msg +#endif + +struct SSCFU_MBUF_T; +struct sscfu; + +/* functions to be supplied by the SSCOP user */ +struct sscfu_funcs { + /* upper (SAAL) interface output */ + void (*send_upper)(struct sscfu *, void *, enum saal_sig, + struct SSCFU_MBUF_T *); + + /* lower (SSCOP) interface output */ + void (*send_lower)(struct sscfu *, void *, enum sscop_aasig, + struct SSCFU_MBUF_T *, u_int); + + /* function to move the SSCOP window */ + void (*window)(struct sscfu *, void *, u_int); + + /* debugging function */ + void (*verbose)(struct sscfu *, void *, const char *, ...) + __printflike(3, 4); +}; + +/* Function defined by the SSCF-UNI code */ + +/* allocate and initialize a new SSCF instance */ +struct sscfu *sscfu_create(void *, const struct sscfu_funcs *); + +/* destroy an SSCF instance and free all resources */ +void sscfu_destroy(struct sscfu *); + +/* reset the SSCF to the released state */ +void sscfu_reset(struct sscfu *); + +/* lower input interface (SSCOP signals) */ +void sscfu_input(struct sscfu *, enum sscop_aasig, struct SSCFU_MBUF_T *, u_int); + +/* upper input interface (SAAL) */ +int sscfu_saalsig(struct sscfu *, enum saal_sig, struct SSCFU_MBUF_T *); + +/* retrieve the current state */ +enum sscfu_state sscfu_getstate(const struct sscfu *); + +/* char'ify signals and states */ +const char *sscfu_signame(enum saal_sig); +const char *sscfu_statename(enum sscfu_state); + +/* retrieve the default set of parameters for SSCOP */ +u_int sscfu_getdefparam(struct sscop_param *); + +/* get/set debugging flags */ +void sscfu_setdebug(struct sscfu *, u_int); +u_int sscfu_getdebug(const struct sscfu *); + +#endif diff --git a/sys/contrib/ngatm/netnatm/saal/sscfudef.h b/sys/contrib/ngatm/netnatm/saal/sscfudef.h new file mode 100644 index 000000000000..08882f2a9bc2 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/saal/sscfudef.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/saal/sscfudef.h,v 1.4 2004/07/08 08:22:16 brandt Exp $ + * + * Definitions of UNI SSCF constants. + */ +#ifndef _NETNATM_SAAL_SSCFUDEF_H_ +#define _NETNATM_SAAL_SSCFUDEF_H_ + +/* + * Signals at the upper boundary of the SSCF. + */ +enum saal_sig { + SAAL_ESTABLISH_request, /* U -> SAAL: (UU) */ + SAAL_ESTABLISH_indication, /* SAAL -> U: (UU) */ + SAAL_ESTABLISH_confirm, /* SAAL -> U: (UU) */ + SAAL_RELEASE_request, /* U -> SAAL: (UU) */ + SAAL_RELEASE_confirm, /* SAAL -> U: */ + SAAL_RELEASE_indication, /* SAAL -> U: (UU) */ + SAAL_DATA_request, /* U -> SAAL: (DATA) */ + SAAL_DATA_indication, /* SAAL -> U: (DATA) */ + SAAL_UDATA_request, /* U -> SAAL: (UDATA) */ + SAAL_UDATA_indication, /* SAAL -> U: (UDATA) */ +}; + +/* + * States of the SSCF + */ +enum sscfu_state { + SSCFU_RELEASED, /* 1/1 */ + SSCFU_AWAITING_ESTABLISH, /* 2/2 */ + SSCFU_AWAITING_RELEASE, /* 4/10 */ + SSCFU_ESTABLISHED, /* 3/4 */ + SSCFU_RESYNC, /* 2/5 */ +}; + +/* + * Debugging flags + */ +enum { + SSCFU_DBG_LSIG = 0x01, + SSCFU_DBG_ERR = 0x02, + SSCFU_DBG_STATE = 0x04, + SSCFU_DBG_EXEC = 0x08, +}; + +#endif diff --git a/sys/contrib/ngatm/netnatm/saal/sscfupriv.h b/sys/contrib/ngatm/netnatm/saal/sscfupriv.h new file mode 100644 index 000000000000..b4a1299ac108 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/saal/sscfupriv.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/saal/sscfupriv.h,v 1.3 2003/09/19 12:02:03 hbb Exp $ + * + * Private SSCF-UNI definitions. + */ +#ifdef _KERNEL +#ifdef __FreeBSD__ +#include <netgraph/atm/sscfu/ng_sscfu_cust.h> +#endif +#else +#include "sscfucust.h" +#endif + +/* + * Structure for signal queueing. + */ +struct sscfu_sig { + sscfu_sigq_link_t link; /* link to next signal */ + enum saal_sig sig; /* the signal */ + struct SSCFU_MBUF_T *m; /* associated message */ +}; + +struct sscfu { + enum sscfu_state state; /* SSCF state */ + const struct sscfu_funcs *funcs; /* func vector */ + void *aarg; /* user arg */ + int inhand; /* need to queue signals */ + sscfu_sigq_head_t sigs; /* signal queue */ + u_int debug; /* debugging flags */ +}; + +/* + * Debugging + */ +#ifdef SSCFU_DEBUG +#define VERBOSE(S,M,F) if ((S)->debug & (M)) (S)->funcs->verbose F +#else +#define VERBOSE(S,M,F) +#endif diff --git a/sys/contrib/ngatm/netnatm/saal/sscop.h b/sys/contrib/ngatm/netnatm/saal/sscop.h new file mode 100644 index 000000000000..8574a1581791 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/saal/sscop.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/saal/sscop.h,v 1.4 2004/07/08 08:22:16 brandt Exp $ + * + * External interface to sscop. + */ +#ifndef _NETNATM_SAAL_SSCOP_H_ +#define _NETNATM_SAAL_SSCOP_H_ + +#include <netnatm/saal/sscopdef.h> + +/* + * Define how a buffer looks like. + */ +#ifdef _KERNEL +#ifdef __FreeBSD__ +#define SSCOP_MBUF_T mbuf +#endif +#else +#define SSCOP_MBUF_T uni_msg +#endif + +struct SSCOP_MBUF_T; +struct sscop; + +/* + * Vector for user functions + */ +struct sscop_funcs { + /* management signal from SSCOP */ + void (*send_manage)(struct sscop *, void *, enum sscop_maasig, + struct SSCOP_MBUF_T *, u_int, u_int); + + /* AAL signal from SSCOP */ + void (*send_upper)(struct sscop *, void *, enum sscop_aasig, + struct SSCOP_MBUF_T *, u_int); + + /* send a PDU to the wire */ + void (*send_lower)(struct sscop *, void *, + struct SSCOP_MBUF_T *); + + /* print a message */ + void (*verbose)(struct sscop *, void *, const char *, ...) + __printflike(3,4); + +#ifndef _KERNEL + /* start a timer */ + void *(*start_timer)(struct sscop *, void *, u_int, + void (*)(void *)); + + /* stop a timer */ + void (*stop_timer)(struct sscop *, void *, void *); +#endif +}; + +/* Function defined by the SSCOP code */ + +/* create a new SSCOP instance and initialize to default values */ +struct sscop *sscop_create(void *, const struct sscop_funcs *); + +/* destroy an SSCOP instance */ +void sscop_destroy(struct sscop *); + +/* get the current parameters of an SSCOP */ +void sscop_getparam(const struct sscop *, struct sscop_param *); + +/* set new parameters in an SSCOP */ +int sscop_setparam(struct sscop *, struct sscop_param *, u_int *); + +/* deliver an signal to the SSCOP */ +int sscop_aasig(struct sscop *, enum sscop_aasig, struct SSCOP_MBUF_T *, u_int); + +/* deliver an management signal to the SSCOP */ +int sscop_maasig(struct sscop *, enum sscop_maasig, struct SSCOP_MBUF_T *); + +/* SSCOP input function */ +void sscop_input(struct sscop *, struct SSCOP_MBUF_T *); + +/* Move the window by a given number of messages. Return the new window */ +u_int sscop_window(struct sscop *, u_int); + +/* declare the lower layer busy or not busy */ +u_int sscop_setbusy(struct sscop *, int); + +/* retrieve the state */ +enum sscop_state sscop_getstate(const struct sscop *); + +/* map signals to strings */ +const char *sscop_msigname(enum sscop_maasig); +const char *sscop_signame(enum sscop_aasig); +const char *sscop_statename(enum sscop_state); + +/* set/get debugging state */ +void sscop_setdebug(struct sscop *, u_int); +u_int sscop_getdebug(const struct sscop *); + +/* reset the instance */ +void sscop_reset(struct sscop *); + +#endif diff --git a/sys/contrib/ngatm/netnatm/saal/sscopdef.h b/sys/contrib/ngatm/netnatm/saal/sscopdef.h new file mode 100644 index 000000000000..ec6716461c34 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/saal/sscopdef.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/saal/sscopdef.h,v 1.4 2004/07/08 08:22:17 brandt Exp $ + * + * Definitions of SSCOP constants and parameter blocks. This is seen by + * the outside world. + */ +#ifndef _NETNATM_SAAL_SSCOPDEF_H_ +#define _NETNATM_SAAL_SSCOPDEF_H_ + +#include <sys/types.h> +#ifdef _KERNEL +#include <sys/stdint.h> +#else +#include <stdint.h> +#endif + +/* + * AA-interface signals + */ +enum sscop_aasig { + SSCOP_ESTABLISH_request, /* <- UU, BR */ + SSCOP_ESTABLISH_indication, /* -> UU */ + SSCOP_ESTABLISH_response, /* <- UU, BR */ + SSCOP_ESTABLISH_confirm, /* -> UU */ + + SSCOP_RELEASE_request, /* <- UU */ + SSCOP_RELEASE_indication, /* -> UU, SRC */ + SSCOP_RELEASE_confirm, /* -> */ + + SSCOP_DATA_request, /* <- MU */ + SSCOP_DATA_indication, /* -> MU, SN */ + + SSCOP_UDATA_request, /* <- MU */ + SSCOP_UDATA_indication, /* -> MU */ + + SSCOP_RECOVER_indication, /* -> */ + SSCOP_RECOVER_response, /* <- */ + + SSCOP_RESYNC_request, /* <- UU */ + SSCOP_RESYNC_indication, /* -> UU */ + SSCOP_RESYNC_response, /* <- */ + SSCOP_RESYNC_confirm, /* -> */ + + SSCOP_RETRIEVE_request, /* <- RN */ + SSCOP_RETRIEVE_indication, /* -> MU */ + SSCOP_RETRIEVE_COMPL_indication,/* -> */ +}; + +enum sscop_maasig { + SSCOP_MDATA_request, /* <- MU */ + SSCOP_MDATA_indication, /* -> MU */ + SSCOP_MERROR_indication, /* -> CODE, CNT */ +}; + +/* + * Values for retrieval. Numbers in SSCOP are 24bit, so + * we can use the large values + */ +enum { + SSCOP_MAXSEQNO = 0xffffff, + + SSCOP_RETRIEVE_UNKNOWN = SSCOP_MAXSEQNO + 1, + SSCOP_RETRIEVE_TOTAL = SSCOP_MAXSEQNO + 2, +}; + +/* + * SSCOP states + */ +enum sscop_state { + SSCOP_IDLE, /* initial state */ + SSCOP_OUT_PEND, /* outgoing connection pending */ + SSCOP_IN_PEND, /* incoming connection pending */ + SSCOP_OUT_DIS_PEND, /* outgoing disconnect pending */ + SSCOP_OUT_RESYNC_PEND, /* outgoing resynchronisation pending */ + SSCOP_IN_RESYNC_PEND, /* incoming resynchronisation pending */ + SSCOP_OUT_REC_PEND, /* outgoing recovery pending */ + SSCOP_REC_PEND, /* recovery response pending */ + SSCOP_IN_REC_PEND, /* incoming recovery pending */ + SSCOP_READY, /* data transfer ready */ +}; +#define SSCOP_NSTATES 10 + +struct sscop_param { + uint32_t timer_cc; /* timer_cc in msec */ + uint32_t timer_poll; /* timer_poll im msec */ + uint32_t timer_keep_alive;/* timer_keep_alive in msec */ + uint32_t timer_no_response;/*timer_no_response in msec */ + uint32_t timer_idle; /* timer_idle in msec */ + uint32_t maxk; /* maximum user data in bytes */ + uint32_t maxj; /* maximum u-u info in bytes */ + uint32_t maxcc; /* max. retransmissions for control packets */ + uint32_t maxpd; /* max. vt(pd) before sending poll */ + uint32_t maxstat; /* max. number of elements in stat list */ + uint32_t mr; /* initial window */ + uint32_t flags; /* flags */ +}; +enum { + SSCOP_ROBUST = 0x0001, /* atmf/97-0216 robustness */ + SSCOP_POLLREX = 0x0002, /* send POLL after retransmit */ +}; + +enum { + SSCOP_SET_TCC = 0x0001, + SSCOP_SET_TPOLL = 0x0002, + SSCOP_SET_TKA = 0x0004, + SSCOP_SET_TNR = 0x0008, + SSCOP_SET_TIDLE = 0x0010, + SSCOP_SET_MAXK = 0x0020, + SSCOP_SET_MAXJ = 0x0040, + SSCOP_SET_MAXCC = 0x0080, + SSCOP_SET_MAXPD = 0x0100, + SSCOP_SET_MAXSTAT = 0x0200, + SSCOP_SET_MR = 0x0400, + SSCOP_SET_ROBUST = 0x0800, + SSCOP_SET_POLLREX = 0x1000, + + SSCOP_SET_ALLMASK = 0x1fff, +}; + +enum { + SSCOP_DBG_USIG = 0x0001, + SSCOP_DBG_TIMER = 0x0002, + SSCOP_DBG_BUG = 0x0004, + SSCOP_DBG_INSIG = 0x0008, + SSCOP_DBG_STATE = 0x0010, + SSCOP_DBG_PDU = 0x0020, + SSCOP_DBG_ERR = 0x0040, + SSCOP_DBG_EXEC = 0x0080, + SSCOP_DBG_FLOW = 0x0100, +}; + +#endif diff --git a/sys/contrib/ngatm/netnatm/saal/sscoppriv.h b/sys/contrib/ngatm/netnatm/saal/sscoppriv.h new file mode 100644 index 000000000000..e2b055530b1f --- /dev/null +++ b/sys/contrib/ngatm/netnatm/saal/sscoppriv.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/saal/sscoppriv.h,v 1.4 2004/07/08 08:22:17 brandt Exp $ + * + * Private SSCOP definitions. + * + */ +#ifdef _KERNEL +#ifdef __FreeBSD__ +#include <netgraph/atm/sscop/ng_sscop_cust.h> +#endif +#else /* !_KERNEL */ +#include "sscopcust.h" +#endif + +/* Argh. BSDi */ +#ifndef _BYTE_ORDER +#ifndef BYTE_ORDER +#error "_BYTE_ORDER not defined" +#endif +#define _BYTE_ORDER BYTE_ORDER +#define _LITTLE_ENDIAN LITTLE_ENDIAN +#define _BIG_ENDIAN BIG_ENDIAN +#endif + +/* + * PDU trailer + */ +union pdu { + u_int sscop_null; + struct { +#if _BYTE_ORDER == _BIG_ENDIAN + u_int pl : 2; /* pad length */ + u_int : 1; /* reserved field */ + u_int s : 1; /* source */ + u_int type : 4; /* PDU type */ + u_int ns : 24; /* sequence number */ +#else + u_int ns : 24; /* sequence number */ + u_int type : 4; /* PDU type */ + u_int s : 1; /* source */ + u_int : 1; /* reserved field */ + u_int pl : 2; /* pad length */ +#endif + } ss; +}; +#define sscop_pl ss.pl +#define sscop_s ss.s +#define sscop_type ss.type +#define sscop_ns ss.ns + +/* + * seqno list entry format + */ +union seqno { + u_int sscop_null; + struct { +#if _BYTE_ORDER == _BIG_ENDIAN + u_int : 8; /* pad */ + u_int n : 24; /* seqno */ +#else + u_int n : 24; /* seqno */ + u_int : 8; /* pad */ +#endif + } ss; +}; +#define sscop_n ss.n + +/* + * Begin pdu + */ +union bgn { + u_int sscop_null; + struct { +#if _BYTE_ORDER == _BIG_ENDIAN + u_int : 24; /* reserved */ + u_int bgns : 8; /* VT_MR */ +#else + u_int bgns : 8; /* VT_MR */ + u_int : 24; /* reserved */ +#endif + } ss; +}; +#define sscop_bgns ss.bgns + +/* + * pdu types + */ +enum pdu_type { + PDU_BGN = 0x1, /* request initialization */ + PDU_BGAK = 0x2, /* request acknowledgement */ + PDU_END = 0x3, /* disconnect command */ + PDU_ENDAK = 0x4, /* disconnect acknowledgement */ + PDU_RS = 0x5, /* resynchronisation command */ + PDU_RSAK = 0x6, /* resynchronisation acknowledgement */ + PDU_BGREJ = 0x7, /* connection reject */ + PDU_SD = 0x8, /* sequenced connection-mode data */ + PDU_ER = 0x9, /* recovery command */ + PDU_POLL = 0xa, /* xmit state info with req. for recv state */ + PDU_STAT = 0xb, /* solicited receiver state info */ + PDU_USTAT = 0xc, /* unsolicited receiver state info */ + PDU_UD = 0xd, /* unumbered user data */ + PDU_MD = 0xe, /* unumbered management data */ + PDU_ERAK = 0xf, /* recovery acknowledgement */ +}; + + +/* + * These are all signals, that are used by SSCOP. Don't change the order or + * number without also changing the associated tables. + */ +enum sscop_sigtype { + /* received PDU's */ + SIG_BGN, /* request initialization */ + SIG_BGAK, /* request acknowledgement */ + SIG_END, /* disconnect command */ + SIG_ENDAK, /* disconnect acknowledgement */ + SIG_RS, /* resynchronisation command */ + SIG_RSAK, /* resynchronisation acknowledgement */ + SIG_BGREJ, /* connection reject */ + SIG_SD, /* sequenced connection-mode data */ + SIG_ER, /* recovery command */ + SIG_POLL, /* xmitter state info with req for recv state */ + SIG_STAT, /* solicited receiver state info */ + SIG_USTAT, /* unsolicited receiver state info */ + SIG_UD, /* unumbered user data */ + SIG_MD, /* unumbered management data */ + SIG_ERAK, /* recovery acknoledgement */ + + /* timer expiry */ + SIG_T_CC, /* CC timer */ + SIG_T_POLL, /* POLL timer */ + SIG_T_KA, /* KEEP ALIVE timer */ + SIG_T_NR, /* NO RESPONSE timer */ + SIG_T_IDLE, /* IDLE timer */ + + /* user originated signals */ + SIG_PDU_Q, /* PDU enqueued pseudosignal */ + SIG_USER_DATA, /* user data request */ + SIG_ESTAB_REQ, /* establish connection request */ + SIG_ESTAB_RESP, /* establish connection response */ + SIG_RELEASE_REQ, /* release connection request */ + SIG_RECOVER, /* automatic recover response */ + SIG_SYNC_REQ, /* resynchronisation request */ + SIG_SYNC_RESP, /* resynchronisation response */ + SIG_UDATA, /* UDATA request */ + SIG_MDATA, /* MDATA request */ + SIG_UPDU_Q, /* UDATA PDU enqueued pseudosignal */ + SIG_MPDU_Q, /* MDATA PDU enqueued pseudosignal */ + SIG_RETRIEVE, /* RETRIEVE */ + + /* number of signals */ + SIG_NUM +}; + +/* + * This is a message as contained in a sscop message queue. It holds a pointer + * to the real message. + */ +struct sscop_msg { + sscop_msgq_link_t link; + u_int seqno; /* seq no */ + u_int poll_seqno; /* poll seqno (for messages in xmit buffer) */ + u_int rexmit; /* in retransmission queue? */ + struct SSCOP_MBUF_T *m; /* the message */ +}; + +/* + * This structure is used to hold signals in the signal queue + */ +struct sscop_sig { + sscop_sigq_link_t link; /* next signal */ + enum sscop_sigtype sig; /* THE signal */ + struct sscop_msg *msg; /* signal argument (message) */ +}; + +/* + * This structure holds the entire sscop state + */ +struct sscop { + enum sscop_state state; /* current state */ + const struct sscop_funcs *funcs; + + /* send state */ + u_int vt_s; /* seqno for next pdu first time transmitted */ + u_int vt_ps; /* current poll seqno */ + u_int vt_a; /* next expected in-sequence sd pdu */ + u_int vt_pa; /* poll seqno of next stat pdu */ + u_int vt_ms; /* maximum allowed send sd seqno */ + u_int vt_pd; /* poll data state */ + u_int vt_cc; /* connection control state */ + u_int vt_sq; /* transmitter connection sequence */ + + /* receive state */ + u_int vr_r; /* receive state */ + u_int vr_h; /* highes expected state */ + u_int vr_mr; /* maximum acceptable */ + u_int vr_sq; /* receiver connection state */ + + /* timers */ + sscop_timer_t t_cc; /* timer_CC */ + sscop_timer_t t_nr; /* timer_NO_RESPONSE */ + sscop_timer_t t_ka; /* timer KEEP_ALIVE */ + sscop_timer_t t_poll; /* timer_POLL */ + sscop_timer_t t_idle; /* idle timer */ + + /* maximum values */ + u_int maxj; /* maximum uu-info */ + u_int maxk; /* maximum info */ + u_int maxcc; /* maximum number of bgn, end, er and rs */ + u_int maxpd; /* maximum value of vt_pd */ + u_int maxstat; /* maximum length of list */ + u_int timercc; /* connection control timer */ + u_int timerka; /* keep alive timer */ + u_int timernr; /* no response timer */ + u_int timerpoll; /* polling */ + u_int timeridle; /* idle timer */ + u_int robustness; /* atmf/97-0216 robustness enhancement */ + u_int poll_after_rex; /* optional POLL after re-transmission */ + u_int mr; /* initial window */ + + /* + * buffers and queues. + * All expect the xq hold SD PDUs. + */ + sscop_msgq_head_t xq; /* xmit queue (input from user before xmit) */ + sscop_msgq_head_t uxq; /* UD xmit queue */ + sscop_msgq_head_t mxq; /* MD xmit queue */ + sscop_msgq_head_t xbuf; /* transmission buffer (SD PDUs transmitted) */ + int rxq; /* number of PDUs in retransmission queue */ + sscop_msgq_head_t rbuf; /* receive buffer (SD PDUs) */ + int last_end_src; /* source field from last xmitted end pdu */ + int clear_buffers; /* flag */ + int credit; /* send window not closed */ + u_int ll_busy; /* lower layer busy */ + u_int rs_mr; /* N(MR) in last RS PDU */ + u_int rs_sq; /* N(SQ) in last RS PDU */ + struct SSCOP_MBUF_T *uu_bgn; /* last UU data */ + struct SSCOP_MBUF_T *uu_bgak; /* ... */ + struct SSCOP_MBUF_T *uu_bgrej; /* ... */ + struct SSCOP_MBUF_T *uu_end; /* ... */ + struct SSCOP_MBUF_T *uu_rs; /* ... */ + + /* signal queues */ + sscop_sigq_head_t sigs; /* saved signals */ + sscop_sigq_head_t saved_sigs; /* saved signals */ + int in_sig; /* in signal handler */ + + /* debugging */ + u_int debug; + + /* AA interface */ + void *aarg; +}; + + +/* + * Default values for SSCOP + */ +enum { + MAXK = 4096, + MAXMAXK = 65528, + MAXJ = 4096, + MAXMAXJ = 65524, + MAXCC = 4, + MAXSTAT = 67, + MAXPD = 25, + MAXMR = 128, /* ??? */ + TIMERCC = 1000, + TIMERKA = 2000, + TIMERNR = 7000, + TIMERPOLL = 750, + TIMERIDLE = 15000, +}; + +/* + * Sequence number arithmetic + */ +#define SEQNO_DIFF(A,B) (((A) < (B)) ? ((A) + (1<<24) - (B)) : ((A) - (B))) + +/* + * Debugging + */ +#ifdef SSCOP_DEBUG +#define VERBOSE(S,M,F) if ((S)->debug & (M)) (S)->funcs->verbose F +#define VERBERR(S,M,F) if ((S)->debug & (M)) (S)->funcs->verbose F +#define ISVERBOSE(S,M) ((S)->debug & (M)) +#else +#define VERBOSE(S,M,F) +#define VERBERR(S,M,F) +#define ISVERBOSE(S,M) (0) +#endif diff --git a/sys/contrib/ngatm/netnatm/sig/genmsgcpyc.awk b/sys/contrib/ngatm/netnatm/sig/genmsgcpyc.awk new file mode 100644 index 000000000000..be61925c977a --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/genmsgcpyc.awk @@ -0,0 +1,80 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# $Begemot: libunimsg/netnatm/sig/genmsgcpyc.awk,v 1.4 2004/07/08 08:22:18 brandt Exp $ +# +# Generate copy functions for messages +# +function begin() { +} + +function first_entry() { + print "/* This file was created automatically" + print " * Source file: " id + print " * $FreeBSD$" + print " */" + print "" + print "#include <netnatm/msg/unistruct.h>" + print "#include <netnatm/sig/unimsgcpy.h>" +} + +function end() { +} + +function start_message() { +} + +function end_message() { + print "" + print "void" + print "copy_msg_" msg "(struct uni_" msg " *src, struct uni_" msg " *dst)" + print "{" + for(i = 0; i < cnt; i++) { + if(ienum[i] != "-") { + print "\tu_int s, d;" + print "" + break + } + } + for(i = 0; i < cnt; i++) { + ie = iename[i] + if(ierep[i]) { + print "\tif(IE_ISGOOD(src->" ie "_repeat))" + print "\t\tdst->" ie "_repeat = src->" ie "_repeat;" + } + if(ienum[i] != "-") { + print "\tfor(s = d = 0; s < "ienum[i]"; s++)" + print "\t\tif(IE_ISGOOD(src->"ie"[s]))" + print "\t\t\tdst->"ie"[d++] = src->"ie"[s];" + } else { + print "\tif(IE_ISGOOD(src->"ie"))" + print "\t\tdst->"ie" = src->"ie";" + } + } + print "}" +} diff --git a/sys/contrib/ngatm/netnatm/sig/genmsgcpyh.awk b/sys/contrib/ngatm/netnatm/sig/genmsgcpyh.awk new file mode 100644 index 000000000000..f9b44f2b168d --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/genmsgcpyh.awk @@ -0,0 +1,55 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. +# +# Author: Hartmut Brandt <harti@freebsd.org> +# +# $Begemot: libunimsg/netnatm/sig/genmsgcpyh.awk,v 1.4 2004/07/08 08:22:19 brandt Exp $ +# +# Generate copy functions for messages +# +function begin() { +} + +function first_entry() { + print "/* This file was created automatically" + print " * Source file: " id + print " * $FreeBSD$" + print " */" + print "" +} + +function end() { +} + +function start_message() { +} + +function end_message() { + print "" + print "void" + print "copy_msg_" msg "(struct uni_" msg " *src, struct uni_" msg " *dst);" + print "" +} diff --git a/sys/contrib/ngatm/netnatm/sig/sig_call.c b/sys/contrib/ngatm/netnatm/sig/sig_call.c new file mode 100644 index 000000000000..d2e3b7f9af2e --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/sig_call.c @@ -0,0 +1,4310 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/sig/sig_call.c,v 1.65 2004/08/05 07:11:00 brandt Exp $ + * + * Call instance handling + * + * Note: + * In all functions that handle messages from the user or from + * the SAAL, commit memory allocation always at the begin of the + * function. If allocation fails, ignore saal messages and + * respond with an error to user messages. + */ + +#include <netnatm/unimsg.h> +#include <netnatm/saal/sscfudef.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#include <netnatm/sig/uni.h> + +#include <netnatm/sig/unipriv.h> +#include <netnatm/sig/unimkmsg.h> +#include <netnatm/sig/unimsgcpy.h> + +static enum call_state state_compat(struct call *, enum uni_callstate); +static void respond_drop_party_ack(struct call *, struct uni_ie_epref *, u_int); + + +#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME, +static const char *const call_sigs[] = { + DEF_CALL_SIGS +}; +#undef DEF_PRIV_SIG + +TIMER_FUNC_CALL(t308, t308_func) +TIMER_FUNC_CALL(t303, t303_func) +TIMER_FUNC_CALL(t301, t301_func) +TIMER_FUNC_CALL(t310, t310_func) +TIMER_FUNC_CALL(t313, t313_func) +TIMER_FUNC_CALL(t322, t322_func) + +const struct callstates callstates[] = { + [CALLST_NULL] = { "NU0", UNI_CALLSTATE_U0 }, + [CALLST_U1] = { "U1", UNI_CALLSTATE_U1 }, + [CALLST_U3] = { "U3", UNI_CALLSTATE_U3 }, + [CALLST_U4] = { "U4", UNI_CALLSTATE_U4 }, + [CALLST_U6] = { "U6", UNI_CALLSTATE_U6 }, + [CALLST_U7] = { "U7", UNI_CALLSTATE_U7 }, + [CALLST_U8] = { "U8", UNI_CALLSTATE_U8 }, + [CALLST_U9] = { "U9", UNI_CALLSTATE_U9 }, + [CALLST_U10] = { "U10", UNI_CALLSTATE_U10 }, + [CALLST_U11] = { "U11", UNI_CALLSTATE_U11 }, + [CALLST_U12] = { "U12", UNI_CALLSTATE_U12 }, + [CALLST_N1] = { "N1", UNI_CALLSTATE_N1 }, + [CALLST_N3] = { "N3", UNI_CALLSTATE_N3 }, + [CALLST_N4] = { "N4", UNI_CALLSTATE_N4 }, + [CALLST_N6] = { "N6", UNI_CALLSTATE_N6 }, + [CALLST_N7] = { "N7", UNI_CALLSTATE_N7 }, + [CALLST_N8] = { "N8", UNI_CALLSTATE_N8 }, + [CALLST_N9] = { "N9", UNI_CALLSTATE_N9 }, + [CALLST_N10] = { "N10", UNI_CALLSTATE_N10 }, + [CALLST_N11] = { "N11", UNI_CALLSTATE_N11 }, + [CALLST_N12] = { "N12", UNI_CALLSTATE_N12 }, +}; + +static void unx_send_add_party_rej(struct call *c, struct uni_all *u); + +static __inline void +set_call_state(struct call *c, enum call_state state) +{ + ASSERT(state == CALLST_NULL || + (c->uni->proto == UNIPROTO_UNI40U && + (state >= CALLST_U1 && state <= CALLST_U12)) || + (c->uni->proto == UNIPROTO_UNI40N && + (state >= CALLST_N1 && state <= CALLST_N12)), + ("setting wrong callstate for proto %u: %u", c->uni->proto, state)); + + if (c->cstate != state) { + VERBOSE(c->uni, UNI_FAC_CALL, 1, "call %d/%d %s -> %s", + c->cref, c->mine, callstates[c->cstate].name, + callstates[state].name); + c->cstate = state; + } +} + +static enum uni_callstate +map_callstate(enum call_state state) +{ + return (callstates[state].ext); +} + +/* + * Find the call. Assume, that the cref is one of a message just received. + * That is, if the call reference flag is 0 it is his call, if it is 1 it + * is my call. + */ +struct call * +uni_find_call(struct uni *uni, struct uni_cref *cref) +{ + struct call *c; + + TAILQ_FOREACH(c, &uni->calls, link) + if (c->cref == cref->cref && (!c->mine == !cref->flag)) + return (c); + return (NULL); +} +struct call * +uni_find_callx(struct uni *uni, u_int cref, u_int mine) +{ + struct call *c; + + TAILQ_FOREACH(c, &uni->calls, link) + if (c->cref == cref && !c->mine == !mine) + return (c); + return (NULL); +} + +/* + * Create a new call instance. The type must be set by the caller. + */ +struct call * +uni_create_call(struct uni *uni, u_int cref, u_int mine, uint32_t cookie) +{ + struct call *c; + struct uniapi_call_created *ind; + struct uni_msg *api; + + if ((c = CALL_ALLOC()) == NULL) + return (NULL); + + if ((ind = ALLOC_API(struct uniapi_call_created, api)) == NULL) { + CALL_FREE(c); + return (NULL); + } + ind->cref.cref = cref; + ind->cref.flag = mine; + + c->uni = uni; + c->type = CALL_NULL; + c->cref = cref; + c->mine = mine; + c->cstate = CALLST_NULL; + TAILQ_INIT(&c->parties); + + TIMER_INIT_CALL(c, t301); + TIMER_INIT_CALL(c, t303); + TIMER_INIT_CALL(c, t308); + TIMER_INIT_CALL(c, t310); + TIMER_INIT_CALL(c, t313); + TIMER_INIT_CALL(c, t322); + + TAILQ_INSERT_HEAD(&uni->calls, c, link); + + uni->funcs->uni_output(uni, uni->arg, UNIAPI_CALL_CREATED, cookie, api); + + VERBOSE(c->uni, UNI_FAC_CALL, 1, "created call %u/%s", + c->cref, c->mine ? "mine" : "his"); + + return (c); +} + +struct call * +uni_create_new_call(struct uni *uni, uint32_t cookie) +{ + struct call *c; + uint32_t old = uni->cref_alloc++; + + again: + if (uni->cref_alloc == (1 << 23)) + uni->cref_alloc = 1; + if (uni->cref_alloc == old) + return (NULL); /* all crefs exhausted!!! */ + TAILQ_FOREACH(c, &uni->calls, link) + if (c->mine && c->cref == uni->cref_alloc) { + uni->cref_alloc++; + goto again; + } + return (uni_create_call(uni, uni->cref_alloc, 1, cookie)); +} + +/* + * Assume timers are all stopped. Memory is not actually freed unless + * the reference count drops to 0. + * This function is assumed to remove the call from the parent UNI's + * call queue. + */ +void +uni_destroy_call(struct call *c, int really) +{ + struct uniapi_call_destroyed *ind; + struct uni_msg *api; + struct party *p; + + VERBOSE(c->uni, UNI_FAC_CALL, 1, "destroying call %u/%s", + c->cref, c->mine ? "mine" : "his"); + + TIMER_DESTROY_CALL(c, t301); + TIMER_DESTROY_CALL(c, t303); + TIMER_DESTROY_CALL(c, t308); + TIMER_DESTROY_CALL(c, t310); + TIMER_DESTROY_CALL(c, t313); + TIMER_DESTROY_CALL(c, t322); + TAILQ_REMOVE(&c->uni->calls, c, link); + + uni_delsig(c->uni, SIG_CALL, c, NULL); + + while ((p = TAILQ_FIRST(&c->parties)) != NULL) { + TAILQ_REMOVE(&c->parties, p, link); + uni_destroy_party(p, really); + } + + if (!really) { + ind = ALLOC_API(struct uniapi_call_destroyed, api); + if (ind != NULL) { + ind->cref.cref = c->cref; + ind->cref.flag = c->mine; + + uni_enq_coord(c->uni, SIGO_CALL_DESTROYED, 0, api); + } + + uni_enq_call(c, SIGC_CALL_DELETE, 0, NULL, NULL); + return; + } + + CALL_FREE(c); +} + +static void +allocate_epref(struct call *c, struct uni_ie_epref *epref) +{ + struct party *p; + uint32_t old = c->epref_alloc++; + + again: + if (c->epref_alloc == (1 << 15)) + c->epref_alloc = 0; + if (c->epref_alloc == old) + return; /* all crefs exhausted!!! */ + TAILQ_FOREACH(p, &c->parties, link) + if (p->epref == c->epref_alloc) { + c->epref_alloc++; + goto again; + } + IE_SETPRESENT(*epref); + epref->flag = 0; + epref->epref = c->epref_alloc; + + epref->h.coding = UNI_CODING_ITU; + epref->h.act = UNI_IEACT_DEFAULT; +} + +static void +reset_all_timers(struct call *c) +{ + TIMER_STOP_CALL(c, t301); + TIMER_STOP_CALL(c, t303); + TIMER_STOP_CALL(c, t308); + TIMER_STOP_CALL(c, t310); + TIMER_STOP_CALL(c, t313); + TIMER_STOP_CALL(c, t322); +} + +/* + * Initiate call clearing because of a problem. This is label D in + * the SDLs and is called from many places. + * The call must have constructed the cause IE in struct call. + * + * Q.2971:Call-Control-U 27/39 + * Q.2971:Call-Control-N 28/39 + * + * Memory problems are handled differently here: we simply ignore them + * by not sending messages or user indications. Because of T308 we + * may be lucky to send the message in a second run. + * + * It is assumed, that the cause for the release is constructed by + * the calling function in uni->cause. + */ +static void +clear_callD(struct call *c) +{ + struct uni_msg *api; + struct uniapi_release_indication *ind; + struct party *p; + struct uni_all *rel; + + /* + * Send indication to API + */ + if ((ind = ALLOC_API(struct uniapi_release_indication, api)) != NULL) { + ind->release.hdr.cref.cref = c->cref; + ind->release.hdr.cref.flag = c->mine; + ind->release.hdr.act = UNI_MSGACT_DEFAULT; + ind->release.cause[0] = c->uni->cause; + + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_RELEASE_indication, 0, api); + } + + reset_all_timers(c); + + if (c->type == CALL_LEAF || c->type == CALL_ROOT) { + TAILQ_FOREACH(p, &c->parties, link) { + uni_enq_party(p, SIGP_RELEASE_request, 0, NULL, NULL); + } + } + + memset(&c->msg_release, 0, sizeof(c->msg_release)); + c->msg_release.cause[0] = c->uni->cause; + + if ((rel = UNI_ALLOC()) != NULL) { + rel->u.release = c->msg_release; + MK_MSG_ORIG(rel, UNI_RELEASE, c->cref, !c->mine); + (void)uni_send_output(rel, c->uni); + UNI_FREE(rel); + } + + TIMER_START_CALL(c, t308, c->uni->timer308); + c->cnt308 = 0; + + if (c->uni->proto == UNIPROTO_UNI40N) + set_call_state(c, CALLST_N12); + else + set_call_state(c, CALLST_U11); +} + + +/**********************************************************************/ +/* + * SETUP message in state NULL + * + * Q.2971:Call-Control-U 4/39 + * Q.2971:Call-Control-N 4/39 + */ +static void +un0_setup(struct call *c, struct uni_msg *m, struct uni_all *u, + enum call_state new_state) +{ + struct uni_all *resp; + struct party *p; + struct uniapi_setup_indication *ind; + struct uni_msg *api; + enum verify v; + + if ((ind = ALLOC_API(struct uniapi_setup_indication, api)) == NULL) { + clear: + uni_destroy_call(c, 0); + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + + /* + * Analyze message + */ + (void)uni_decode_body(m, u, &c->uni->cx); + MANDATE_IE(c->uni, u->u.setup.bearer, UNI_IE_BEARER); + MANDATE_IE(c->uni, u->u.setup.traffic, UNI_IE_TRAFFIC); + MANDATE_IE(c->uni, u->u.setup.called, UNI_IE_CALLED); + + /* + * UNI4.0: 9.1.1.2 Notes 2/3 + */ + if (!IE_ISPRESENT(u->u.setup.qos)) + MANDATE_IE(c->uni, u->u.setup.exqos, UNI_IE_EXQOS); + if (!IE_ISPRESENT(u->u.setup.exqos)) + MANDATE_IE(c->uni, u->u.setup.qos, UNI_IE_QOS); + + /* + * Q.2971 + */ + if (IE_ISGOOD(u->u.setup.bearer) && + u->u.setup.bearer.cfg == UNI_BEARER_MP) { + if (IE_ISGOOD(u->u.setup.epref) && + u->u.setup.epref.flag == 1) { + IE_SETERROR(u->u.setup.epref); + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + u->u.setup.epref.h.act, UNI_IERR_BAD); + } + uni_mandate_epref(c->uni, &u->u.setup.epref); + } + + v = uni_verify(c->uni, u->u.hdr.act); + switch (v) { + + case VFY_RAI: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + UNI_CALLSTATE_U0, NULL, 0); + /* FALLTHRU */ + case VFY_I: + uni_msg_destroy(api); + goto clear; + + case VFY_RAIM: + case VFY_CLR: + if ((resp = UNI_ALLOC()) != NULL) { + MK_MSG_RESP(resp, UNI_RELEASE_COMPL, &u->u.hdr.cref); + uni_vfy_collect_ies(c->uni); + resp->u.release_compl.cause[0] = c->uni->cause; + uni_send_output(resp, c->uni); + UNI_FREE(resp); + } + uni_msg_destroy(api); + goto clear; + + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(new_state), NULL, 0); + /* FALLTHRU */ + case VFY_OK: + break; + } + + if (u->u.setup.bearer.cfg == UNI_BEARER_P2P) { + c->type = CALL_P2P; + + } else { + c->type = CALL_LEAF; + if ((p = uni_create_party(c, &u->u.setup.epref)) == NULL) { + uni_msg_destroy(api); + goto clear; + } + uni_enq_party(p, SIGP_SETUP, 0, NULL, NULL); + } + + ind->setup.hdr = u->u.hdr; + copy_msg_setup(&u->u.setup, &ind->setup); + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_SETUP_indication, 0, api); + + uni_msg_destroy(m); + UNI_FREE(u); + + set_call_state(c, new_state); +} + +/* + * Setup.request from user + * + * Q.2971:Call-Control-U 4/39 (U0) + * Q.2971:Call-Control-N 4/39 (N0) + */ +static void +un0_setup_request(struct call *c, struct uni_msg *m, uint32_t cookie, + enum call_state new_state) +{ + struct uniapi_setup_request *arg = + uni_msg_rptr(m, struct uniapi_setup_request *); + struct uni_setup *setup = &arg->setup; + struct uni_all *out; + struct party *p; + + if (!IE_ISGOOD(setup->bearer)) { + uni_msg_destroy(m); + uniapi_call_error(c, UNIAPI_ERROR_MISSING_IE, cookie); + uni_destroy_call(c, 0); + return; + } + if ((out = UNI_ALLOC()) == NULL) { + uni_msg_destroy(m); + uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie); + uni_destroy_call(c, 0); + return; + } + + c->msg_setup = *setup; + + if (IE_ISGOOD(setup->connid)) + c->connid = setup->connid; + + if (setup->bearer.cfg == UNI_BEARER_P2P) { + c->type = CALL_P2P; + } else { + c->type = CALL_ROOT; + + /* + * If the user didn't specify a endpoint reference, + * use 0. Use IE_IGNORE accoring to Appendix II Q.2971 + */ + if (!IE_ISPRESENT(c->msg_setup.epref)) { + MK_IE_EPREF(c->msg_setup.epref, 0, 0); + if (c->uni->proto == UNIPROTO_UNI40N) + c->msg_setup.epref.h.act = UNI_IEACT_IGNORE; + + } else if (!IE_ISGOOD(c->msg_setup.epref)) { + uni_msg_destroy(m); + uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie); + uni_destroy_call(c, 0); + return; + } + if ((p = uni_create_partyx(c, 0, 1, cookie)) == NULL) { + uni_msg_destroy(m); + uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie); + uni_destroy_call(c, 0); + return; + } + uni_enq_party(p, SIGP_SETUP_request, cookie, NULL, NULL); + } + + uni_msg_destroy(m); + + out->u.setup = c->msg_setup; + MK_MSG_ORIG(out, UNI_SETUP, c->cref, !c->mine); + (void)uni_send_output(out, c->uni); + UNI_FREE(out); + + TIMER_START_CALL(c, t303, c->uni->timer303); + c->cnt303 = 0; + + set_call_state(c, new_state); + + uniapi_call_error(c, UNIAPI_OK, cookie); +} + +/* + * CALL PROCEEDING message + * + * Q.2971:Call-Control-U 6/39 (in U1) + * Q.2971:Call-Control-N 11/39 (in N6) + */ +static void +u1n6_call_proc(struct call *c, struct uni_msg *m, struct uni_all *u, + enum call_state new_state) +{ + struct uni_call_proc *cp = &u->u.call_proc; + struct uniapi_proceeding_indication *ind; + struct uni_msg *api; + + ind = ALLOC_API(struct uniapi_proceeding_indication, api); + if (ind == NULL) { + ignore: + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + /* + * Analyze message + */ + (void)uni_decode_body(m, u, &c->uni->cx); + if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(cp->connid)) + uni_mandate_ie(c->uni, UNI_IE_CONNID); + + /* + * Q.2971: L3MU_01_03 requests us to ignore the message if + * the EPREF is missing. + */ + if (c->msg_setup.bearer.cfg == UNI_BEARER_MP && + IE_ISPRESENT(c->msg_setup.epref)) { + if (!IE_ISPRESENT(cp->epref)) + uni_mandate_ie(c->uni, UNI_IE_EPREF); \ + + else if (IE_ISGOOD(cp->epref) && + (cp->epref.flag != 1 || + cp->epref.epref != c->msg_setup.epref.epref)) { + IE_SETERROR(cp->epref); + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + cp->epref.h.act, UNI_IERR_BAD); + } + } + + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + /* FALLTHRU */ + case VFY_I: + uni_msg_destroy(api); + goto ignore; + + case VFY_RAIM: + case VFY_RAI: + report: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), NULL, 0); + uni_msg_destroy(api); + goto ignore; + + case VFY_RAP: + case VFY_RAPU: + if (c->type == CALL_ROOT && !IE_ISGOOD(cp->epref)) + goto report; + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(new_state), NULL, 0); + /* FALLTHRU */ + case VFY_OK: + break; + } + + TIMER_STOP_CALL(c, t303); + + if (IE_ISGOOD(cp->connid)) + c->connid = cp->connid; + + ind->call_proc.hdr = u->u.hdr; + copy_msg_call_proc(cp, &ind->call_proc); + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_PROCEEDING_indication, 0, api); + + TIMER_START_CALL(c, t310, c->uni->timer310); + + uni_msg_destroy(m); + UNI_FREE(u); + + set_call_state(c, new_state); +} + +/* + * T303 tick. + * + * Q.2971:Call-Control-U 6/39 + * Q.2971:Call-Control-N 11/39 + */ +static void +u1n6_t303(struct call *c) +{ + struct uni_all *msg; + struct uniapi_release_confirm *conf; + struct uni_msg *api; + + VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T303 tick %d", + c->cref, c->mine ? "mine" : "his", c->cnt303 + 1); + + if (++c->cnt303 < c->uni->init303) { + if ((msg = UNI_ALLOC()) != NULL) { + msg->u.setup = c->msg_setup; + MK_MSG_ORIG(msg, UNI_SETUP, c->cref, !c->mine); + (void)uni_send_output(msg, c->uni); + UNI_FREE(msg); + } + TIMER_START_CALL(c, t303, c->uni->timer303); + return; + } + + /* + * Send indication to API + */ + if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) { + conf->release.hdr.cref.cref = c->cref; + conf->release.hdr.cref.flag = c->mine; + conf->release.hdr.act = UNI_MSGACT_DEFAULT; + MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER, + UNI_CAUSE_NO_RESPONSE); + + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_RELEASE_confirm, 0, api); + } + + /* + * send to party (there may be only one) + */ + if (c->type == CALL_ROOT && !TAILQ_EMPTY(&c->parties)) { + uni_enq_party(TAILQ_FIRST(&c->parties), + SIGP_RELEASE_confirm, 0, NULL, NULL); + } + uni_destroy_call(c, 0); +} + +/* + * T310 (Call Proceeding) timer tick. + * + * Q.2971:Call-Control-U 7/39 + * Q.2971:Call-Control-N 17/39 + */ +static void +u3n9_t310(struct call *c) +{ + VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T310 tick", + c->cref, c->mine ? "mine" : "his"); + + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_NO_RESPONSE); + clear_callD(c); +} + +/* + * T301 (Alerting) timer tick. + * + * Q.2971:Call-Control-U Missing + * Q.2971:Call-Control-N 14/39 + */ +static void +u4n7_t301(struct call *c) +{ + VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T301 tick", + c->cref, c->mine ? "mine" : "his"); + + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_NO_RESP_ALERT); + clear_callD(c); +} + +/* + * ALERTING received + * + * Q.2971:Call-Control-U 37/39 (U1) + * Q.2971:Call-Control-U 7/39 (U3) + * Q.2971:Call-Control-N 9/39 (N6) + * Q.2971:Call-Control-N 17/39 (N9) + * + * There are two errors in the user side SDL Annex A: + * + * - the resetted timers are swapped (T310 and T303) + * + * - for U1 we should go to C12, not C3 to start T301. + */ +static void +unx_alerting(struct call *c, struct uni_msg *m, struct uni_all *u, + enum call_state new_state) +{ + struct uni_alerting *al = &u->u.alerting; + struct uniapi_alerting_indication *ind; + struct uni_msg *api; + + ind = ALLOC_API(struct uniapi_alerting_indication, api); + if (ind == NULL) { + ignore: + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + + /* + * Analyze message + */ + (void)uni_decode_body(m, u, &c->uni->cx); + if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(al->connid)) + uni_mandate_ie(c->uni, UNI_IE_CONNID); + + /* + * Q.2971: L3MU_01_04 requests us to ignore the message if the + * EPREF is missing. + */ + if (c->msg_setup.bearer.cfg == UNI_BEARER_MP && + IE_ISPRESENT(c->msg_setup.epref)) { + if (!IE_ISPRESENT(al->epref)) + uni_mandate_ie(c->uni, UNI_IE_EPREF); \ + + else if (IE_ISGOOD(al->epref) && + (al->epref.flag != 1 || + al->epref.epref != c->msg_setup.epref.epref)) { + IE_SETERROR(al->epref); + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + al->epref.h.act, UNI_IERR_BAD); + } + } + + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + case VFY_I: + uni_msg_destroy(api); + goto ignore; + + case VFY_RAIM: + case VFY_RAI: + report: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), NULL, 0); + uni_msg_destroy(api); + goto ignore; + + case VFY_RAP: + case VFY_RAPU: + if (c->type == CALL_ROOT && !IE_ISGOOD(al->epref)) + goto report; + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), NULL, 0); + case VFY_OK: + break; + } + + if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6) + TIMER_STOP_CALL(c, t303); + else if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9) + TIMER_STOP_CALL(c, t310); + + if (IE_ISGOOD(al->connid)) + c->connid = al->connid; + + ind->alerting.hdr = u->u.hdr; + copy_msg_alerting(al, &ind->alerting); + + if (c->type == CALL_LEAF || c->type == CALL_ROOT) { + uni_enq_party(TAILQ_FIRST(&c->parties), SIGP_ALERTING, + 0, NULL, NULL); + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_ALERTING_indication, 0, api); + } else { + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_ALERTING_indication, 0, api); + TIMER_START_CALL(c, t301, c->uni->timer301); + } + UNI_FREE(u); + uni_msg_destroy(m); + + set_call_state(c, new_state); +} + +/* + * Proceeding.request from API + * + * Q.2971:Call-Control-U 12/39 (U6) + * Q.2971:Call-Control-N 6/39 (N1) + */ +static void +u6n1_proceeding_request(struct call *c, struct uni_msg *m, uint32_t cookie, + enum call_state new_state) +{ + struct uni_all *msg; + struct uniapi_proceeding_request *arg = + uni_msg_rptr(m, struct uniapi_proceeding_request *); + + if ((msg = UNI_ALLOC()) == NULL) { + uni_msg_destroy(m); + uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie); + return; + } + + if (IE_ISGOOD(arg->call_proc.connid)) + c->connid = arg->call_proc.connid; + + msg->u.call_proc = arg->call_proc; + MK_MSG_ORIG(msg, UNI_CALL_PROC, c->cref, !c->mine); + (void)uni_send_output(msg, c->uni); + UNI_FREE(msg); + + set_call_state(c, new_state); + + uni_msg_destroy(m); + + uniapi_call_error(c, UNIAPI_OK, cookie); +} + +/* + * Alerting.request from API + * + * Q.2971:Call-Control-U 13/39 (U6) + * Q.2971:Call-Control-U 17/39 (U9) + * Q.2971:Call-Control-N 38/39 (N1) + * Q.2971:Call-Control-N 7/39 (N3) + */ +static void +unx_alerting_request(struct call *c, struct uni_msg *m, uint32_t cookie, + enum call_state new_state) +{ + struct uni_all *msg; + struct uniapi_alerting_request *arg = + uni_msg_rptr(m, struct uniapi_alerting_request *); + + if ((msg = UNI_ALLOC()) == NULL) { + uni_msg_destroy(m); + uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie); + return; + } + + if (c->type == CALL_ROOT || c->type == CALL_LEAF) { + uni_enq_party(TAILQ_FIRST(&c->parties), + SIGP_ALERTING_request, cookie, NULL, NULL); + } + + /* + * It's not really clear, what happens, if we send another + * connid in CALL_PROC and ALERTING + */ + if (!IE_ISGOOD(c->connid) && IE_ISGOOD(arg->alerting.connid)) + c->connid = arg->alerting.connid; + + msg->u.alerting = arg->alerting; + MK_MSG_ORIG(msg, UNI_ALERTING, c->cref, !c->mine); + (void)uni_send_output(msg, c->uni); + UNI_FREE(msg); + + set_call_state(c, new_state); + + uni_msg_destroy(m); + + uniapi_call_error(c, UNIAPI_OK, cookie); +} + + +/* + * Setup.response from API + * + * Q.2971:Call-Control-U 13/39 (U6) + * Q.2971:Call-Control-U 14/39 (U7) + * Q.2971:Call-Control-U 17/39 (U9) + * Q.2971:Call-Control-N 39/39 (N1) + * Q.2971:Call-Control-N 7/39 (N3) + * Q.2971:Call-Control-N 8/39 (N4) + */ +static void +unx_setup_response(struct call *c, struct uni_msg *m, uint32_t cookie, + enum call_state new_state) +{ + struct uni_all *msg; + struct uniapi_setup_response *arg = + uni_msg_rptr(m, struct uniapi_setup_response *); + struct party *p; + + if ((msg = UNI_ALLOC()) == NULL) { + uni_msg_destroy(m); + uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie); + return; + } + + if (!IE_ISGOOD(c->connid) && IE_ISGOOD(arg->connect.connid)) + c->connid = arg->connect.connid; + + if (IE_ISGOOD(arg->connect.epref)) { + p = uni_find_partyx(c, arg->connect.epref.epref, + !arg->connect.epref.flag); + if (p == NULL) { + uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie); + UNI_FREE(msg); + uni_msg_destroy(m); + return; + } + /* we need to remember that we have sent the CONNECT from this + * party because the CONNECT ACK must move only this party + * into P7 */ + p->flags |= PARTY_CONNECT; + + } else if (c->type == CALL_LEAF) { + /* XXX don't mandate if only one party */ + uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie); + UNI_FREE(msg); + uni_msg_destroy(m); + return; + } + + /* inform the parties on the network side */ + if (c->uni->proto == UNIPROTO_UNI40N && c->type == CALL_LEAF) + TAILQ_FOREACH(p, &c->parties, link) + uni_enq_party(p, SIGP_SETUP_response, 0, NULL, NULL); + + msg->u.connect = arg->connect; + MK_MSG_ORIG(msg, UNI_CONNECT, c->cref, !c->mine); + (void)uni_send_output(msg, c->uni); + UNI_FREE(msg); + + if (c->uni->proto == UNIPROTO_UNI40U) + TIMER_START_CALL(c, t313, c->uni->timer313); + + set_call_state(c, new_state); + + uni_msg_destroy(m); + + uniapi_call_error(c, UNIAPI_OK, cookie); +} + +/* + * Setup_complete.request + * + * Q.2971:Call-Control-N 15/39 (N8) + */ +static void +n8_setup_compl_request(struct call *c, struct uni_msg *m, uint32_t cookie, + enum call_state new_state) +{ + struct uni_all *msg; + struct uniapi_setup_complete_request *arg = + uni_msg_rptr(m, struct uniapi_setup_complete_request *); + struct party *p; + + if ((msg = UNI_ALLOC()) == NULL) { + uni_msg_destroy(m); + uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie); + return; + } + + /* inform the parties on the network side */ + if (c->uni->proto == UNIPROTO_UNI40N && + (c->type == CALL_LEAF || c->type == CALL_ROOT)) { + TAILQ_FOREACH(p, &c->parties, link) + uni_enq_party(p, SIGP_SETUP_COMPL_request, + 0, NULL, NULL); + } + + msg->u.connect_ack = arg->connect_ack; + MK_MSG_ORIG(msg, UNI_CONNECT_ACK, c->cref, !c->mine); + (void)uni_send_output(msg, c->uni); + UNI_FREE(msg); + + set_call_state(c, new_state); + + uni_msg_destroy(m); + + uniapi_call_error(c, UNIAPI_OK, cookie); +} + +/* + * CONNECT message + * + * Q.2971:Call-Control-U 7-8/39 (U3) + * Q.2971:Call-Control-U 11/39 (U4) + * Q.2971:Call-Control-U 37/39 (U1) + * Q.2971:Call-Control-N 9-10/39 (N6) + * Q.2971:Call-Control-N 14/39 (N7) + * Q.2971:Call-Control-N 17/39 (N9) + */ +static void +unx_connect(struct call *c, struct uni_msg *m, struct uni_all *u, + enum call_state new_state) +{ + struct uni_connect *co = &u->u.connect; + struct uniapi_setup_confirm *conf; + struct uni_msg *api; + struct uni_all *ack; + struct party *p; + + conf = ALLOC_API(struct uniapi_setup_confirm, api); + if (conf == NULL) { + ignore: + UNI_FREE(u); + uni_msg_destroy(m); + return; + } + if ((ack = UNI_ALLOC()) == NULL) { + uni_msg_destroy(api); + goto ignore; + } + + /* + * Analyze message + */ + (void)uni_decode_body(m, u, &c->uni->cx); + if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(co->connid)) + uni_mandate_ie(c->uni, UNI_IE_CONNID); + + /* + * Q.2971: L3MU_01_05 requires the epref to be present. + */ + p = NULL; + if (c->msg_setup.bearer.cfg == UNI_BEARER_MP) { + if (IE_ISPRESENT(c->msg_setup.epref)) { + if (!IE_ISPRESENT(co->epref)) + uni_mandate_ie(c->uni, UNI_IE_EPREF); \ + + if (IE_ISGOOD(co->epref) && + co->epref.flag != 1) { + IE_SETERROR(co->epref); + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + co->epref.h.act, UNI_IERR_BAD); + } + } + + if (IE_ISGOOD(co->epref)) { + p = uni_find_party(c, &co->epref); + if (p == NULL) { + respond_drop_party_ack(c, &co->epref, + UNI_CAUSE_ENDP_INV); + uni_msg_destroy(api); + UNI_FREE(ack); + goto ignore; + } + } + } + + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + /* FALLTHRU */ + case VFY_I: + uni_msg_destroy(api); + UNI_FREE(ack); + goto ignore; + + case VFY_RAIM: + case VFY_RAI: + report: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), NULL, 0); + uni_msg_destroy(api); + UNI_FREE(ack); + goto ignore; + + case VFY_RAP: + case VFY_RAPU: + if (c->type == CALL_ROOT && !IE_ISGOOD(co->epref)) + goto report; + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(new_state), NULL, 0); + /* FALLTHRU */ + case VFY_OK: + break; + } + + if (IE_ISGOOD(co->connid)) + c->connid = co->connid; + + if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6) + TIMER_STOP_CALL(c, t303); + else if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9) + TIMER_STOP_CALL(c, t310); + else if (c->cstate == CALLST_U4 || c->cstate == CALLST_N7) { + if(c->type == CALL_P2P) + TIMER_STOP_CALL(c, t301); + } + + /* + * This is sent to the party only on the user side and only + * to the one party in the epref (L3MU_05_03). + */ + if (c->uni->proto == UNIPROTO_UNI40U && + (c->type == CALL_LEAF || c->type == CALL_ROOT)) + uni_enq_party(p, SIGP_CONNECT, 0, NULL, NULL); + + conf->connect.hdr = u->u.hdr; + copy_msg_connect(co, &conf->connect); + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_SETUP_confirm, 0, api); + + if (c->uni->proto == UNIPROTO_UNI40U) { + /* this is left to the application on the network side */ + MK_MSG_ORIG(ack, UNI_CONNECT_ACK, c->cref, !c->mine); + (void)uni_send_output(ack, c->uni); + UNI_FREE(ack); + } + + UNI_FREE(u); + uni_msg_destroy(m); + + set_call_state(c, new_state); +} + +/* + * T313 (Connect) timer tick. + * + * Q.2971:Call-Control-U 15/39 + */ +static void +u8_t313(struct call *c) +{ + VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T313 tick", + c->cref, c->mine ? "mine" : "his"); + + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER); + ADD_CAUSE_TIMER(c->uni->cause, "313"); + clear_callD(c); +} + +/* + * CONNECT ACKNOWLEDGE message in U8 + * + * Q.2971:Call-Control-U 15-16/39 + */ +static void +u8_connect_ack(struct call *c, struct uni_msg *m, struct uni_all *u, + enum call_state new_state) +{ + struct uniapi_setup_complete_indication *ind; + struct uni_msg *api; + + ind = ALLOC_API(struct uniapi_setup_complete_indication, api); + if (ind == NULL) { + ignore: + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + + /* + * Analyze message + */ + (void)uni_decode_body(m, u, &c->uni->cx); + + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + /* FALLTHRU */ + case VFY_I: + uni_msg_destroy(api); + goto ignore; + + case VFY_RAIM: + case VFY_RAI: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), NULL, 0); + uni_msg_destroy(api); + goto ignore; + + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(new_state), NULL, 0); + /* FALLTHRU */ + case VFY_OK: + break; + } + + TIMER_STOP_CALL(c, t313); + + if (c->type == CALL_LEAF) { + struct party *p; + + TAILQ_FOREACH(p, &c->parties, link) { + if (p->flags & PARTY_CONNECT) { + uni_enq_party(p, SIGP_CONNECT_ACK, + 0, NULL, NULL); + break; + } + } + } + + ind->connect_ack.hdr = u->u.hdr; + copy_msg_connect_ack(&u->u.connect_ack, &ind->connect_ack); + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_SETUP_COMPLETE_indication, 0, api); + + UNI_FREE(u); + uni_msg_destroy(m); + + set_call_state(c, new_state); +} + +/* + * CONNECT ACKNOWLEDGE message in N10 + * + * Q.2971:Call-Control-N 18/39 + */ +static void +n10_connect_ack(struct call *c, struct uni_msg *m, struct uni_all *u) +{ + /* + * Analyze message + */ + (void)uni_decode_body(m, u, &c->uni->cx); + + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + /* FALLTHRU */ + case VFY_I: + uni_msg_destroy(m); + UNI_FREE(u); + return; + + case VFY_RAIM: + case VFY_RAI: + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), NULL, 0); + /* FALLTHRU */ + case VFY_OK: + uni_msg_destroy(m); + UNI_FREE(u); + return; + } +} + +/* + * Release.response in U6 or U12. + * + * Q.2971:Call-Control-U 12/39 (U6) + * Q.2971:Call-Control-U 30/39 (U12) + * Q.2971:Call-Control-N 6/39 (N1) + * Q.2971:Call-Control-N 29/39 (N11) + */ +static void +unx_release_response(struct call *c, struct uni_msg *m, uint32_t cookie) +{ + struct party *p; + struct uni_all *msg; + struct uniapi_release_response *arg = + uni_msg_rptr(m, struct uniapi_release_response *); + + if ((msg = UNI_ALLOC()) == NULL) { + uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie); + uni_msg_destroy(m); + return; + } + + if (c->cstate == CALLST_U6 || c->cstate == CALLST_N1) { + if (c->type == CALL_ROOT || c->type == CALL_LEAF) { + TAILQ_FOREACH(p, &c->parties, link) + uni_enq_party(p, SIGP_RELEASE_response, + cookie, NULL, NULL); + } + } + msg->u.release_compl = arg->release_compl; + MK_MSG_ORIG(msg, UNI_RELEASE_COMPL, c->cref, !c->mine); + (void)uni_send_output(msg, c->uni); + UNI_FREE(msg); + + uni_msg_destroy(m); + + uniapi_call_error(c, UNIAPI_OK, cookie); + + uni_destroy_call(c, 0); +} + +/* + * Got a RELEASE COMPLETE in any state expect U0 + * + * Q.2971:Call-Control-U 25/39 + * Q.2971:Call-Control-N 26/39 + * + * This is also called from the restart processes. + */ +void +uni_release_compl(struct call *c, struct uni_all *u) +{ + struct uni_msg *api; + struct uniapi_release_confirm *conf; + struct party *p; + u_int i, j; + + if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) == NULL) + return; + + reset_all_timers(c); + if (c->type == CALL_ROOT || c->type == CALL_LEAF) { + TAILQ_FOREACH(p, &c->parties, link) + uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL); + /* YYY optional call reoffering 10.3.3/10.3.4 */ + } + conf->release.hdr = u->u.hdr; + + for (i = j = 0; i < 2; i++) + if (IE_ISGOOD(u->u.release_compl.cause[i])) + conf->release.cause[j++] = u->u.release_compl.cause[i]; + for (i = j = 0; i < UNI_NUM_IE_GIT; i++) + if (IE_ISGOOD(u->u.release_compl.git[i])) + conf->release.git[j++] = u->u.release_compl.git[i]; + if (IE_ISGOOD(u->u.release_compl.uu)) + conf->release.uu = u->u.release_compl.uu; + if (IE_ISGOOD(u->u.release_compl.crankback)) + conf->release.crankback = u->u.release_compl.crankback; + + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_RELEASE_confirm, 0, api); + + uni_destroy_call(c, 0); +} +static void +unx_release_compl(struct call *c, struct uni_msg *m, struct uni_all *u) +{ + + (void)uni_decode_body(m, u, &c->uni->cx); + (void)uni_verify(c->uni, u->u.hdr.act); /* no point :-) */ + + uni_release_compl(c, u); + + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * Got a RELEASE COMPLETE in any state expect U0 and U11 + * + * Q.2971:Call-Control-U 25/39 + * Q.2971:Call-Control-N 26/39 + */ +static void +unx_release(struct call *c, struct uni_msg *m, struct uni_all *u, + enum call_state new_state) +{ + struct uniapi_release_indication *ind; + struct uni_msg *api; + + if ((ind = ALLOC_API(struct uniapi_release_indication, api)) == NULL) { + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + + (void)uni_decode_body(m, u, &c->uni->cx); + (void)uni_verify(c->uni, u->u.hdr.act); /* no point :-) */ + + reset_all_timers(c); + if (c->type == CALL_ROOT || c->type == CALL_LEAF) { + struct party *p; + + TAILQ_FOREACH(p, &c->parties, link) + uni_enq_party(p, SIGP_RELEASE, 0, NULL, NULL); + /* YYY optional call reoffering 10.3.3/10.3.4 */ + } + if (c->cstate != new_state) { + /* + * According to Q.2971 we should send a 2nd + * Release.indication. + * According to Q.2931 the recipte of a RELEASE in U12/N11 + * is illegal. + * According to us make it legal, but don't send a 2nd + * indication. + */ + ind->release.hdr = u->u.hdr; + copy_msg_release(&u->u.release, &ind->release); + + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_RELEASE_indication, 0, api); + } else + uni_msg_destroy(api); + + uni_msg_destroy(m); + UNI_FREE(u); + + set_call_state(c, new_state); +} + +/* + * Got RELEASE in U11 or N12 + * + * Q.2971:Call-Control-U 28/39 + * Q.2971:Call-Control-N 30/39 + */ +static void +u11n12_release(struct call *c, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_release_confirm *conf; + struct uni_msg *api; + + if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) == NULL) { + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + + (void)uni_decode_body(m, u, &c->uni->cx); + (void)uni_verify(c->uni, u->u.hdr.act); /* no point :-) */ + + TIMER_STOP_CALL(c, t308); + + conf->release.hdr = u->u.hdr; + copy_msg_release(&u->u.release, &conf->release); + + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_RELEASE_confirm, 0, api); + + uni_msg_destroy(m); + UNI_FREE(u); + + uni_destroy_call(c, 0); +} + +/* + * NOTIFY message + * + * Q.2971:Call-Control-U 18/39 + * Q.2971:Call-Control-N 19/39 + */ +static void +unx_notify(struct call *c, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_notify_indication *ind; + struct uni_msg *api; + struct party *p = NULL; + + if ((ind = ALLOC_API(struct uniapi_notify_indication, api)) == NULL) { + ignore: + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + + /* + * Analyze message + */ + (void)uni_decode_body(m, u, &c->uni->cx); + MANDATE_IE(c->uni, u->u.notify.notify, UNI_IE_NOTIFY); + + if (IE_ISGOOD(u->u.notify.epref)) { + if ((p = uni_find_party(c, &u->u.notify.epref)) == NULL) { + respond_drop_party_ack(c, &u->u.notify.epref, + UNI_CAUSE_ENDP_INV); + uni_msg_destroy(api); + goto ignore; + } + } + + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + uni_msg_destroy(api); + uni_vfy_collect_ies(c->uni); + clear_callD(c); + goto ignore; + + case VFY_RAIM: + case VFY_RAI: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), &u->u.notify.epref, + p ? p->state : 0); + /* FALLTHRU */ + case VFY_I: + uni_msg_destroy(api); + goto ignore; + + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), &u->u.notify.epref, + p ? p->state : 0); + case VFY_OK: + /* FALLTHRU */ + break; + } + + ind->notify.hdr = u->u.hdr; + copy_msg_notify(&u->u.notify, &ind->notify); + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_NOTIFY_indication, 0, api); + + UNI_FREE(u); + uni_msg_destroy(m); +} + +/* + * Notify.request from user + * + * Q.2971:Call-Control-U 18/39 + * Q.2971:Call-Control-N 19/39 + */ +static void +unx_notify_request(struct call *c, struct uni_msg *m, uint32_t cookie) +{ + struct uni_all *msg; + struct uniapi_notify_request *arg = + uni_msg_rptr(m, struct uniapi_notify_request *); + + if ((msg = UNI_ALLOC()) == NULL) { + uni_msg_destroy(m); + uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie); + return; + } + + msg->u.notify = arg->notify; + MK_MSG_ORIG(msg, UNI_NOTIFY, c->cref, !c->mine); + (void)uni_send_output(msg, c->uni); + UNI_FREE(msg); + + uni_msg_destroy(m); + + uniapi_call_error(c, UNIAPI_OK, cookie); +} + +/**********************************************************************/ + +/* + * Release.request from API in any state except U11, U12, N11, N12 + * + * Q.2971:Call-Control-U 27/39 + * Q.2971:Call-Control-N 28/39 + */ +static void +unx_release_request(struct call *c, struct uni_msg *m, uint32_t cookie, + enum call_state new_state) +{ + struct uni_all *msg; + struct uniapi_release_request *arg = + uni_msg_rptr(m, struct uniapi_release_request *); + struct party *p; + + if ((msg = UNI_ALLOC()) == NULL) { + uni_msg_destroy(m); + uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie); + return; + } + + reset_all_timers(c); + + if (c->type == CALL_LEAF || c->type == CALL_ROOT) { + TAILQ_FOREACH(p, &c->parties, link) { + uni_enq_party(p, SIGP_RELEASE_request, cookie, + NULL, NULL); + } + } + + c->msg_release = arg->release; + if (!IE_ISPRESENT(c->msg_release.cause[0]) && + !IE_ISPRESENT(c->msg_release.cause[1])) + MK_IE_CAUSE(c->msg_release.cause[0], UNI_CAUSE_LOC_USER, + UNI_CAUSE_UNSPEC); + + msg->u.release = c->msg_release; + MK_MSG_ORIG(msg, UNI_RELEASE, c->cref, !c->mine); + (void)uni_send_output(msg, c->uni); + UNI_FREE(msg); + + TIMER_START_CALL(c, t308, c->uni->timer308); + c->cnt308 = 0; + + set_call_state(c, new_state); + + uni_msg_destroy(m); + + uniapi_call_error(c, UNIAPI_OK, cookie); +} + +/* + * Message with unknown EPREF - send a drop party according to 9.5.3.2.3a) + */ +static void +respond_drop_party_ack(struct call *c, struct uni_ie_epref *epref, + u_int cause) +{ + struct uni_all *msg; + + if ((msg = UNI_ALLOC()) == NULL) + return; + + MK_MSG_ORIG(msg, UNI_DROP_PARTY_ACK, c->cref, !c->mine); + MK_IE_EPREF(msg->u.drop_party_ack.epref, epref->epref, !epref->flag); + MK_IE_CAUSE(msg->u.drop_party_ack.cause, UNI_CAUSE_LOC_USER, cause); + (void)uni_send_output(msg, c->uni); + UNI_FREE(msg); +} + +/* + * T308 (RELEASE) timer + * + * Q.2971:Call-Control-U 28/39 + * Q.2971:Call-Control-N 30/39 + */ +static void +u11n12_t308(struct call *c) +{ + struct uni_all *msg; + struct uni_msg *api; + struct uniapi_release_confirm *conf; + + VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T308 tick %d", + c->cref, c->mine ? "mine" : "his", c->cnt308 + 1); + + if (++c->cnt308 < c->uni->init308) { + if ((msg = UNI_ALLOC()) != NULL) { + msg->u.release = c->msg_release; + MK_MSG_ORIG(msg, UNI_RELEASE, c->cref, !c->mine); + if (!IE_ISPRESENT(msg->u.release.cause[1])) { + MK_IE_CAUSE(msg->u.release.cause[1], + UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER); + ADD_CAUSE_TIMER(msg->u.release.cause[1], "308"); + } + (void)uni_send_output(msg, c->uni); + UNI_FREE(msg); + } + TIMER_START_CALL(c, t308, c->uni->timer308); + return; + } + + /* + * Send indication to API + */ + if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) { + conf->release.hdr.cref.cref = c->cref; + conf->release.hdr.cref.flag = c->mine; + conf->release.hdr.act = UNI_MSGACT_DEFAULT; + MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER, + UNI_CAUSE_RECOVER); + ADD_CAUSE_TIMER(conf->release.cause[0], "308"); + + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_RELEASE_confirm, 0, api); + } + + uni_destroy_call(c, 0); +} +/**********************************************************************/ + +/* + * STATUS in U11/U12 + * + * Q.2971:Call-Control-U 29/39 (U11) + * Q.2971:Call-Control-U 30/39 (U12) + * Q.2971:Call-Control-N 29/39 (N11) + * Q.2971:Call-Control-N 31/39 (N12) + */ +static void +un11un12_status(struct call *c, struct uni_msg *m, struct uni_all *u) +{ + enum call_state ns; + struct uniapi_release_confirm *conf; + struct uni_msg *api; + struct party *p; + struct uniapi_status_indication *stat; + + /* + * Analyze message + */ + (void)uni_decode_body(m, u, &c->uni->cx); + MANDATE_IE(c->uni, u->u.status.callstate, UNI_IE_CALLSTATE); + MANDATE_IE(c->uni, u->u.status.cause, UNI_IE_CAUSE); + + ns = c->cstate; + if (IE_ISGOOD(u->u.status.callstate) && + u->u.status.callstate.state == UNI_CALLSTATE_U0) + ns = CALLST_NULL; + + p = NULL; + if (IE_ISGOOD(u->u.status.epref)) + p = uni_find_party(c, &u->u.status.epref); + + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + uni_msg_destroy(m); + UNI_FREE(u); + return; + + case VFY_RAIM: + case VFY_RAI: + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(ns), &u->u.status.epref, + p ? p->state : UNI_EPSTATE_NULL); + case VFY_I: + case VFY_OK: + break; + } + + if (ns == c->cstate) { + /* + * Inform API + */ + stat = ALLOC_API(struct uniapi_status_indication, api); + if (stat != NULL) { + stat->cref = u->u.hdr.cref; + stat->my_state = map_callstate(c->cstate); + stat->his_state = u->u.status.callstate; + stat->his_cause = u->u.status.cause; + stat->epref = u->u.status.epref; + stat->epstate = u->u.status.epstate; + stat->my_cause = 0; + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_STATUS_indication, 0, api); + } + + uni_msg_destroy(m); + UNI_FREE(u); + + return; + } + + uni_msg_destroy(m); + UNI_FREE(u); + + /* + * Send indication to API + */ + if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) { + conf->release.hdr.cref.cref = c->cref; + conf->release.hdr.cref.flag = c->mine; + conf->release.hdr.act = UNI_MSGACT_DEFAULT; + MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER, + UNI_CAUSE_MSG_INCOMP); + ADD_CAUSE_MTYPE(conf->release.cause[0], UNI_STATUS); + + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_RELEASE_confirm, 0, api); + } + + uni_destroy_call(c, 0); +} + +static int +status_enq_filter(struct sig *sig, void *arg) +{ + return (sig->type == SIG_CALL && + (struct call *)arg == sig->call && + sig->sig == SIGC_SEND_STATUS_ENQ); +} + +/* + * STATUS in any state except U0/U11/U12 N0/N11/N12 + * + * Q.2971:Call-Control-U 32/39 + * Q.2971:Call-Control-N 33/39 + */ +static void +unx_status(struct call *c, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_status_indication *stat; + struct uniapi_release_confirm *conf; + enum call_state ns; + struct uni_msg *api; + struct party *p; + + /* + * Analyze message + */ + (void)uni_decode_body(m, u, &c->uni->cx); + MANDATE_IE(c->uni, u->u.status.callstate, UNI_IE_CALLSTATE); + MANDATE_IE(c->uni, u->u.status.cause, UNI_IE_CAUSE); + + ns = c->cstate; + if (IE_ISGOOD(u->u.status.callstate)) + ns = state_compat(c, u->u.status.callstate.state); + + p = NULL; + if (IE_ISGOOD(u->u.status.epref)) { + p = uni_find_party(c, &u->u.status.epref); + MANDATE_IE(c->uni, u->u.status.epstate, UNI_IE_EPSTATE); + } + + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + uni_msg_destroy(m); + UNI_FREE(u); + return; + + case VFY_RAIM: + case VFY_RAI: + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(ns), &u->u.notify.epref, + p ? p->state : UNI_EPSTATE_NULL); + /* FALLTHRU */ + case VFY_I: + case VFY_OK: + break; + } + + if (u->u.status.callstate.state == UNI_CALLSTATE_U0) { + /* release_complete */ + uni_msg_destroy(m); + UNI_FREE(u); + + if (c->type == CALL_LEAF || c->type == CALL_ROOT) { + TAILQ_FOREACH(p, &c->parties, link) + uni_enq_party(p, SIGP_RELEASE_COMPL, + 0, NULL, NULL); + } + /* + * Send indication to API + */ + conf = ALLOC_API(struct uniapi_release_confirm, api); + if (conf != NULL) { + conf->release.hdr.cref.cref = c->cref; + conf->release.hdr.cref.flag = c->mine; + conf->release.hdr.act = UNI_MSGACT_DEFAULT; + MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER, + UNI_CAUSE_MSG_INCOMP); + ADD_CAUSE_MTYPE(conf->release.cause[0], UNI_STATUS); + + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_RELEASE_confirm, 0, api); + } + uni_destroy_call(c, 0); + return; + } + + if (IE_ISGOOD(u->u.status.cause) && + u->u.status.cause.cause == UNI_CAUSE_STATUS) { + c->se_active = 0; + TIMER_STOP_CALL(c, t322); + uni_undel(c->uni, status_enq_filter, c); + } + + /* + * Inform API + */ + if ((stat = ALLOC_API(struct uniapi_status_indication, api)) != NULL) { + stat->cref = u->u.hdr.cref; + stat->my_state = map_callstate(c->cstate); + stat->his_state = u->u.status.callstate; + stat->his_cause = u->u.status.cause; + stat->epref = u->u.status.epref; + stat->epstate = u->u.status.epstate; + } + + if (ns == c->cstate) { + /* compatible or recovered */ + if (p != NULL) + uni_enq_party(p, SIGP_STATUS, 0, m, u); + else { + if (IE_ISGOOD(u->u.status.epref) && + (!IE_ISGOOD(u->u.status.epstate) || + u->u.status.epstate.state != UNI_EPSTATE_NULL)) + respond_drop_party_ack(c, &u->u.status.epref, + UNI_CAUSE_MSG_INCOMP); + + uni_msg_destroy(m); + UNI_FREE(u); + } + if (stat != NULL) { + stat->my_cause = 0; + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_STATUS_indication, 0, api); + } + + return; + } + + /* incompatible */ + if (stat != NULL) { + stat->my_cause = UNI_CAUSE_MSG_INCOMP; + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_STATUS_indication, 0, api); + } + + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_MSG_INCOMP); + + uni_msg_destroy(m); + UNI_FREE(u); + + clear_callD(c); +} + +/* + * Enquiry peer status + * + * Q.2971:Call-Control-U 31/39 + * Q.2971:Call-Control-N 32/39 + */ +static void +unx_status_enquiry_request(struct call *c, struct uni_msg *msg, uint32_t cookie) +{ + struct uniapi_status_enquiry_request *arg = + uni_msg_rptr(msg, struct uniapi_status_enquiry_request *); + struct party *p; + struct uni_all *stat; + + if (c->se_active) { + /* This case is not handled in the SDLs */ + uniapi_call_error(c, UNIAPI_ERROR_BUSY, cookie); + uni_msg_destroy(msg); + return; + } + if ((c->type == CALL_ROOT || c->type == CALL_LEAF) && + IE_ISGOOD(arg->epref)) { + if ((p = uni_find_partyx(c, arg->epref.epref, !arg->epref.flag)) + == NULL) { + uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie); + uni_msg_destroy(msg); + return; + } + uni_msg_destroy(msg); + uni_enq_party(p, SIGP_STATUS_ENQUIRY_request, cookie, + NULL, NULL); + return; + } + if ((stat = UNI_ALLOC()) == NULL) { + uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie); + uni_msg_destroy(msg); + return; + } + memset(&c->stat_epref, 0, sizeof(c->stat_epref)); + MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine); + (void)uni_send_output(stat, c->uni); + UNI_FREE(stat); + + TIMER_START_CALL(c, t322, c->uni->timer322); + c->cnt322 = 0; + c->se_active = 1; + + uniapi_call_error(c, UNIAPI_OK, cookie); +} + +/* + * T322 tick + * + * Q.2971:Call-Control-U 34/39 + * Q.2971:Call-Control-N 35/39 + */ +static void +unx_t322(struct call *c) +{ + struct uni_all *stat; + + VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T322 tick %d", + c->cref, c->mine ? "mine" : "his", c->cnt322 + 1); + + if (++c->cnt322 < c->uni->init322) { + if ((stat = UNI_ALLOC()) != NULL) { + MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine); + stat->u.status_enq.epref = c->stat_epref; + (void)uni_send_output(stat, c->uni); + UNI_FREE(stat); + } + TIMER_START_CALL(c, t322, c->uni->timer322); + return; + } + c->se_active = 0; + + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER); + ADD_CAUSE_TIMER(c->uni->cause, "322"); + + clear_callD(c); +} + +/* + * STATUS ENQUIRY message + * + * Q.2971:Call-Control-U 31/39 + * Q.2971:Call-Control-N 32/39 + */ +static void +unx_status_enq(struct call *c, struct uni_msg *m, struct uni_all *u) +{ + struct party *p = NULL; + u_int epref, flag; + + /* + * Analyze message + */ + (void)uni_decode_body(m, u, &c->uni->cx); + + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + uni_msg_destroy(m); + UNI_FREE(u); + return; + + case VFY_RAIM: + case VFY_RAI: + case VFY_RAP: + case VFY_RAPU: + case VFY_I: + case VFY_OK: + break; + } + + uni_msg_destroy(m); + + if ((c->type == CALL_ROOT || c->type == CALL_LEAF) && + IE_ISGOOD(u->u.status_enq.epref)) { + p = uni_find_party(c, &u->u.status_enq.epref); + + epref = u->u.status_enq.epref.epref; + flag = u->u.status_enq.epref.flag; + memset(u, 0, sizeof(*u)); + MK_IE_EPREF(u->u.status.epref, epref, !flag); + + if (p != NULL) + MK_IE_EPSTATE(u->u.status.epstate, p->state); + else + MK_IE_EPSTATE(u->u.status.epstate, UNI_EPSTATE_NULL); + } else + memset(u, 0, sizeof(*u)); + + + MK_MSG_ORIG(u, UNI_STATUS, c->cref, !c->mine); + MK_IE_CALLSTATE(u->u.status.callstate, map_callstate(c->cstate)); + MK_IE_CAUSE(u->u.status.cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_STATUS); + (void)uni_send_output(u, c->uni); + UNI_FREE(u); +} + +/**********************************************************************/ + +/* + * Link-release.indication from SAAL in state U10 or N10. + * + * Q.2971:Call-Control-U 19/39 + * Q.2971:Call-Control-N 20/39 + */ +static void +un10_link_release_indication(struct call *c) +{ + struct party *p; + + if (c->type == CALL_LEAF || c->type == CALL_ROOT) + TAILQ_FOREACH(p, &c->parties, link) { + if (p->state != UNI_EPSTATE_ACTIVE) + uni_enq_party(p, SIGP_RELEASE_COMPL, + 0, NULL, NULL); + } + + uni_enq_coord(c->uni, SIGO_LINK_ESTABLISH_request, 0, NULL); +} + +/* + * Link-release.indication from SAAL in all state except U10 and N10. + * + * Q.2971:Call-Control-U 36/39 + * Q.2971:Call-Control-N 37/39 + */ +static void +unx_link_release_indication(struct call *c) +{ + struct uniapi_release_confirm *conf; + struct uni_msg *api; + struct party *p; + + if (c->type == CALL_LEAF || c->type == CALL_ROOT) + TAILQ_FOREACH(p, &c->parties, link) + uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL); + + if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) { + conf->release.hdr.cref.cref = c->cref; + conf->release.hdr.cref.flag = c->mine; + conf->release.hdr.act = UNI_MSGACT_DEFAULT; + MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER, + UNI_CAUSE_DST_OOO); + + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_RELEASE_confirm, 0, api); + } + + uni_destroy_call(c, 0); +} + +/* + * Failed to establish SAAL link. Can happen only in U10 or N10. + * + * Q.2971:Call-Control-U 19/39 + * Q.2971:Call-Control-N 20/39 + */ +static void +un10_link_establish_error_indication(struct call *c) +{ + struct party *p; + struct uni_msg *api; + struct uniapi_release_confirm *conf; + + if (c->type == CALL_LEAF || c->type == CALL_ROOT) + TAILQ_FOREACH(p, &c->parties, link) + uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL); + + if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) { + conf->release.hdr.cref.cref = c->cref; + conf->release.hdr.cref.flag = c->mine; + conf->release.hdr.act = UNI_MSGACT_DEFAULT; + MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER, + UNI_CAUSE_DST_OOO); + + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_RELEASE_confirm, 0, api); + } + + uni_destroy_call(c, 0); +} + +/* + * Issue a STATUS ENQUIRY of we are not busy + * + * Q.2971: Call-Control-U: 34/39 + * Q.2971: Call-Control-N: 34/39 + */ +static void +call_se(struct call *c) +{ + struct uni_all *stat; + + c->cnt322 = 0; + if (c->se_active) + return; + + memset(&c->stat_epref, 0, sizeof(c->stat_epref)); + if ((stat = UNI_ALLOC()) != NULL) { + MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine); + (void)uni_send_output(stat, c->uni); + UNI_FREE(stat); + } + + TIMER_START_CALL(c, t322, c->uni->timer322); + c->se_active = 1; +} + +/* + * Link-establish.indication in U10 + * + * Q.2971:Call-Control-U 19-20/39 + * Q.2971:Call-Control-N 20-22/39 + */ +static void +un10_link_establish_indication(struct call *c) +{ + int act = 0; + struct party *p; + + if (c->type == CALL_ROOT || c->type == CALL_LEAF) { + TAILQ_FOREACH(p, &c->parties, link) + if (p->state == UNI_EPSTATE_ACTIVE) { + act = 1; + uni_enq_party(p, SIGP_STATUS_ENQUIRY_request, + 0, NULL, NULL); + } + if (act) + return; + } + call_se(c); +} + +/* + * Link-establish.indication in NOT U10/U11/U12 N10/N11/N12 + * + * Q.2971:Call-Control-U 36/39 + * Q.2971:Call-Control-N 37/39 + */ +static void +unx_link_establish_indication(struct call *c) +{ + call_se(c); +} + +/* + * Link-establish.confirm in U10 or N10 + * + * Q.2971:Call-Control-U 19/39 + * Q.2971:Call-Control-N 20/39 + */ +static void +un10_link_establish_confirm(struct call *c) +{ + struct party *p; + + if (c->type == CALL_ROOT || c->type == CALL_LEAF) { + TAILQ_FOREACH(p, &c->parties, link) + uni_enq_party(p, SIGP_STATUS_ENQUIRY_request, + 0, NULL, NULL); + return; + } + + call_se(c); +} + +/* + * STATUS ENQ from party + * + * Q.2971:Call-Control-U 21/39 + * Q.2971:Call-Control-U 25/39 + */ +static void +unx_send_party_status_enq(struct call *c, struct uni_all *u) +{ + if (c->se_active) { + uni_delenq_sig(c->uni, SIG_CALL, c, NULL, + SIGC_SEND_STATUS_ENQ, 0, NULL, u); + return; + } + + c->stat_epref = u->u.status_enq.epref; + (void)uni_send_output(u, c->uni); + UNI_FREE(u); + + TIMER_START_CALL(c, t322, c->uni->timer322); + c->se_active = 1; +} + +/**********************************************************************/ + +static void +make_drop_cause(struct call *c, struct uni_ie_cause *cause) +{ + + if (!IE_ISGOOD(*cause)) { + /* 9.5.7.1 paragraph 2 */ + if (IE_ISPRESENT(*cause)) + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_IE_INV); + else + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_MANDAT); + c->uni->cause.u.ie.len = 1; + c->uni->cause.u.ie.ie[0] = UNI_IE_CAUSE; + c->uni->cause.h.present |= UNI_CAUSE_IE_P; + + } else if (!IE_ISGOOD(c->uni->cause)) + c->uni->cause = *cause; +} + +/* + * Drop-party.indication from Party-Control in any state. + * + * Q.2971:Call-Control-U 23/39 + */ +static void +ux_drop_party_indication(struct call *c, struct uni_msg *api) +{ + struct uniapi_drop_party_indication *drop = + uni_msg_rptr(api, struct uniapi_drop_party_indication *); + + if (uni_party_act_count(c, 2) == 0) { + if (c->cstate != CALLST_U11) { + make_drop_cause(c, &drop->drop.cause); + clear_callD(c); + } + uni_msg_destroy(api); + return; + } + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_DROP_PARTY_indication, 0, api); +} + +/* + * Drop-party.indication from Party-Control in any state. + * + * Q.2971:Call-Control-N 23/39 + */ +static void +nx_drop_party_indication(struct call *c, struct uni_msg *api) +{ + struct uniapi_drop_party_indication *drop = + uni_msg_rptr(api, struct uniapi_drop_party_indication *); + + if (uni_party_act_count(c, 0) == 0) { + if (uni_party_act_count(c, 1) == 0) { + if (c->cstate != CALLST_U11) { + make_drop_cause(c, &drop->drop.cause); + clear_callD(c); + } + uni_msg_destroy(api); + } else { + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_DROP_PARTY_indication, 0, api); + set_call_state(c, CALLST_N7); + } + } else { + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_DROP_PARTY_indication, 0, api); + } +} + +/* + * Drop-party-ack.indication from Party-Control in any state. + * + * Q.2971:Call-Control-U 23/39 + */ +static void +ux_drop_party_ack_indication(struct call *c, struct uni_msg *api) +{ + struct uniapi_drop_party_ack_indication *drop = + uni_msg_rptr(api, struct uniapi_drop_party_ack_indication *); + + if (uni_party_act_count(c, 2) == 0) { + if (c->cstate != CALLST_U11) { + make_drop_cause(c, &drop->drop.cause); + clear_callD(c); + } + uni_msg_destroy(api); + return; + } + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_DROP_PARTY_ACK_indication, 0, api); +} + +/* + * Drop-party-ack.indication from Party-Control in any state. + * + * Q.2971:Call-Control-N 23/39 + */ +static void +nx_drop_party_ack_indication(struct call *c, struct uni_msg *api) +{ + struct uniapi_drop_party_ack_indication *drop = + uni_msg_rptr(api, struct uniapi_drop_party_ack_indication *); + + if (uni_party_act_count(c, 0) == 0) { + if (uni_party_act_count(c, 1) == 0) { + if (c->cstate != CALLST_U11) { + make_drop_cause(c, &drop->drop.cause); + clear_callD(c); + } + uni_msg_destroy(api); + } else { + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_DROP_PARTY_ACK_indication, 0, api); + set_call_state(c, CALLST_N7); + } + } else { + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_DROP_PARTY_ACK_indication, 0, api); + } +} + +/* + * Add-party-rej.indication from Party-Control in any state. + * + * Q.2971:Call-Control-U 23/39 + */ +static void +ux_add_party_rej_indication(struct call *c, struct uni_msg *api) +{ + struct uniapi_add_party_rej_indication *rej = + uni_msg_rptr(api, struct uniapi_add_party_rej_indication *); + + if (uni_party_act_count(c, 2) == 0) { + if (c->cstate != CALLST_U11) { + make_drop_cause(c, &rej->rej.cause); + clear_callD(c); + } + uni_msg_destroy(api); + return; + } + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_ADD_PARTY_REJ_indication, 0, api); +} + +/* + * Add-party-rej.indication from Party-Control in any state. + * + * Q.2971:Call-Control-N 23/39 + */ +static void +nx_add_party_rej_indication(struct call *c, struct uni_msg *api) +{ + struct uniapi_add_party_rej_indication *rej = + uni_msg_rptr(api, struct uniapi_add_party_rej_indication *); + + if (uni_party_act_count(c, 0) == 0) { + if (uni_party_act_count(c, 1) == 0) { + if (c->cstate != CALLST_U11) { + make_drop_cause(c, &rej->rej.cause); + clear_callD(c); + } + uni_msg_destroy(api); + } else { + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_ADD_PARTY_REJ_indication, 0, api); + set_call_state(c, CALLST_N7); + } + } else { + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_ADD_PARTY_REJ_indication, 0, api); + } +} + +/* + * Add-party.request from API in U4 or U10 + * + * Q.2971:Call-Control-U 9-10/39 (U4) + * Q.2971:Call-Control-U 21/39 (U10) + * Q.2971:Call-Control-N 12/39 (N7) + * Q.2971:Call-Control-N 22/39 (N10) + */ +static void +unx_add_party_request(struct call *c, struct uni_msg *msg, uint32_t cookie) +{ + struct uniapi_add_party_request *add = + uni_msg_rptr(msg, struct uniapi_add_party_request *); + struct party *p; + + if (IE_ISGOOD(add->add.epref)) { + if (add->add.epref.flag != 0) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie); + return; + } + p = uni_find_partyx(c, add->add.epref.epref, 1); + if (p != NULL) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_EPREF_INUSE, cookie); + return; + } + } else if (!IE_ISPRESENT(add->add.epref)) { + allocate_epref(c, &add->add.epref); + if (!IE_ISPRESENT(add->add.epref)) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_EPREF_INUSE, cookie); + return; + } + } else { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie); + return; + } + + if ((p = uni_create_partyx(c, add->add.epref.epref, 1, cookie)) == NULL) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie); + return; + } + uni_enq_party(p, SIGP_ADD_PARTY_request, cookie, msg, NULL); +} + +/* + * Add-party-ack.request from API in U10/N10 + * + * Q.2971:Call-Control-U 21/39 + * Q.2971:Call-Control-N 22/39 + */ +static void +un10_add_party_ack_request(struct call *c, struct uni_msg *msg, uint32_t cookie) +{ + struct uniapi_add_party_ack_request *ack = + uni_msg_rptr(msg, struct uniapi_add_party_ack_request *); + struct party *p; + + if (!IE_ISGOOD(ack->ack.epref)) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie); + return; + } + if (ack->ack.epref.flag != 1) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie); + return; + } + if ((p = uni_find_partyx(c, ack->ack.epref.epref, 0)) == NULL) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie); + return; + } + + uni_enq_party(p, SIGP_ADD_PARTY_ACK_request, cookie, msg, NULL); +} + +/* + * Party-alerting.request from API in U7/U8/U10 + * + * Q.2971:Call-Control-U 14/39 U7 + * Q.2971:Call-Control-U 15/39 U8 + * Q.2971:Call-Control-U 21/39 U10 + * Q.2971:Call-Control-N 8/39 N4 + * Q.2971:Call-Control-N 22/39 N10 + */ +static void +unx_party_alerting_request(struct call *c, struct uni_msg *msg, uint32_t cookie) +{ + struct uniapi_party_alerting_request *alert = + uni_msg_rptr(msg, struct uniapi_party_alerting_request *); + struct party *p; + + if (!IE_ISGOOD(alert->alert.epref)) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie); + return; + } + if (alert->alert.epref.flag != 1) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie); + return; + } + if ((p = uni_find_partyx(c, alert->alert.epref.epref, 0)) == NULL) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie); + return; + } + + uni_enq_party(p, SIGP_PARTY_ALERTING_request, cookie, msg, NULL); +} + +/* + * Add-party-rej.request from API in U7/U8/U10/N4/N10 + * + * Q.2971:Call-Control-U 14/39 U7 + * Q.2971:Call-Control-U 15/39 U8 + * Q.2971:Call-Control-U 21/39 U10 + * Q.2971:Call-Control-N 8/39 N4 + * Q.2971:Call-Control-N 22/39 N10 + */ +static void +unx_add_party_rej_request(struct call *c, struct uni_msg *msg, uint32_t cookie) +{ + struct uniapi_add_party_rej_request *rej = + uni_msg_rptr(msg, struct uniapi_add_party_rej_request *); + struct party *p; + + if (!IE_ISGOOD(rej->rej.epref)) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie); + return; + } + if (rej->rej.epref.flag != 1) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie); + return; + } + if ((p = uni_find_partyx(c, rej->rej.epref.epref, 0)) == NULL) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie); + return; + } + + uni_enq_party(p, SIGP_ADD_PARTY_REJ_request, cookie, msg, NULL); +} + +/* + * Drop-party.request from API in U1-U10 + * + * Q.2971:Call-Control-U 21/39 U10 + * Q.2971:Call-Control-U 26/39 U1-U9 + * Q.2971:Call-Control-N 22/39 N10 + * Q.2971:Call-Control-N 27/39 N1-N9 + */ +static void +unx_drop_party_request(struct call *c, struct uni_msg *msg, uint32_t cookie) +{ + struct uniapi_drop_party_request *drop = + uni_msg_rptr(msg, struct uniapi_drop_party_request *); + struct party *p; + + if (!IE_ISGOOD(drop->drop.epref)) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie); + return; + } + if ((p = uni_find_partyx(c, drop->drop.epref.epref, !drop->drop.epref.flag)) == NULL) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie); + return; + } + + uni_enq_party(p, SIGP_DROP_PARTY_request, cookie, msg, NULL); +} + +/* + * Drop-party-ack.request from API in U1-U10 + * + * Q.2971:Call-Control-U 21/39 U10 + * Q.2971:Call-Control-U 26/39 U1-U9 + * Q.2971:Call-Control-N 22/39 N10 + * Q.2971:Call-Control-N 27/39 N1-N9 + */ +static void +unx_drop_party_ack_request(struct call *c, struct uni_msg *msg, + uint32_t cookie) +{ + struct uniapi_drop_party_ack_request *ack = + uni_msg_rptr(msg, struct uniapi_drop_party_ack_request *); + struct party *p; + + if (!IE_ISGOOD(ack->ack.epref)) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie); + return; + } + if ((p = uni_find_partyx(c, ack->ack.epref.epref, !ack->ack.epref.flag)) == NULL) { + uni_msg_destroy(msg); + uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie); + return; + } + + uni_enq_party(p, SIGP_DROP_PARTY_ACK_request, cookie, msg, NULL); +} + +/* + * ADD PARTY in U7/U8/U10 + * + * Q.2971:Call-Control-U 14/39 U7 + * Q.2971:Call-Control-U 15/39 U8 + * Q.2971:Call-Control-U 21/39 U10 + * Q.2971:Call-Control-N 8/39 N4 + * Q.2971:Call-Control-N 21/39 N10 + * + * Body already decoded + * XXX check EPREF flag + */ +static void +unx_add_party(struct call *c, struct uni_msg *m, struct uni_all *u, + int legal) +{ + struct uni_all *resp; + struct uni_ierr *e1; + struct party *p = NULL; + enum verify vfy; + + uni_mandate_epref(c->uni, &u->u.add_party.epref); + MANDATE_IE(c->uni, u->u.add_party.called, UNI_IE_CALLED); + + /* + * Do part of the verify handish: according to 9.5.7.2 we must send + * an ADD_PARTY_REJ if mandatory IEs are bad or missing instead of + * clearing the call. But we must send a STATUS, if it is the EPREF! + */ + if (IE_ISGOOD(u->u.add_party.epref)) { + c->uni->cause.u.ie.len = 0; + FOREACH_ERR(e1, c->uni) { + if (e1->err == UNI_IERR_MIS) { + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_MANDAT); + goto rej; + } + } + FOREACH_ERR(e1, c->uni) { + if (e1->man && e1->ie != UNI_IE_EPREF && + e1->act == UNI_IEACT_DEFAULT) { + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_IE_INV); + rej: + uni_vfy_collect_ies(c->uni); + if ((resp = UNI_ALLOC()) != NULL) { + MK_MSG_RESP(resp, UNI_ADD_PARTY_REJ, + &u->u.hdr.cref); + MK_IE_EPREF(resp->u.add_party_rej.epref, + u->u.add_party.epref.epref, + !u->u.add_party.epref.flag); + resp->u.add_party_rej.cause = + c->uni->cause; + + unx_send_add_party_rej(c, resp); + } + goto ignore; + } + } + p = uni_find_partyx(c, u->u.add_party.epref.epref, + u->u.add_party.epref.flag); + } + + vfy = uni_verify(c->uni, u->u.hdr.act); + + switch (vfy) { + + case VFY_CLR: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + goto ignore; + + case VFY_RAIM: + case VFY_RAI: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), &u->u.add_party.epref, + p ? p->state : UNI_EPSTATE_NULL); + /* FALLTHRU */ + case VFY_I: + goto ignore; + + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), &u->u.add_party.epref, + UNI_EPSTATE_ADD_RCVD); + case VFY_OK: + /* FALLTHRU */ + break; + } + if (!legal) { + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.add_party.epref, -1); + return; + } + + if (IE_ISGOOD(u->u.add_party.epref) && p == NULL && + u->u.add_party.epref.flag) { + IE_SETERROR(u->u.add_party.epref); + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + u->u.add_party.epref.h.act, UNI_IERR_BAD); + } + + if (!IE_ISGOOD(u->u.add_party.epref)) { + /* 9.5.3.2.2 */ + if (vfy == VFY_OK) { + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_IE_INV); + + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), NULL, 0); + } + goto ignore; + } + + + if (p == NULL && (p = uni_create_party(c, &u->u.add_party.epref)) + == NULL) + goto ignore; + + uni_enq_party(p, SIGP_ADD_PARTY, 0, m, u); + return; + + ignore: + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * ADD PARTY ACKNOWLEDGE + * + * Q.2971:Call-Control-U 21/39 U10 + * Q.2971:Call-Control-N 15/39 N8 + * Q.2971:Call-Control-N 22/39 N10 + */ +static void +un10n8_add_party_ack(struct call *c, struct uni_msg *m, struct uni_all *u, + int legal) +{ + struct party *p = NULL; + + if (IE_ISGOOD(u->u.add_party_ack.epref)) { + if (u->u.add_party_ack.epref.flag == 0) { + IE_SETERROR(u->u.add_party_ack.epref); + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + u->u.add_party_ack.epref.h.act, UNI_IERR_BAD); + } else { + p = uni_find_partyx(c, u->u.add_party_ack.epref.epref, 1); + if (p == NULL) { + respond_drop_party_ack(c, + &u->u.add_party_ack.epref, + UNI_CAUSE_ENDP_INV); + goto ignore; + } + } + } + uni_mandate_epref(c->uni, &u->u.add_party_ack.epref); + + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + goto ignore; + + case VFY_RAIM: + case VFY_RAI: + report: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), &u->u.add_party_ack.epref, + p ? p->state : UNI_EPSTATE_NULL); + case VFY_I: + goto ignore; + + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), &u->u.add_party_ack.epref, + p ? UNI_EPSTATE_ACTIVE : UNI_EPSTATE_NULL); + if (!IE_ISGOOD(u->u.party_alerting.epref)) + /* See below */ + goto ignore; + break; + case VFY_OK: + if (!IE_ISGOOD(u->u.party_alerting.epref)) + /* this happens when the EPREF has bad format. + * The rules require us the message to be ignored + * (9.5.3.2.2e) and to report status. + */ + goto report; + break; + } + if (legal) { + /* p is != NULL here */ + uni_enq_party(p, SIGP_ADD_PARTY_ACK, 0, m, u); + return; + } + if (p == NULL) + /* Q.2971 9.5.3.2.3a) */ + respond_drop_party_ack(c, &u->u.add_party_ack.epref, + UNI_CAUSE_ENDP_INV); + else + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.add_party_ack.epref, p->state); + + ignore: + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * Make the EPREF action default + */ +static void +default_act_epref(struct uni *uni, struct uni_ie_epref *epref) +{ + struct uni_ierr *e; + + FOREACH_ERR(e, uni) + if (e->ie == UNI_IE_EPREF) { + e->act = UNI_IEACT_DEFAULT; + break; + } + epref->h.act = UNI_IEACT_DEFAULT; +} + +/* + * PARTY ALERTING message + * + * Q.2971:Call-Control-U 9/39 U4 + * Q.2971:Call-Control-U 21/39 U10 + * Q.2971:Call-Control-N 12/39 N7 + * Q.2971:Call-Control-N 15/39 N8 + * Q.2971:Call-Control-N 22/39 N10 + */ +static void +unx_party_alerting(struct call *c, struct uni_msg *m, struct uni_all *u, + int legal) +{ + struct party *p = NULL; + + if (IE_ISGOOD(u->u.party_alerting.epref)) { + if (u->u.party_alerting.epref.flag == 0) { + IE_SETERROR(u->u.party_alerting.epref); + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + u->u.party_alerting.epref.h.act, UNI_IERR_BAD); + } else { + p = uni_find_partyx(c, u->u.party_alerting.epref.epref, 1); + if (p == NULL) { + respond_drop_party_ack(c, + &u->u.party_alerting.epref, + UNI_CAUSE_ENDP_INV); + goto ignore; + } + } + } + uni_mandate_epref(c->uni, &u->u.party_alerting.epref); + + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + goto ignore; + + case VFY_RAIM: + case VFY_RAI: + report: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), &u->u.party_alerting.epref, + p ? p->state : UNI_EPSTATE_NULL); + case VFY_I: + goto ignore; + + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), &u->u.party_alerting.epref, + p ? UNI_EPSTATE_ALERT_RCVD : UNI_EPSTATE_NULL); + if (!IE_ISGOOD(u->u.party_alerting.epref)) + /* See below */ + goto ignore; + break; + + case VFY_OK: + if (!IE_ISGOOD(u->u.party_alerting.epref)) + /* The rules require us the message to be ignored + * (9.5.3.2.2e) and to report status. + */ + goto report; + break; + } + if (legal) { + /* p is != NULL here */ + uni_enq_party(p, SIGP_PARTY_ALERTING, 0, m, u); + return; + } + if (p == NULL) + /* Q.2971 9.5.3.2.3a) */ + respond_drop_party_ack(c, &u->u.party_alerting.epref, + UNI_CAUSE_ENDP_INV); + else + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.party_alerting.epref, p->state); + + ignore: + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * Handle a bad/missing cause in a DROP_PARTY_ACK or ADD_PARTY_REJ + * + * If the IE is missing or bad and the action is defaulted handle as + * cause #1 according to 9.5.7.1/2. + * Otherwise keep the IE. + */ +static void +handle_bad_drop_cause(struct call *c, struct uni_ie_cause *cause, int mkcause) +{ + + if (IE_ISGOOD(*cause)) + return; + + if (!IE_ISPRESENT(*cause)) { + /* 9.5.7.1 */ + /* cannot make cause here because we need the 96 error */ + uni_vfy_remove_cause(c->uni); + return; + } + if (cause->h.act != UNI_IEACT_DEFAULT) + return; + + /* 9.5.7.2 */ + uni_vfy_remove_cause(c->uni); + if (mkcause) + MK_IE_CAUSE(*cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_UNSPEC); +} + +/* + * ADD PARTY REJ from party control + * Q.2971:Call-Control-U 21/39 + * Q.2971:Call-Control-U 24/39 + */ +static void +unx_send_add_party_rej(struct call *c, struct uni_all *u) +{ + + if (uni_party_act_count(c, 2) == 0) { + if (c->cstate != CALLST_U11 && c->cstate != CALLST_N12) { + c->uni->cause = u->u.add_party_rej.cause; + clear_callD(c); + } + } else + (void)uni_send_output(u, c->uni); + UNI_FREE(u); +} + +/* + * ADD_PARTY_REJECT in U4/U10 + * + * Q.2971:Call-Control-U 9/39 U4 + * Q.2971:Call-Control-U 21/39 U10 + * Q.2971:Call-Control-N 12/39 N7 + * Q.2971:Call-Control-N 15/39 N8 + * Q.2971:Call-Control-N 22/39 N10 + */ +static void +unx_add_party_rej(struct call *c, struct uni_msg *m, struct uni_all *u, + int legal) +{ + struct uni_add_party_rej *ar = &u->u.add_party_rej; + struct party *p; + + if (IE_ISGOOD(ar->epref)) { + p = uni_find_partyx(c, ar->epref.epref, ar->epref.flag); + if (p == NULL) + goto ignore; + + if (legal) { + handle_bad_drop_cause(c, &ar->cause, 0); + uni_vfy_remove_unknown(c->uni); + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + goto clear; + + case VFY_RAIM: + case VFY_RAI: + uni_respond_status_verify(c->uni, + &u->u.hdr.cref, map_callstate(c->cstate), + &ar->epref, p->state); + case VFY_I: + goto ignore; + + case VFY_RAPU: + uni_vfy_collect_ies(c->uni); + break; + + case VFY_RAP: + uni_respond_status_verify(c->uni, + &u->u.hdr.cref, map_callstate(c->cstate), + &ar->epref, p->state); + case VFY_OK: + break; + } + uni_enq_party(p, SIGP_ADD_PARTY_REJ, 0, m, u); + return; + } + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &ar->epref, -1); + return; + } + + /* Q.2971: 9.5.3.2.1 last paragraph + * 9.5.3.2.2 second to last paragraph + * Make the action indicator default. + */ + default_act_epref(c->uni, &ar->epref); + if (!IE_ISPRESENT(ar->epref)) + uni_mandate_ie(c->uni, UNI_IE_EPREF); + (void)uni_verify(c->uni, u->u.hdr.act); + + clear: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + + ignore: + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * DROP_PARTY + * + * Q.2971:Call-Control-U 26/39 Ux + * Q.2971:Call-Control-U 21/39 U10 + * Q.2971:Call-Control-N 27/39 Nx + * Q.2971:Call-Control-N 22/39 N10 + */ +static void +unx_drop_party(struct call *c, struct uni_msg *m, struct uni_all *u, int legal) +{ + struct uni_drop_party *dp = &u->u.drop_party; + struct party *p; + struct uni_ierr *e; + + if (IE_ISGOOD(dp->epref)) { + p = uni_find_partyx(c, dp->epref.epref, dp->epref.flag); + if (p == NULL) { + respond_drop_party_ack(c, &dp->epref, + UNI_CAUSE_ENDP_INV); + goto ignore; + } + handle_bad_drop_cause(c, &dp->cause, 0); + uni_vfy_remove_unknown(c->uni); + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + goto clear; + + case VFY_RAIM: + case VFY_RAI: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), + &u->u.drop_party.epref, p->state); + case VFY_I: + goto ignore; + + case VFY_RAPU: + uni_vfy_collect_ies(c->uni); + break; + + case VFY_RAP: + uni_respond_status_verify(c->uni, &u->u.hdr.cref, + map_callstate(c->cstate), + &dp->epref, UNI_EPSTATE_DROP_RCVD); + case VFY_OK: + break; + } + if (legal) { + uni_enq_party(p, SIGP_DROP_PARTY, 0, m, u); + return; + } + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, &dp->epref, -1); + goto ignore; + } + + /* Q.2971: 9.5.3.2.1 last paragraph + * 9.5.3.2.2 second to last paragraph + * Make the action indicator default. + */ + FOREACH_ERR(e, c->uni) + if (e->ie == UNI_IE_EPREF) { + e->act = UNI_IEACT_DEFAULT; + break; + } + dp->epref.h.act = UNI_IEACT_DEFAULT; + + if (!IE_ISPRESENT(dp->epref)) + uni_mandate_ie(c->uni, UNI_IE_EPREF); + (void)uni_verify(c->uni, u->u.hdr.act); + + clear: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + uni_msg_destroy(m); + UNI_FREE(u); + return; + + ignore: + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * DROP_PARTY_ACK + * + * Q.2971:Call-Control-U 26/39 Ux + * Q.2971:Call-Control-U 21/39 U10 + * Q.2971:Call-Control-N 27/39 Nx + * Q.2971:Call-Control-N 22/39 N10 + */ +static void +unx_drop_party_ack(struct call *c, struct uni_msg *m, struct uni_all *u, + int legal) +{ + struct party *p; + struct uni_drop_party_ack *ack = &u->u.drop_party_ack; + + if (IE_ISGOOD(u->u.drop_party_ack.epref)) { + p = uni_find_partyx(c, ack->epref.epref, ack->epref.flag); + if (p != NULL) { + handle_bad_drop_cause(c, &ack->cause, 1); + uni_vfy_remove_unknown(c->uni); + switch (uni_verify(c->uni, u->u.hdr.act)) { + + case VFY_CLR: + goto clear; + + case VFY_RAIM: + case VFY_RAI: + uni_respond_status_verify(c->uni, + &u->u.hdr.cref, map_callstate(c->cstate), + &ack->epref, p->state); + case VFY_I: + goto ignore; + + case VFY_RAP: + uni_respond_status_verify(c->uni, + &u->u.hdr.cref, map_callstate(c->cstate), + &ack->epref, UNI_EPSTATE_NULL); + case VFY_RAPU: + case VFY_OK: + break; + } + if (legal) { + uni_enq_party(p, SIGP_DROP_PARTY_ACK, 0, m, u); + return; + } + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &ack->epref, -1); + } + goto ignore; + } + + /* Q.2971: 9.5.3.2.1 last paragraph + * 9.5.3.2.2 second to last paragraph + */ + (void)uni_verify(c->uni, u->u.hdr.act); + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_IE_INV); + + clear: + uni_vfy_collect_ies(c->uni); + clear_callD(c); + uni_msg_destroy(m); + UNI_FREE(u); + return; + + ignore: + uni_msg_destroy(m); + UNI_FREE(u); +} + +/**********************************************************************/ + +/* + * Bad or unrecognized message. + * + * Q.2971:Call-Control-U 35/39 + */ +void +uni_bad_message(struct call *c, struct uni_all *u, u_int cause, + struct uni_ie_epref *epref, int ps) +{ + struct uni_all *resp; + struct party *p; + + if ((u->u.hdr.act == UNI_MSGACT_CLEAR && + (c->cstate == CALLST_U11 || + c->cstate == CALLST_U12 || + c->cstate == CALLST_N11 || + c->cstate == CALLST_N12)) || + u->u.hdr.act == UNI_MSGACT_IGNORE) + return; + + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, cause); + ADD_CAUSE_MTYPE(c->uni->cause, u->mtype); + + if (u->u.hdr.act == UNI_MSGACT_CLEAR) { + clear_callD(c); + return; + } + + /* + * Send STATUS + */ + if ((resp = UNI_ALLOC()) != NULL) { + MK_MSG_RESP(resp, UNI_STATUS, &u->u.hdr.cref); + MK_IE_CALLSTATE(resp->u.status.callstate, + map_callstate(c->cstate)); + resp->u.status.cause = c->uni->cause; + + if (epref != NULL && IE_ISGOOD(*epref)) { + MK_IE_EPREF(resp->u.status.epref, epref->epref, !epref->flag); + if (ps == -1) { + p = uni_find_party(c, epref); + if (p == NULL) + ps = UNI_EPSTATE_NULL; + else + ps = p->state; + } + MK_IE_EPSTATE(resp->u.status.epstate, ps); + } + (void)uni_send_output(resp, c->uni); + + UNI_FREE(resp); + } +} + +/**********************************************************************/ + +/* + * Unknown message in any state. + * + * Q.2971:Call-Control 35/39 + * Q.2971:Call-Control 36/39 + */ +static void +unx_unknown(struct call *c, struct uni_msg *m, struct uni_all *u) +{ + /* + * Unrecognized message. Cannot call verify here, because + * it doesn't know about unrecognized messages. + */ + if (u->u.hdr.act == UNI_MSGACT_CLEAR) { + MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_MTYPE_NIMPL); + ADD_CAUSE_MTYPE(c->uni->cause, u->mtype); + clear_callD(c); + } else if(u->u.hdr.act == UNI_MSGACT_IGNORE) { + ; + } else { + (void)uni_decode_body(m, u, &c->uni->cx); + uni_bad_message(c, u, UNI_CAUSE_MTYPE_NIMPL, + &u->u.unknown.epref, -1); + } + uni_msg_destroy(m); + UNI_FREE(u); +} +/**********************************************************************/ + +void +uni_sig_call(struct call *c, enum call_sig sig, uint32_t cookie, + struct uni_msg *msg, struct uni_all *u) +{ + if (sig >= SIGC_END) { + VERBOSE(c->uni, UNI_FAC_ERR, 1, + "Signal %d outside of range to Call-Control", sig); + if (msg) + uni_msg_destroy(msg); + if (u) + UNI_FREE(u); + return; + } + + VERBOSE(c->uni, UNI_FAC_CALL, 1, "Signal %s in state %s of call %u/%s" + "; cookie %u", call_sigs[sig], callstates[c->cstate].name, c->cref, + c->mine ? "mine" : "his", cookie); + + switch (sig) { + + case SIGC_LINK_RELEASE_indication: + if (c->cstate == CALLST_U10 || c->cstate == CALLST_N10) + /* Q.2971:Call-Control-U 36/39 */ + /* Q.2971:Call-Control-N 20/39 */ + un10_link_release_indication(c); + else + /* Q.2971:Call-Control-U 36/39 */ + /* Q.2971:Call-Control-N 37/39 */ + unx_link_release_indication(c); + break; + + case SIGC_LINK_ESTABLISH_ERROR_indication: + if (c->cstate != CALLST_U10 && c->cstate != CALLST_N10) { + VERBOSE(c->uni, UNI_FAC_ERR, 1, + "link-establish-error.indication in cs=%s", + callstates[c->cstate].name); + break; + } + /* Q.2971:Call-Control-U 19/39 */ + /* Q.2971:Call-Control-N 20/39 */ + un10_link_establish_error_indication(c); + break; + + case SIGC_LINK_ESTABLISH_indication: + switch (c->cstate) { + + case CALLST_U1: case CALLST_N1: + case CALLST_U3: case CALLST_N3: + case CALLST_U4: case CALLST_N4: + case CALLST_U6: case CALLST_N6: + case CALLST_U7: case CALLST_N7: + case CALLST_U8: case CALLST_N8: + case CALLST_U9: case CALLST_N9: + /* Q.2971:Call-Control-U 36/39 */ + /* Q.2971:Call-Control-N 37/39 */ + unx_link_establish_indication(c); + break; + + case CALLST_U10: case CALLST_N10: + /* Q.2971:Call-Control-U 19/39 */ + /* Q.2971:Call-Control-N 20/39 */ + un10_link_establish_indication(c); + break; + + case CALLST_U11: case CALLST_N11: + case CALLST_U12: case CALLST_N12: + /* Q.2971:Call-Control-U 36/39 */ + /* Q.2971:Call-Control-N 37/39 */ + break; + + default: + VERBOSE(c->uni, UNI_FAC_ERR, 1, + "link-establish.indication in cs=%s", + callstates[c->cstate].name); + } + break; + + case SIGC_LINK_ESTABLISH_confirm: + if (c->cstate != CALLST_U10 && c->cstate != CALLST_N10) { + VERBOSE(c->uni, UNI_FAC_ERR, 1, + "link-establish.confirm in cs=%s", + callstates[c->cstate].name); + break; + } + /* Q.2971:Call-Control-U 19/39 */ + /* Q.2971:Call-Control-N 20/39 */ + un10_link_establish_confirm(c); + break; + + case SIGC_UNKNOWN: + /* Q.2971:Call-Control 35/39 */ + /* Q.2971:Call-Control 36/39 */ + unx_unknown(c, msg, u); + break; + + case SIGC_SETUP: + if (c->cstate != CALLST_NULL) { + (void)uni_decode_body(msg, u, &c->uni->cx); + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.setup.epref, -1); + goto drop; + } + if (c->uni->proto == UNIPROTO_UNI40N) + /* Q.2971:Call-Control-N 4/39 */ + un0_setup(c, msg, u, CALLST_N1); + else + /* Q.2971:Call-Control-U 4/39 */ + un0_setup(c, msg, u, CALLST_U6); + break; + + case SIGC_CALL_PROC: + if (c->cstate == CALLST_U1) { + /* Q.2971:Call-Control-U 6/39 */ + u1n6_call_proc(c, msg, u, CALLST_U3); + break; + } + if (c->cstate == CALLST_N6) { + /* Q.2971:Call-Control-N 11/39 */ + u1n6_call_proc(c, msg, u, CALLST_N9); + break; + } + (void)uni_decode_body(msg, u, &c->uni->cx); + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.call_proc.epref, -1); + goto drop; + + case SIGC_ALERTING: + if (c->cstate == CALLST_U1 || c->cstate == CALLST_U3) { + /* Q.2971:Call-Control-U 37/39 (U1) */ + /* Q.2971:Call-Control-U 7/39 (U3) */ + unx_alerting(c, msg, u, CALLST_U4); + break; + } + if (c->cstate == CALLST_N6) { + /* Q.2971:Call-Control-N 9/39 (N6) */ + /* Q.2971:Call-Control-N 17/39 (N9) */ + unx_alerting(c, msg, u, CALLST_N7); + break; + } + (void)uni_decode_body(msg, u, &c->uni->cx); + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.alerting.epref, -1); + goto drop; + + case SIGC_CONNECT: + if (c->cstate == CALLST_U1 || c->cstate == CALLST_U3 || + c->cstate == CALLST_U4) { + /* Q.2971:Call-Control-U 7-8/39 (U3) */ + /* Q.2971:Call-Control-U 11/39 (U4) */ + /* Q.2971:Call-Control-U 37/39 (U1) */ + unx_connect(c, msg, u, CALLST_U10); + break; + } + if (c->cstate == CALLST_N6 || c->cstate == CALLST_N7 || + c->cstate == CALLST_N9) { + /* Q.2971:Call-Control-N 9-10/39 (N6) */ + /* Q.2971:Call-Control-N 14/39 (N7) */ + /* Q.2971:Call-Control-N 17/39 (N9) */ + unx_connect(c, msg, u, CALLST_N8); + break; + } + (void)uni_decode_body(msg, u, &c->uni->cx); + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.connect.epref, -1); + goto drop; + + case SIGC_CONNECT_ACK: + if (c->cstate == CALLST_U8) { + /* Q.2971:Call-Control-U 15-16/39 */ + u8_connect_ack(c, msg, u, CALLST_U10); + break; + } + if (c->cstate == CALLST_N10) { + /* Q.2971:Call-Control-N 18/39 */ + n10_connect_ack(c, msg, u); + break; + } + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, NULL, 0); + goto drop; + + case SIGC_RELEASE: + switch (c->cstate) { + + default: + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, NULL, 0); + goto drop; + + case CALLST_U11: + case CALLST_N12: + /* Q.2971:Call-Control-U 28/39 */ + /* Q.2971:Call-Control-N 30/39 */ + u11n12_release(c, msg, u); + break; + + case CALLST_U1: + case CALLST_U3: + case CALLST_U4: + case CALLST_U6: + case CALLST_U7: + case CALLST_U8: + case CALLST_U9: + case CALLST_U10: + case CALLST_U12: + /* Q.2971:Call-Control-U 25/39 */ + unx_release(c, msg, u, CALLST_U12); + break; + + case CALLST_N1: + case CALLST_N3: + case CALLST_N4: + case CALLST_N6: + case CALLST_N7: + case CALLST_N8: + case CALLST_N9: + case CALLST_N10: + case CALLST_N11: + /* Q.2971:Call-Control-N 26/39 */ + unx_release(c, msg, u, CALLST_N11); + break; + } + break; + + case SIGC_RELEASE_COMPL: + /* Q.2971:Call-Control-U 25/39 */ + /* Q.2971:Call-Control-N 26/39 */ + unx_release_compl(c, msg, u); + break; + + case SIGC_NOTIFY: + /* Q.2971:Call-Control-U 18/39 */ + /* Q.2971:Call-Control-N 19/39 */ + unx_notify(c, msg, u); + break; + + case SIGC_STATUS: + if (c->cstate == CALLST_U11 || c->cstate == CALLST_U12 || + c->cstate == CALLST_N11 || c->cstate == CALLST_N12) { + /* Q.2971:Call-Control-U 29/39 (U11) */ + /* Q.2971:Call-Control-U 30/39 (U12) */ + /* Q.2971:Call-Control-N 29/39 (N11) */ + /* Q.2971:Call-Control-N 31/39 (N12) */ + un11un12_status(c, msg, u); + break; + } + /* Q.2971:Call-Control-U 32/39 */ + /* Q.2971:Call-Control-N 33/39 */ + unx_status(c, msg, u); + break; + + case SIGC_STATUS_ENQ: + /* Q.2971:Call-Control-U 31/39 */ + /* Q.2971:Call-Control-N 32/39 */ + unx_status_enq(c, msg, u); + break; + + case SIGC_ADD_PARTY: + (void)uni_decode_body(msg, u, &c->uni->cx); + + if (c->type != CALL_LEAF && c->type != CALL_ROOT) { + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.add_party.epref, UNI_EPSTATE_NULL); + goto drop; + } + switch (c->cstate) { + case CALLST_U7: + case CALLST_U8: + case CALLST_U10: + case CALLST_N4: + case CALLST_N10: + /* Q.2971:Call-Control-U 14/39 U7 */ + /* Q.2971:Call-Control-U 15/39 U8 */ + /* Q.2971:Call-Control-U 21/39 U10 */ + /* Q.2971:Call-Control-N 8/39 N4 */ + /* Q.2971:Call-Control-N 21/39 N10 */ + unx_add_party(c, msg, u, 1); + break; + + default: + unx_add_party(c, msg, u, 0); + goto drop; + } + break; + + case SIGC_PARTY_ALERTING: + (void)uni_decode_body(msg, u, &c->uni->cx); + + if (c->type != CALL_ROOT) { + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.party_alerting.epref, -1); + goto drop; + } + switch (c->cstate) { + + default: + /* Q.2971 9.5.3.2.3a) */ + unx_party_alerting(c, msg, u, 0); + break; + + case CALLST_U4: + case CALLST_U10: + /* Q.2971:Call-Control-U 9/39 U4 */ + /* Q.2971:Call-Control-U 21/39 U10 */ + /* Q.2971:Call-Control-N 12/39 N7 */ + /* Q.2971:Call-Control-N 15/39 N8 */ + /* Q.2971:Call-Control-N 22/39 N10 */ + unx_party_alerting(c, msg, u, 1); + break; + } + break; + + case SIGC_ADD_PARTY_ACK: + (void)uni_decode_body(msg, u, &c->uni->cx); + + if (c->type != CALL_ROOT) { + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.add_party_rej.epref, -1); + goto drop; + } + switch (c->cstate) { + + case CALLST_U10: + /* Q.2971:Call-Control-U 21/39 U10 */ + /* Q.2971:Call-Control-N 15/39 N8 */ + /* Q.2971:Call-Control-N 22/39 N10 */ + un10n8_add_party_ack(c, msg, u, 1); + break; + + default: + /* Q.2971 9.5.3.2.3a) */ + un10n8_add_party_ack(c, msg, u, 0); + break; + } + break; + + case SIGC_ADD_PARTY_REJ: + (void)uni_decode_body(msg, u, &c->uni->cx); + + if (c->type != CALL_ROOT) { + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.add_party_rej.epref, -1); + goto drop; + } + switch (c->cstate) { + + case CALLST_U4: + case CALLST_U10: + case CALLST_N7: + case CALLST_N8: + case CALLST_N10: + /* Q.2971:Call-Control-U 9/39 U4 */ + /* Q.2971:Call-Control-U 21/39 U10 */ + /* Q.2971:Call-Control-N 12/39 N7 */ + /* Q.2971:Call-Control-N 15/39 N8 */ + /* Q.2971:Call-Control-N 22/39 N10 */ + unx_add_party_rej(c, msg, u, 1); + break; + + default: + /* Q.2971: 9.5.3.2.3b */ + unx_add_party_rej(c, msg, u, 0); + break; + } + break; + + case SIGC_DROP_PARTY: + (void)uni_decode_body(msg, u, &c->uni->cx); + + if (c->type != CALL_ROOT && c->type != CALL_LEAF) { + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.drop_party.epref, -1); + goto drop; + } + switch (c->cstate) { + case CALLST_U11: + case CALLST_U12: + case CALLST_N11: + case CALLST_N12: + /* Q.2971:Call-Control-U 28/39 U11 */ + /* Q.2971:Call-Control-U 30/39 U12 */ + /* Q.2971:Call-Control-N 29/39 N11 */ + /* Q.2971:Call-Control-N 30/39 N12 */ + goto drop; + + case CALLST_NULL: + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.drop_party.epref, UNI_EPSTATE_NULL); + goto drop; + + case CALLST_U3: + case CALLST_N3: + /* L3MU_17_38 */ + unx_drop_party(c, msg, u, 0); + break; + + case CALLST_U8: + if (c->uni->sb_tb) { + /* L3MU_06_0[3-6] */ + unx_drop_party(c, msg, u, 0); + break; + } + /* FALLTHRU */ + + default: + /* Q.2971:Call-Control-U 26/39 Ux */ + /* Q.2971:Call-Control-U 21/39 U10 */ + /* Q.2971:Call-Control-N 27/39 Nx */ + /* Q.2971:Call-Control-N 21/39 N10 */ + unx_drop_party(c, msg, u, 1); + break; + } + break; + + case SIGC_DROP_PARTY_ACK: + (void)uni_decode_body(msg, u, &c->uni->cx); + + if (c->type != CALL_ROOT && c->type != CALL_LEAF) { + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.drop_party_ack.epref, -1); + goto drop; + } + switch (c->cstate) { + + case CALLST_U11: + case CALLST_U12: + /* Q.2971:Call-Control-U 28/39 U11 */ + /* Q.2971:Call-Control-U 30/39 U12 */ + /* Q.2971:Call-Control-N 29/39 N11 */ + /* Q.2971:Call-Control-N 30/39 N12 */ + goto drop; + + case CALLST_NULL: + uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, + &u->u.drop_party.epref, UNI_EPSTATE_NULL); + goto drop; + + case CALLST_U4: + case CALLST_N4: + case CALLST_U7: + case CALLST_N7: + case CALLST_U8: + case CALLST_N8: + case CALLST_U10: + case CALLST_N10: + /* Q.2971:Call-Control-U 26/39 Ux */ + /* Q.2971:Call-Control-U 21/39 U10 */ + /* Q.2971:Call-Control-N 27/39 Nx */ + /* Q.2971:Call-Control-N 22/39 N10 */ + unx_drop_party_ack(c, msg, u, 1); + break; + + default: + /* Q.2971 10.5 4th paragraph */ + unx_drop_party_ack(c, msg, u, 0); + break; + } + break; + + case SIGC_COBISETUP: /* XXX */ + unx_unknown(c, msg, u); + break; + + /* + * User signals + */ + case SIGC_SETUP_request: + if (c->cstate == CALLST_NULL) { + /* Q.2971:Call-Control-U 4/39 (U0) */ + /* Q.2971:Call-Control-N 4/39 (N0) */ + if (c->uni->proto == UNIPROTO_UNI40N) + un0_setup_request(c, msg, cookie, CALLST_N6); + else + un0_setup_request(c, msg, cookie, CALLST_U1); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup.request in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_SETUP_response: + if (c->cstate == CALLST_U6 || c->cstate == CALLST_U9 || + c->cstate == CALLST_U7) { + /* Q.2971:Call-Control-U 13/39 (U6) */ + /* Q.2971:Call-Control-U 14/39 (U7) */ + /* Q.2971:Call-Control-U 17/39 (U9) */ + unx_setup_response(c, msg, cookie, CALLST_U8); + break; + } + if (c->cstate == CALLST_N1 || c->cstate == CALLST_N3 || + c->cstate == CALLST_N4) { + /* Q.2971:Call-Control-N 39/39 (N1) */ + /* Q.2971:Call-Control-N 7/39 (N3) */ + /* Q.2971:Call-Control-N 8/39 (N4) */ + unx_setup_response(c, msg, cookie, CALLST_N10); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup.response in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_SETUP_COMPLETE_request: + if (c->cstate == CALLST_N8) { + /* Q.2971:Call-Control-N 15/39 (N8) */ + n8_setup_compl_request(c, msg, cookie, CALLST_N10); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup_compl.request in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_PROCEEDING_request: + if (c->cstate == CALLST_U6) { + /* Q.2971:Call-Control-U 12/39 (U6) */ + u6n1_proceeding_request(c, msg, cookie, CALLST_U9); + break; + } + if (c->cstate == CALLST_N1) { + /* Q.2971:Call-Control-N 6/39 (N1) */ + u6n1_proceeding_request(c, msg, cookie, CALLST_N3); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "proceeding.request in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_ALERTING_request: + if (c->cstate == CALLST_U6 || c->cstate == CALLST_U9) { + /* Q.2971:Call-Control-U 13/39 (U6) */ + /* Q.2971:Call-Control-U 17/39 (U9) */ + unx_alerting_request(c, msg, cookie, CALLST_U7); + break; + } + if (c->cstate == CALLST_N1 || c->cstate == CALLST_N3) { + /* Q.2971:Call-Control-N 38/39 (N1) */ + /* Q.2971:Call-Control-N 7/39 (N3) */ + unx_alerting_request(c, msg, cookie, CALLST_N4); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "alerting.request in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_RELEASE_request: + switch (c->cstate) { + + case CALLST_U1: + case CALLST_U3: + case CALLST_U4: + case CALLST_U6: + case CALLST_U7: + case CALLST_U8: + case CALLST_U9: + case CALLST_U10: + /* Q.2971:Call-Control-U 27/39 */ + unx_release_request(c, msg, cookie, CALLST_U11); + break; + + case CALLST_N1: + case CALLST_N3: + case CALLST_N4: + case CALLST_N6: + case CALLST_N7: + case CALLST_N8: + case CALLST_N9: + case CALLST_N10: + /* Q.2971:Call-Control-N 28/39 */ + unx_release_request(c, msg, cookie, CALLST_N12); + break; + + case CALLST_U11: + case CALLST_U12: + case CALLST_N11: + case CALLST_N12: + case CALLST_NULL: + VERBOSE(c->uni, UNI_FAC_ERR, 1, + "release.request in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, + cookie); + uni_msg_destroy(msg); + break; + } + break; + + case SIGC_RELEASE_response: + if (c->cstate == CALLST_U6 || c->cstate == CALLST_U12 || + c->cstate == CALLST_N1 || c->cstate == CALLST_N11) { + /* Q.2971:Call-Control-U 12/39 (U6) */ + /* Q.2971:Call-Control-U 30/39 (U12) */ + /* Q.2971:Call-Control-N 6/39 (N1) */ + /* Q.2971:Call-Control-N 29/39 (N11) */ + unx_release_response(c, msg, cookie); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "release.response in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_NOTIFY_request: + /* Q.2971:Call-Control-U 18/39 */ + /* Q.2971:Call-Control-N 19/39 */ + unx_notify_request(c, msg, cookie); + break; + + case SIGC_STATUS_ENQUIRY_request: + /* Q.2971:Call-Control-U 31/39 */ + /* Q.2971:Call-Control-N 32/39 */ + unx_status_enquiry_request(c, msg, cookie); + break; + + case SIGC_ADD_PARTY_request: + if (c->cstate == CALLST_U4 || c->cstate == CALLST_U10 || + c->cstate == CALLST_N7 || c->cstate == CALLST_N10) { + /* Q.2971:Call-Control-U 9-10/39 (U4) */ + /* Q.2971:Call-Control-U 21/39 (U10) */ + /* Q.2971:Call-Control-N 12/39 (N7) */ + /* Q.2971:Call-Control-N 22/39 (N10) */ + unx_add_party_request(c, msg, cookie); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "add-party.request in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_PARTY_ALERTING_request: + if (c->cstate == CALLST_U7 || c->cstate == CALLST_U8 || + c->cstate == CALLST_U10 || + c->cstate == CALLST_N4 || c->cstate == CALLST_N10) { + /* Q.2971:Call-Control-U 14/39 U7 */ + /* Q.2971:Call-Control-U 15/39 U8 */ + /* Q.2971:Call-Control-U 21/39 U10 */ + /* Q.2971:Call-Control-N 8/39 N4 */ + /* Q.2971:Call-Control-N 22/39 N10 */ + unx_party_alerting_request(c, msg, cookie); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, + "party-alerting.request in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_ADD_PARTY_ACK_request: + if (c->cstate == CALLST_U10 || c->cstate == CALLST_N10) { + /* Q.2971:Call-Control-U 21/39 (U10) */ + /* Q.2971:Call-Control-N 22/39 (N10)*/ + un10_add_party_ack_request(c, msg, cookie); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, + "add-party-ack.request in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_ADD_PARTY_REJ_request: + if (c->cstate == CALLST_U7 || c->cstate == CALLST_U8 || + c->cstate == CALLST_U10 || + c->cstate == CALLST_N4 || c->cstate == CALLST_N10) { + /* Q.2971:Call-Control-U 14/39 U7 */ + /* Q.2971:Call-Control-U 15/39 U8 */ + /* Q.2971:Call-Control-U 21/39 U10 */ + /* Q.2971:Call-Control-N 8/39 N4 */ + /* Q.2971:Call-Control-N 22/39 N10 */ + unx_add_party_rej_request(c, msg, cookie); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, + "add-party-rej.request in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_DROP_PARTY_request: + if (c->cstate != CALLST_U11 && c->cstate != CALLST_U12 && + c->cstate != CALLST_N11 && c->cstate != CALLST_N12 && + c->cstate != CALLST_NULL) { + /* Q.2971:Call-Control-U 21/39 U10 */ + /* Q.2971:Call-Control-U 26/39 U1-U9 */ + /* Q.2971:Call-Control-N 22/39 N10 */ + /* Q.2971:Call-Control-N 27/39 N1-N9 */ + unx_drop_party_request(c, msg, cookie); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "drop-party.request in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_DROP_PARTY_ACK_request: + if (c->cstate != CALLST_U11 && c->cstate != CALLST_U12 && + c->cstate != CALLST_N11 && c->cstate != CALLST_N12 && + c->cstate != CALLST_NULL) { + /* Q.2971:Call-Control-U 21/39 U10 */ + /* Q.2971:Call-Control-U 26/39 U1-U9 */ + /* Q.2971:Call-Control-N 22/39 N10 */ + /* Q.2971:Call-Control-N 27/39 N1-N9 */ + unx_drop_party_ack_request(c, msg, cookie); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, + "drop-party-ack.request in cs=%s", + callstates[c->cstate].name); + uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGC_ABORT_CALL_request: + { + struct uni *uni = c->uni; + + uni_destroy_call(c, 0); + uniapi_uni_error(uni, UNIAPI_OK, cookie, UNI_CALLSTATE_U0); + break; + } + + /* + * Timers + */ + case SIGC_T301: + if (c->cstate == CALLST_U4 || c->cstate == CALLST_N7) { + /* Q.2971:Call-Control-U Missing */ + /* Q.2971:Call-Control-N 14/39 */ + u4n7_t301(c); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "T301 in cs=%s", + callstates[c->cstate].name); + break; + + case SIGC_T303: + if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6) { + /* Q.2971:Call-Control-U 6/39 */ + /* Q.2971:Call-Control-N 11/39 */ + u1n6_t303(c); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "T303 in cs=%s", + callstates[c->cstate].name); + break; + + case SIGC_T308: + if (c->cstate == CALLST_U11 || c->cstate == CALLST_N12) { + /* Q.2971:Call-Control-U 28/39 */ + /* Q.2971:Call-Control-N 30/39 */ + u11n12_t308(c); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "T308 in cs=%s", + callstates[c->cstate].name); + break; + + case SIGC_T310: + if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9) { + /* Q.2971:Call-Control-U 7/39 */ + /* Q.2971:Call-Control-N 17/39 */ + u3n9_t310(c); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "T310 in cs=%s", + callstates[c->cstate].name); + break; + + case SIGC_T313: + if (c->cstate == CALLST_U8) { + /* Q.2971:Call-Control-U 15/39 */ + u8_t313(c); + break; + } + VERBOSE(c->uni, UNI_FAC_ERR, 1, "T313 in cs=%s", + callstates[c->cstate].name); + break; + + case SIGC_T322: + /* Q.2971:Call-Control-U 34/39 */ + /* Q.2971:Call-Control-N 35/39 */ + unx_t322(c); + break; + + case SIGC_CALL_DELETE: + CALL_FREE(c); + break; + + /* + * Party-Control + */ + case SIGC_DROP_PARTY_indication: + if (c->uni->proto == UNIPROTO_UNI40U) + /* Q.2971:Call-Control-U 23/39 */ + ux_drop_party_indication(c, msg); + else + /* Q.2971:Call-Control-N 23/39 */ + nx_drop_party_indication(c, msg); + break; + + case SIGC_DROP_PARTY_ACK_indication: + if (c->uni->proto == UNIPROTO_UNI40U) + /* Q.2971:Call-Control-U 23/39 */ + ux_drop_party_ack_indication(c, msg); + else + /* Q.2971:Call-Control-N 23/39 */ + nx_drop_party_ack_indication(c, msg); + break; + + case SIGC_ADD_PARTY_REJ_indication: + if (c->uni->proto == UNIPROTO_UNI40U) + /* Q.2971:Call-Control-U 23/39 */ + ux_add_party_rej_indication(c, msg); + else + /* Q.2971:Call-Control-N 23/39 */ + nx_add_party_rej_indication(c, msg); + break; + + + case SIGC_SEND_DROP_PARTY: + /* Q.2971:Call-Control-U 21/39 */ + /* Q.2971:Call-Control-U 25/39 */ + if (uni_party_act_count(c, 2) != 0) + (void)uni_send_output(u, c->uni); + else if(c->cstate != CALLST_U11) { + c->uni->cause = u->u.drop_party.cause; + clear_callD(c); + } + UNI_FREE(u); + break; + + case SIGC_SEND_DROP_PARTY_ACK: + /* Q.2971:Call-Control-U 21/39 */ + /* Q.2971:Call-Control-U 25/39 */ + if (uni_party_act_count(c, 2) != 0) + (void)uni_send_output(u, c->uni); + else if (c->cstate != CALLST_U11) { + c->uni->cause = u->u.drop_party_ack.cause; + clear_callD(c); + } + UNI_FREE(u); + break; + + case SIGC_SEND_ADD_PARTY_REJ: + /* Q.2971:Call-Control-U 21/39 */ + /* Q.2971:Call-Control-U 24/39 */ + unx_send_add_party_rej(c, u); + break; + + case SIGC_SEND_STATUS_ENQ: + /* Q.2971:Call-Control-U 21/39 */ + /* Q.2971:Call-Control-U 25/39 */ + unx_send_party_status_enq(c, u); + break; + + case SIGC_PARTY_DESTROYED: + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_PARTY_DESTROYED, cookie, msg); + break; + + case SIGC_END: + break; + } + + return; + + drop: + /* + * This is for SAAL message signals that should be dropped. + */ + uni_msg_destroy(msg); + UNI_FREE(u); +} + +/**********************************************************************/ + +/* + * Timeout functions + */ +static void +t308_func(struct call *c) +{ + uni_enq_call(c, SIGC_T308, 0, NULL, NULL); +} +static void +t303_func(struct call *c) +{ + uni_enq_call(c, SIGC_T303, 0, NULL, NULL); +} +static void +t301_func(struct call *c) +{ + uni_enq_call(c, SIGC_T301, 0, NULL, NULL); +} +static void +t310_func(struct call *c) +{ + uni_enq_call(c, SIGC_T310, 0, NULL, NULL); +} +static void +t313_func(struct call *c) +{ + uni_enq_call(c, SIGC_T313, 0, NULL, NULL); +} + +static void +t322_func(struct call *c) +{ + uni_enq_call(c, SIGC_T322, 0, NULL, NULL); +} + +/**********************************************************************/ + +/* + * Check whether the peer state is compatible with our state. + * Return the new callstate we should go to (either U0 or the current + * state). + * None of the state is U0 here. My state is not U11 or U12. + * + * Well, this turns out to be not so easy: the status enquiry could have + * been sent before we changed into the current state - the status will + * report a previous state without anything been lost. + * + * Incoming states are incompatible with outgoing states. Everything is ok. + */ +static enum call_state +state_compat(struct call *c, enum uni_callstate peer) +{ + if ((c->cstate == CALLST_U1 || + c->cstate == CALLST_U3 || + c->cstate == CALLST_U4) && + (peer == UNI_CALLSTATE_N6 || + peer == UNI_CALLSTATE_N7 || + peer == UNI_CALLSTATE_N8 || + peer == UNI_CALLSTATE_N9)) + return (CALLST_NULL); + + if ((c->cstate == CALLST_N6 || + c->cstate == CALLST_N7 || + c->cstate == CALLST_N8 || + c->cstate == CALLST_N9) && + (peer == UNI_CALLSTATE_U1 || + peer == UNI_CALLSTATE_U3 || + peer == UNI_CALLSTATE_U4)) + return (CALLST_NULL); + + if ((peer == UNI_CALLSTATE_N1 || + peer == UNI_CALLSTATE_N3 || + peer == UNI_CALLSTATE_N4) && + (c->cstate == CALLST_U6 || + c->cstate == CALLST_U7 || + c->cstate == CALLST_U8 || + c->cstate == CALLST_N9)) + return (CALLST_NULL); + + if ((peer == UNI_CALLSTATE_U6 || + peer == UNI_CALLSTATE_U7 || + peer == UNI_CALLSTATE_U8 || + peer == UNI_CALLSTATE_U9) && + (c->cstate == CALLST_N1 || + c->cstate == CALLST_N3 || + c->cstate == CALLST_N4)) + return (CALLST_NULL); + + return (c->cstate); +} diff --git a/sys/contrib/ngatm/netnatm/sig/sig_coord.c b/sys/contrib/ngatm/netnatm/sig/sig_coord.c new file mode 100644 index 000000000000..6a688302f053 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/sig_coord.c @@ -0,0 +1,1171 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/sig/sig_coord.c,v 1.12 2004/08/05 07:11:01 brandt Exp $ + * + * Coordinator + */ + +#include <netnatm/unimsg.h> +#include <netnatm/saal/sscfudef.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#include <netnatm/sig/uni.h> + +#include <netnatm/sig/unipriv.h> +#include <netnatm/sig/unimkmsg.h> + +#define STR(S) [S] = #S +static const char *const cunames[] = { + STR(CU_STAT0), + STR(CU_STAT1), + STR(CU_STAT2), + STR(CU_STAT3), +}; + +#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME, +static const char *const coord_sigs[] = { + DEF_COORD_SIGS +}; +#undef DEF_PRIV_SIG + +static void sig_all_calls(struct uni *, u_int sig); +static void set_custat(struct uni *, enum cu_stat); + +static void input_dummy(struct uni *uni, struct uni_msg *m, struct uni_all *u); +static void input_global(struct uni *uni, struct uni_msg *m, struct uni_all *u); +static void input_unknown(struct uni *uni, struct uni_msg *m, struct uni_all *u); +static void input_cobi(struct call *c, struct uni_msg *m, struct uni_all *u); +static void input_call(struct call *c, struct uni_msg *m, struct uni_all *u); + +TIMER_FUNC_UNI(t309, t309_func) + +/* + * All those 'bogus signal' printouts are not specified in the SDLs. + */ + + +/* + * SAAL-ESTABLISH.indication + * + * This means either a resynchronisation or error-recovery or + * an incoming SSCOP connection. + */ +static void +coord_saal_establish_indication(struct uni *uni) +{ + switch (uni->custat) { + + case CU_STAT0: /* Q.2931:Coord-U 4/10 */ + case CU_STAT3: /* Q.2931:Coord-U 5/10 */ + sig_all_calls(uni, SIGC_LINK_ESTABLISH_indication); + set_custat(uni, CU_STAT3); + break; + + case CU_STAT1: + case CU_STAT2: + VERBOSE0(uni, UNI_FAC_COORD, + "signal saal_establish.indication in CU%u", uni->custat); + break; + + default: + ASSERT(0, ("CU_STAT*")); + } +} + +/* + * SAAL-ESTABLISH.confirm + */ +static void +coord_saal_establish_confirm(struct uni *uni) +{ + switch (uni->custat) { + + case CU_STAT0: + case CU_STAT2: + VERBOSE0(uni, UNI_FAC_COORD, + "signal saal_establish.confirm in CU%u", uni->custat); + break; + + case CU_STAT1: + /* + * Q.2931:Co-ord-U 4/10 + */ + TIMER_STOP_UNI(uni, t309); + sig_all_calls(uni, SIGC_LINK_ESTABLISH_confirm); + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_LINK_ESTABLISH_confirm, 0, NULL); + set_custat(uni, CU_STAT3); + break; + + case CU_STAT3: + /* + * Q.2931:Coord-U 5/10 + */ + sig_all_calls(uni, SIGC_LINK_ESTABLISH_confirm); + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_LINK_ESTABLISH_confirm, 0, NULL); + break; + + default: + ASSERT(0, ("CU_STAT*")); + } +} + +/* + * SAAL-RELEASE.confirm + */ +static void +coord_saal_release_confirm(struct uni *uni) +{ + switch (uni->custat) { + + case CU_STAT0: + case CU_STAT1: + case CU_STAT3: + VERBOSE0(uni, UNI_FAC_COORD, + "signal saal_release.confirm in CU%u", uni->custat); + break; + + case CU_STAT2: + /* + * Q.2931:Coord-U 5/10 + */ + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_LINK_RELEASE_confirm, 0, NULL); + set_custat(uni, CU_STAT0); + break; + + default: + ASSERT(0, ("CU_STAT*")); + } +} + +/* + * SAAL failure. + */ +static void +coord_saal_release_indication(struct uni *uni) +{ + switch (uni->custat) { + + case CU_STAT0: + case CU_STAT2: + VERBOSE0(uni, UNI_FAC_COORD, + "signal saal_release.indication in CU%u", uni->custat); + break; + + case CU_STAT1: + case CU_STAT3: + /* + * Q.2931:Coord-U 4/10 + * Q.2931:Coord-U 5/10 + */ + sig_all_calls(uni, SIGC_LINK_RELEASE_indication); + set_custat(uni, CU_STAT0); + break; + + default: + ASSERT(0, ("CU_STAT*")); + } +} + +/* + * Link-establish.request from USER. This can also come from + * a call instance. In this case 'cookie' is zero. + */ +static void +coord_link_establish_request(struct uni *uni, uint32_t cookie) +{ + switch (uni->custat) { + + case CU_STAT0: + /* + * Q.2931:Coord-U 4/10 + */ + uni->funcs->saal_output(uni, uni->arg, + SAAL_ESTABLISH_request, NULL); + if (!TIMER_ISACT(uni, t309)) + TIMER_START_UNI(uni, t309, uni->timer309); + set_custat(uni, CU_STAT1); + if (cookie) + uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); + break; + + case CU_STAT1: + /* + * Q.2931:Coord-U 4/10 + * This is probably missing from the delay field. + */ + uni_delenq_coord(uni, SIGO_LINK_ESTABLISH_request, + cookie, NULL); + break; + + case CU_STAT2: + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); + if (cookie == 0) + VERBOSE0(uni, UNI_FAC_COORD, + "signal link-establish.request in CU%u", + uni->custat); + break; + + case CU_STAT3: + /* + * Q.2931:Coord-U 5/10 + */ + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_LINK_ESTABLISH_confirm, 0, NULL); + uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); + break; + + default: + ASSERT(0, ("CU_STAT*")); + } +} + +/* + * Link-release.request from user + */ +static void +coord_link_release_request(struct uni *uni, u_int cookie) +{ + switch (uni->custat) { + + case CU_STAT0: + case CU_STAT1: + case CU_STAT2: + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); + break; + + case CU_STAT3: + /* + * Q.2931:Coord-U 5/10 + */ + uni->funcs->saal_output(uni, uni->arg, + SAAL_RELEASE_request, NULL); + set_custat(uni, CU_STAT2); + uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); + break; + + default: + ASSERT(0, ("CU_STAT*")); + } +} + +/* + * T309 timeout signal + */ +static void +coord_t309(struct uni *uni) +{ + switch (uni->custat) { + + case CU_STAT0: + case CU_STAT1: + /* + * Q.2931:Coord-U 4/10 + */ + sig_all_calls(uni, SIGC_LINK_ESTABLISH_ERROR_indication); + set_custat(uni, CU_STAT0); + /* this is not in the SDLs, but how will the call control + * know, that starting the LINK has failed otherwise? */ + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_LINK_RELEASE_confirm, 0, NULL); + break; + + case CU_STAT2: + case CU_STAT3: + VERBOSE0(uni, UNI_FAC_COORD, + "signal T309 in CU%u", uni->custat); + break; + + default: + ASSERT(0, ("CU_STAT*")); + } +} + +/* + * Message from SAAL + */ +static void +coord_saal_data_indication(struct uni *uni, struct uni_msg *m) +{ + struct uni_all *u; + struct call *c; + + memset(&uni->cause, 0, sizeof(uni->cause)); + if ((u = UNI_ALLOC()) == NULL) { + uni_msg_destroy(m); + return; + } + if (uni_decode_head(m, u, &uni->cx)) { + VERBOSE(uni, UNI_FAC_COORD, 2, "bogus message - ignored"); + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + if (u->u.hdr.cref.cref == CREF_DUMMY) { + if (uni->cx.q2932) { + input_dummy(uni, m, u); + } else { + VERBOSE(uni, UNI_FAC_COORD, 2, "dummy cref - ignored"); + UNI_FREE(u); + uni_msg_destroy(m); + } + return; + } + + if (u->u.hdr.cref.cref == CREF_GLOBAL) + input_global(uni, m, u); + else if ((c = uni_find_call(uni, &u->u.hdr.cref)) == NULL) + input_unknown(uni, m, u); + else if (c->type == CALL_COBI) + input_cobi(c, m, u); + else + input_call(c, m, u); +} + +/* + * Message with global call reference + * + * Q.2931:Coord-U (X) 7/10 + */ +static void +input_global(struct uni *uni, struct uni_msg *m, struct uni_all *u) +{ + VERBOSE(uni, UNI_FAC_COORD, 2, "GLOB MTYPE = %x", u->mtype); + + switch (u->mtype) { + + default: + /* + * Q.2931:Coord-U 7/10 + * Q.2931: 5.6.3.2e + * Amd4: 29e + */ + uni_respond_status(uni, &u->u.hdr.cref, + u->u.hdr.cref.flag ? uni->glob_start : uni->glob_respond, + UNI_CAUSE_CREF_INV); + break; + + case UNI_RESTART: + if (u->u.hdr.cref.flag) { + /* + * Q.2931:Coord-U 7/10 (5.6.3.2h) + */ + uni_respond_status(uni, &u->u.hdr.cref, + uni->glob_start, UNI_CAUSE_CREF_INV); + break; + } + uni_enq_resp(uni, SIGR_RESTART, 0, m, u); + return; + + case UNI_RESTART_ACK: + if (!u->u.hdr.cref.flag) { + /* + * Q.2931:Coord-U 7/10 (5.6.3.2h) + * Note, that the SDL diagram contains an error. + * The error with the 'YES' label should go to the + * box below 'OTHER'. + */ + uni_respond_status(uni, &u->u.hdr.cref, + uni->glob_respond, UNI_CAUSE_CREF_INV); + break; + } + uni_enq_start(uni, SIGS_RESTART_ACK, 0, m, u); + return; + + case UNI_STATUS: + if (u->u.hdr.cref.flag) + uni_enq_start(uni, SIGS_STATUS, 0, m, u); + else + uni_enq_resp(uni, SIGR_STATUS, 0, m, u); + return; + } + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * Q.2931:Coord-U 8/10 + * + * Message for an unknown call reference + */ +static void +input_unknown(struct uni *uni, struct uni_msg *m, struct uni_all *u) +{ + struct uni_all *resp; + struct call *c; + u_int cause = UNI_CAUSE_CREF_INV; + + VERBOSE(uni, UNI_FAC_COORD, 2, "UNKNOWN MTYPE = %x", u->mtype); + + switch (u->mtype) { + + default: + /* + * This message type is entirly unknown + * + * 5.6.4 and 5.7.1 are only when the call is not in the + * NULL state. This means, 5.6.3.2a takes over. + */ + break; + + case UNI_SETUP: + if (u->u.hdr.cref.flag) + /* + * 5.6.3.2c + */ + goto drop; + if ((c = uni_create_call(uni, u->u.hdr.cref.cref, 0, 0)) != NULL) { + uni_enq_call(c, SIGC_SETUP, 0, m, u); + return; + } + goto drop; + + case UNI_RELEASE_COMPL: + /* + * 5.6.3.2c + */ + goto drop; + + case UNI_STATUS: + /* + * 5.6.12 + * + * The SDLs don't use the verify procedure and don't + * handle the case of an invalid callstate - we + * ignore the message, if the callstate is not good. + */ + (void)uni_decode_body(m, u, &uni->cx); + if (!IE_ISGOOD(u->u.status.callstate)) + goto drop; + if (u->u.status.callstate.state == UNI_CALLSTATE_U0) + goto drop; + cause = UNI_CAUSE_MSG_INCOMP; + break; + + case UNI_STATUS_ENQ: + if ((resp = UNI_ALLOC()) == NULL) + goto drop; + + (void)uni_decode_body(m, u, &uni->cx); + MK_MSG_RESP(resp, UNI_STATUS, &u->u.hdr.cref); + MK_IE_CALLSTATE(resp->u.status.callstate, UNI_CALLSTATE_U0); + MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_STATUS); + + if (IE_ISGOOD(u->u.status_enq.epref)) { + /* reflect epref as required by L3MU_PO */ + resp->u.status.epref = u->u.status_enq.epref; + MK_IE_EPREF(resp->u.status.epref, + u->u.status_enq.epref.epref, + !u->u.status_enq.epref.flag); + MK_IE_EPSTATE(resp->u.status.epstate, UNI_EPSTATE_NULL); + } + + (void)uni_send_output(resp, uni); + + UNI_FREE(resp); + goto drop; + + case UNI_COBISETUP: + if (u->u.hdr.cref.flag) + /* + * 5.6.3.2c (probably) + */ + goto drop; + if ((c = uni_create_call(uni, u->u.hdr.cref.cref, 0, 0)) != NULL) { + uni_enq_call(c, SIGC_COBISETUP, 0, m, u); + return; + } + goto drop; + } + + /* + * 5.6.3.2a) + * + * Respond with a RELEASE COMPLETE + */ + if ((resp = UNI_ALLOC()) == NULL) + goto drop; + + MK_MSG_RESP(resp, UNI_RELEASE_COMPL, &u->u.hdr.cref); + MK_IE_CAUSE(resp->u.release_compl.cause[0], UNI_CAUSE_LOC_USER, cause); + if (uni_diag(cause, UNI_CODING_ITU) == UNI_DIAG_MTYPE) + ADD_CAUSE_MTYPE(resp->u.release_compl.cause[0], u->mtype); + + (void)uni_send_output(resp, uni); + + UNI_FREE(resp); + + drop: + UNI_FREE(u); + uni_msg_destroy(m); +} + +static void +input_cobi(struct call *c __unused, struct uni_msg *m, struct uni_all *u) +{ + /* XXX */ + UNI_FREE(u); + uni_msg_destroy(m); +} + +static void +input_dummy(struct uni *uni __unused, struct uni_msg *m, struct uni_all *u) +{ + /* XXX */ + UNI_FREE(u); + uni_msg_destroy(m); +} + +static void +input_call(struct call *c, struct uni_msg *m, struct uni_all *u) +{ + VERBOSE(c->uni, UNI_FAC_COORD, 2, "CALL MTYPE = %x %d/%s", + u->mtype, c->cref, c->mine ? "mine":"his"); + + switch (u->mtype) { + + case UNI_SETUP: + /* + * Ignored + */ + break; + + case UNI_CALL_PROC: + uni_enq_call(c, SIGC_CALL_PROC, 0, m, u); + return; + + case UNI_ALERTING: + uni_enq_call(c, SIGC_ALERTING, 0, m, u); + return; + + case UNI_RELEASE: + uni_enq_call(c, SIGC_RELEASE, 0, m, u); + return; + + case UNI_RELEASE_COMPL: + uni_enq_call(c, SIGC_RELEASE_COMPL, 0, m, u); + return; + + case UNI_CONNECT: + uni_enq_call(c, SIGC_CONNECT, 0, m, u); + return; + + case UNI_CONNECT_ACK: + uni_enq_call(c, SIGC_CONNECT_ACK, 0, m, u); + return; + + case UNI_NOTIFY: + uni_enq_call(c, SIGC_NOTIFY, 0, m, u); + return; + + case UNI_STATUS: + uni_enq_call(c, SIGC_STATUS, 0, m, u); + return; + + case UNI_STATUS_ENQ: + uni_enq_call(c, SIGC_STATUS_ENQ, 0, m, u); + return; + + case UNI_ADD_PARTY: + uni_enq_call(c, SIGC_ADD_PARTY, 0, m, u); + return; + + case UNI_PARTY_ALERTING: + uni_enq_call(c, SIGC_PARTY_ALERTING, 0, m, u); + return; + + case UNI_ADD_PARTY_ACK: + uni_enq_call(c, SIGC_ADD_PARTY_ACK, 0, m, u); + return; + + case UNI_ADD_PARTY_REJ: + uni_enq_call(c, SIGC_ADD_PARTY_REJ, 0, m, u); + return; + + case UNI_DROP_PARTY: + uni_enq_call(c, SIGC_DROP_PARTY, 0, m, u); + return; + + case UNI_DROP_PARTY_ACK: + uni_enq_call(c, SIGC_DROP_PARTY_ACK, 0, m, u); + return; + + default: + uni_enq_call(c, SIGC_UNKNOWN, 0, m, u); + return; + } + UNI_FREE(u); + uni_msg_destroy(m); +} + + +/* + * This macro tries to implement the delaying behaviour for + * message from the API when we are in the Awaiting-Establish state. + * In this state, the message is delayed. If we drop back to CU 0, + * everything gets unqueued and errors are returned for all that stuff. + * If we progess to CUSTAT2 we process the requests. + */ +#define COMMON_DELAY(SIG, COOKIE) \ + if (uni->custat == CU_STAT0 || uni->custat == CU_STAT2) {\ + uniapi_uni_error(uni, UNIAPI_ERROR_BADCU, \ + COOKIE, 0); \ + break; \ + } \ + if (uni->custat == CU_STAT1) { \ + uni_delenq_coord(uni, SIG, COOKIE, msg); \ + break; \ + } + +/* + * Signal handler of the coordinator + */ +void +uni_sig_coord(struct uni *uni, enum coord_sig sig, uint32_t cookie, + struct uni_msg *msg) +{ + struct call *c; + + if (sig >= SIGO_END) { + VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to " + "Coord", sig); + if (msg) + uni_msg_destroy(msg); + return; + } + + VERBOSE(uni, UNI_FAC_COORD, 1, "Signal %s in state %s", + coord_sigs[sig], cunames[uni->custat]); + + switch (sig) { + + case SIGO_END: + break; + + case SIGO_DATA: /* delayed output */ + if (uni->custat == CU_STAT0 || uni->custat == CU_STAT1) + break; /* drop */ + if (uni->custat == CU_STAT1) + uni_delenq_coord(uni, SIGO_DATA, cookie, msg);/* ??? */ + else + uni->funcs->saal_output(uni, uni->arg, + SAAL_DATA_request, msg); + msg = NULL; + break; + + /* + * SAAL signals + */ + case SIGO_SAAL_ESTABLISH_indication: + coord_saal_establish_indication(uni); + break; + + case SIGO_SAAL_ESTABLISH_confirm: + coord_saal_establish_confirm(uni); + break; + + case SIGO_SAAL_RELEASE_confirm: + coord_saal_release_confirm(uni); + break; + + case SIGO_SAAL_RELEASE_indication: + coord_saal_release_indication(uni); + break; + + case SIGO_SAAL_DATA_indication: + coord_saal_data_indication(uni, msg); + msg = NULL; + break; + + case SIGO_SAAL_UDATA_indication: + VERBOSE0(uni, UNI_FAC_ERR, "SAAL_UDATA_indication"); + break; + + /* + * Signals from USER + */ + case SIGO_LINK_ESTABLISH_request: + coord_link_establish_request(uni, cookie); + break; + + case SIGO_LINK_RELEASE_request: + coord_link_release_request(uni, cookie); + break; + + case SIGO_RESET_request: + uni_enq_start(uni, SIGS_RESET_request, cookie, msg, NULL); + msg = NULL; + if (uni->custat == CU_STAT0) { + uni->funcs->saal_output(uni, uni->arg, + SAAL_ESTABLISH_request, NULL); + if (!TIMER_ISACT(uni, t309)) + TIMER_START_UNI(uni, t309, uni->timer309); + set_custat(uni, CU_STAT1); + } + break; + + case SIGO_RESET_ERROR_response: + COMMON_DELAY(SIGO_RESET_ERROR_response, cookie); + uni_enq_resp(uni, SIGR_RESET_ERROR_response, cookie, msg, NULL); + msg = NULL; + break; + + case SIGO_RESET_response: + COMMON_DELAY(SIGO_RESET_response, cookie); + uni_enq_resp(uni, SIGR_RESET_response, cookie, msg, NULL); + msg = NULL; + break; + + case SIGO_SETUP_request: + if ((c = uni_create_new_call(uni, cookie)) != NULL) { + uni_enq_call(c, SIGC_SETUP_request, cookie, msg, NULL); + msg = NULL; + if (uni->custat == CU_STAT0) { + uni->funcs->saal_output(uni, uni->arg, + SAAL_ESTABLISH_request, NULL); + if (!TIMER_ISACT(uni, t309)) + TIMER_START_UNI(uni, t309, uni->timer309); + set_custat(uni, CU_STAT1); + } + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, + UNI_CALLSTATE_U0); + } + break; + + case SIGO_PROCEEDING_request: + { + struct uniapi_proceeding_request *arg = + uni_msg_rptr(msg, struct uniapi_proceeding_request *); + + COMMON_DELAY(SIGO_PROCEEDING_request, cookie); + if ((c = uni_find_call(uni, &arg->call_proc.hdr.cref)) != NULL) { + uni_enq_call(c, SIGC_PROCEEDING_request, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_ALERTING_request: + { + struct uniapi_alerting_request *arg = + uni_msg_rptr(msg, struct uniapi_alerting_request *); + + COMMON_DELAY(SIGO_ALERTING_request, cookie); + if ((c = uni_find_call(uni, &arg->alerting.hdr.cref)) != NULL) { + uni_enq_call(c, SIGC_ALERTING_request, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_SETUP_response: + { + struct uniapi_setup_response *arg = + uni_msg_rptr(msg, struct uniapi_setup_response *); + + COMMON_DELAY(SIGO_SETUP_response, cookie); + if ((c = uni_find_call(uni, &arg->connect.hdr.cref)) != NULL) { + uni_enq_call(c, SIGC_SETUP_response, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_SETUP_COMPLETE_request: + { + struct uniapi_setup_complete_request *arg = + uni_msg_rptr(msg, struct uniapi_setup_complete_request *); + + COMMON_DELAY(SIGO_SETUP_COMPLETE_request, cookie); + if ((c = uni_find_call(uni, &arg->connect_ack.hdr.cref)) != NULL) { + uni_enq_call(c, SIGC_SETUP_COMPLETE_request, + cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_RELEASE_request: + { + struct uniapi_release_request *arg = + uni_msg_rptr(msg, struct uniapi_release_request *); + + COMMON_DELAY(SIGO_RELEASE_request, cookie); + if ((c = uni_find_call(uni, &arg->release.hdr.cref)) != NULL) { + uni_enq_call(c, SIGC_RELEASE_request, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_RELEASE_response: + { + struct uniapi_release_response *arg = + uni_msg_rptr(msg, struct uniapi_release_response *); + + COMMON_DELAY(SIGO_RELEASE_response, cookie); + if ((c = uni_find_call(uni, &arg->release_compl.hdr.cref)) != NULL) { + uni_enq_call(c, SIGC_RELEASE_response, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_NOTIFY_request: + { + struct uniapi_notify_request *arg = + uni_msg_rptr(msg, struct uniapi_notify_request *); + + COMMON_DELAY(SIGO_NOTIFY_request, cookie); + if ((c = uni_find_call(uni, &arg->notify.hdr.cref)) != NULL) { + uni_enq_call(c, SIGC_NOTIFY_request, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_STATUS_ENQUIRY_request: + { + struct uniapi_status_enquiry_request *arg = + uni_msg_rptr(msg, struct uniapi_status_enquiry_request *); + + COMMON_DELAY(SIGO_STATUS_ENQUIRY_request, cookie); + if ((c = uni_find_call(uni, &arg->cref)) != NULL) { + uni_enq_call(c, SIGC_STATUS_ENQUIRY_request, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_ADD_PARTY_request: + { + struct uniapi_add_party_request *arg = + uni_msg_rptr(msg, struct uniapi_add_party_request *); + + COMMON_DELAY(SIGO_ADD_PARTY_request, cookie); + if ((c = uni_find_call(uni, &arg->add.hdr.cref)) != NULL) { + if (c->type != CALL_ROOT) { + uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE, + cookie); + break; + } + uni_enq_call(c, SIGC_ADD_PARTY_request, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_PARTY_ALERTING_request: + { + struct uniapi_party_alerting_request *arg = + uni_msg_rptr(msg, struct uniapi_party_alerting_request *); + + COMMON_DELAY(SIGO_PARTY_ALERTING_request, cookie); + if ((c = uni_find_call(uni, &arg->alert.hdr.cref)) != NULL) { + if (c->type != CALL_LEAF) { + uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE, + cookie); + break; + } + uni_enq_call(c, SIGC_PARTY_ALERTING_request, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_ADD_PARTY_ACK_request: + { + struct uniapi_add_party_ack_request *arg = + uni_msg_rptr(msg, struct uniapi_add_party_ack_request *); + + COMMON_DELAY(SIGO_ADD_PARTY_ACK_request, cookie); + if ((c = uni_find_call(uni, &arg->ack.hdr.cref)) != NULL) { + if (c->type != CALL_LEAF) { + uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE, + cookie); + break; + } + uni_enq_call(c, SIGC_ADD_PARTY_ACK_request, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_ADD_PARTY_REJ_request: + { + struct uniapi_add_party_rej_request *arg = + uni_msg_rptr(msg, struct uniapi_add_party_rej_request *); + + COMMON_DELAY(SIGO_ADD_PARTY_REJ_request, cookie); + if ((c = uni_find_call(uni, &arg->rej.hdr.cref)) != NULL) { + if (c->type != CALL_LEAF) { + uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE, + cookie); + break; + } + uni_enq_call(c, SIGC_ADD_PARTY_REJ_request, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_DROP_PARTY_request: + { + struct uniapi_drop_party_request *arg = + uni_msg_rptr(msg, struct uniapi_drop_party_request *); + + COMMON_DELAY(SIGO_DROP_PARTY_request, cookie); + if ((c = uni_find_call(uni, &arg->drop.hdr.cref)) != NULL) { + if (c->type != CALL_ROOT && c->type != CALL_LEAF) { + uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE, + cookie); + break; + } + uni_enq_call(c, SIGC_DROP_PARTY_request, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_DROP_PARTY_ACK_request: + { + struct uniapi_drop_party_ack_request *arg = + uni_msg_rptr(msg, struct uniapi_drop_party_ack_request *); + + COMMON_DELAY(SIGO_DROP_PARTY_ACK_request, cookie); + if ((c = uni_find_call(uni, &arg->ack.hdr.cref)) != NULL) { + if (c->type != CALL_ROOT && c->type != CALL_LEAF) { + uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE, + cookie); + break; + } + uni_enq_call(c, SIGC_DROP_PARTY_ACK_request, cookie, msg, NULL); + msg = NULL; + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + case SIGO_ABORT_CALL_request: + { + struct uniapi_abort_call_request *arg = + uni_msg_rptr(msg, struct uniapi_abort_call_request *); + + if ((c = uni_find_call(uni, &arg->cref)) != NULL) { + uni_enq_call(c, SIGC_ABORT_CALL_request, cookie, NULL, NULL); + } else { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie, + UNI_CALLSTATE_U0); + } + break; + } + + /* + * Call-Control + */ + case SIGO_CALL_DESTROYED: + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_CALL_DESTROYED, 0, msg); + msg = NULL; + break; + + /* + * ResetRespond + */ + case SIGO_RESET_indication: + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_indication, 0, msg); + msg = NULL; + break; + + /* + * Timeouts + */ + case SIGO_T309: + coord_t309(uni); + break; + + } + if (msg != NULL) + uni_msg_destroy(msg); +} + +/* + * Send a signal to all call instances + */ +static void +sig_all_calls(struct uni *uni, u_int sig) +{ + struct call *call; + + TAILQ_FOREACH(call, &uni->calls, link) + uni_enq_call(call, sig, 0, NULL, NULL); +} + +/* + * Set a new coordinator state - this moves all delayed coordinator + * signals from the delayed queue to the signal queue. + */ +static int +cufilt(struct sig *s, void *arg __unused) +{ + return (s->type == SIG_COORD); +} + +static void +set_custat(struct uni *uni, enum cu_stat nstate) +{ + if (uni->custat != nstate) { + uni->custat = nstate; + uni_undel(uni, cufilt, NULL); + } +} + +/* + * T309 timeout function + */ +static void +t309_func(struct uni *uni) +{ + uni_enq_coord(uni, SIGO_T309, 0, NULL); +} + +/* + * Respond with a status message + */ +void +uni_respond_status(struct uni *uni, struct uni_cref *cref, + enum uni_callstate cs, enum uni_cause c1) +{ + struct uni_all *resp; + + if ((resp = UNI_ALLOC()) == NULL) + return; + + MK_MSG_RESP(resp, UNI_STATUS, cref); + MK_IE_CALLSTATE(resp->u.status.callstate, cs); + MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, c1); + + (void)uni_send_output(resp, uni); + + UNI_FREE(resp); +} + +/* + * Respond with a status message + */ +void +uni_respond_status_mtype(struct uni *uni, struct uni_cref *cref, + enum uni_callstate cs, enum uni_cause c1, u_int mtype) +{ + struct uni_all *resp; + + if((resp = UNI_ALLOC()) == NULL) + return; + + MK_MSG_RESP(resp, UNI_STATUS, cref); + MK_IE_CALLSTATE(resp->u.status.callstate, cs); + MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, c1); + ADD_CAUSE_MTYPE(resp->u.status.cause, mtype); + + (void)uni_send_output(resp, uni); + + UNI_FREE(resp); +} + +/* + * Send a message. If we are in CUSTAT1, delay the message if we + * are in CUSTAT3 send it, else drop it. + */ +int +uni_send_output(struct uni_all *u, struct uni *uni) +{ + struct uni_msg *m; + int err; + + if (uni->custat == CU_STAT0 || uni->custat == CU_STAT2) + return (0); + + m = uni_msg_alloc(1024); + if ((err = uni_encode(m, u, &uni->cx)) != 0) { + VERBOSE0(uni, UNI_FAC_ERR, "uni_encode failed: %08x", err); + uni_msg_destroy(m); + return (-1); + } + if (uni->custat == CU_STAT1) + uni_delenq_coord(uni, SIGO_DATA, 0, m); + else + uni->funcs->saal_output(uni, uni->arg, SAAL_DATA_request, m); + return (0); +} diff --git a/sys/contrib/ngatm/netnatm/sig/sig_party.c b/sys/contrib/ngatm/netnatm/sig/sig_party.c new file mode 100644 index 000000000000..f9d5cd0cf571 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/sig_party.c @@ -0,0 +1,1353 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/sig/sig_party.c,v 1.18 2004/08/05 07:11:01 brandt Exp $ + * + * Party instance handling + */ + +#include <netnatm/unimsg.h> +#include <netnatm/saal/sscfudef.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#include <netnatm/sig/uni.h> + +#include <netnatm/sig/unipriv.h> +#include <netnatm/sig/unimkmsg.h> +#include <netnatm/sig/unimsgcpy.h> + +static void drop_partyE(struct party *p); +static int epstate_compat(struct party *, enum uni_epstate); + +#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME, +static const char *const party_sigs[] = { + DEF_PARTY_SIGS +}; +#undef DEF_PRIV_SIG + +TIMER_FUNC_PARTY(t397, t397_func) +TIMER_FUNC_PARTY(t398, t398_func) +TIMER_FUNC_PARTY(t399, t399_func) + +static __inline void +set_party_state(struct party *p, enum uni_epstate state) +{ + if (p->state != state) { + VERBOSE(p->call->uni, UNI_FAC_CALL, 1, + "party %u/%u %u/%u PU%u -> PU%u", + p->call->cref, p->call->mine, + p->epref, p->flags & PARTY_MINE, p->state, state); + p->state = state; + } +} + +/* + * Create a party with a given endpoint reference. + * No check is done, that a party with this epref does not alreay exist. + */ +struct party * +uni_create_partyx(struct call *c, u_int epref, u_int mine, uint32_t cookie) +{ + struct party *p; + struct uni_msg *api; + struct uniapi_party_created *ind; + + mine = (mine ? PARTY_MINE : 0); + + if ((p = PARTY_ALLOC()) == NULL) + return (NULL); + + if ((ind = ALLOC_API(struct uniapi_party_created, api)) == NULL) { + PARTY_FREE(p); + return (NULL); + } + + ind->cref.cref = c->cref; + ind->cref.flag = c->mine; + MK_IE_EPREF(ind->epref, epref, mine); + ind->epref.h.act = UNI_IEACT_DEFAULT; + + p->call = c; + p->epref = epref; + p->flags = mine; + p->state = UNI_EPSTATE_NULL;; + + TIMER_INIT_PARTY(p, t397); + TIMER_INIT_PARTY(p, t398); + TIMER_INIT_PARTY(p, t399); + + TAILQ_INSERT_HEAD(&c->parties, p, link); + + c->uni->funcs->uni_output(c->uni, c->uni->arg, + UNIAPI_PARTY_CREATED, cookie, api); + + VERBOSE(c->uni, UNI_FAC_CALL, 1, "created party %u/%s %u/%s", + p->call->cref, p->call->mine ? "mine" : "his", + p->epref, (p->flags & PARTY_MINE) ? "mine" : "his"); + + return (p); + +} + +struct party * +uni_create_party(struct call *c, struct uni_ie_epref *epref) +{ + return (uni_create_partyx(c, epref->epref, epref->flag, 0)); +} + +struct party * +uni_find_party(struct call *c, struct uni_ie_epref *epref) +{ + struct party *p; + + TAILQ_FOREACH(p, &c->parties, link) + if (p->epref == epref->epref && + (!(p->flags & PARTY_MINE) == !epref->flag)) + return (p); + return (NULL); +} +struct party * +uni_find_partyx(struct call *c, u_int epref, u_int mine) +{ + struct party *p; + + TAILQ_FOREACH(p, &c->parties, link) + if (p->epref == epref && (!(p->flags & PARTY_MINE) == !mine)) + return (p); + return (NULL); +} + +/* + * Destroy a party. + * This function is assumed to remove the party from the parent's call + * party list. + */ +void +uni_destroy_party(struct party *p, int really) +{ + struct uni_msg *api; + struct uniapi_party_destroyed *ind; + + TIMER_DESTROY_PARTY(p, t397); + TIMER_DESTROY_PARTY(p, t398); + TIMER_DESTROY_PARTY(p, t399); + + TAILQ_REMOVE(&p->call->parties, p, link); + + uni_delsig(p->call->uni, SIG_PARTY, p->call, p); + + if (!really) { + ind = ALLOC_API(struct uniapi_party_destroyed, api); + if (ind != NULL) { + ind->cref.cref = p->call->cref; + ind->cref.flag = p->call->mine; + ind->epref.epref = p->epref; + ind->epref.flag = p->flags & PARTY_MINE; + ind->epref.h.act = UNI_IEACT_DEFAULT; + IE_SETPRESENT(ind->epref); + + uni_enq_call(p->call, SIGC_PARTY_DESTROYED, 0, api, NULL); + } + + uni_enq_party(p, SIGP_PARTY_DELETE, 0, NULL, NULL); + return; + } + PARTY_FREE(p); +} + +/* + * Count number of parties in active states. + * If the argument is 0 only ACTIVE parties are counter + * If the argument is 1 only parties in establishing states are counted + * If the argument is 2 both are counted. + */ +u_int +uni_party_act_count(struct call *c, int kind) +{ + struct party *p; + u_int cnt; + + cnt = 0; + TAILQ_FOREACH(p, &c->parties, link) { + switch (p->state) { + + case UNI_EPSTATE_ACTIVE: + if (kind == 0 || kind == 2) + cnt++; + break; + + case UNI_EPSTATE_ALERT_RCVD: + case UNI_EPSTATE_ADD_INIT: + case UNI_EPSTATE_ALERT_DLVD: + case UNI_EPSTATE_ADD_RCVD: + if (kind == 1 || kind == 2) + cnt++; + break; + + default: + break; + } + } + return (cnt); +} + +static void +stop_all_party_timers(struct party *p) +{ + TIMER_STOP_PARTY(p, t397); + TIMER_STOP_PARTY(p, t398); + TIMER_STOP_PARTY(p, t399); +} +/************************************************************/ + +/* + * Add-party.request + * + * Q.2971:Party-control-U 3 (PU0) + * Q.2971:Party-control-N 3 (PN0) + */ +static void +pun0_add_party_request(struct party *p, struct uni_msg *api, uint32_t cookie) +{ + struct uni_all *add; + struct uniapi_add_party_request *req = + uni_msg_rptr(api, struct uniapi_add_party_request *); + + if ((add = UNI_ALLOC()) == NULL) { + uni_msg_destroy(api); + uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie); + return; + } + + add->u.add_party = req->add; + MK_MSG_ORIG(add, UNI_ADD_PARTY, p->call->cref, !p->call->mine); + uni_send_output(add, p->call->uni); + UNI_FREE(add); + + TIMER_START_PARTY(p, t399, p->call->uni->timer399); + + set_party_state(p, UNI_EPSTATE_ADD_INIT); + + uni_msg_destroy(api); + uniapi_party_error(p, UNIAPI_OK, cookie); +} + +/* + * Add-party-ack.request + * + * Q.2971:Party-Control-U 6 PU2 + * Q.2971:Party-Control-U 7 PU3 + * Q.2971:Party-Control-N 6 PN2 + * Q.2971:Party-Control-N 7 PN3 + */ +static void +punx_add_party_ack_request(struct party *p, struct uni_msg *m, uint32_t cookie) +{ + struct uni_all *ack; + struct uniapi_add_party_ack_request *req = + uni_msg_rptr(m, struct uniapi_add_party_ack_request *); + + if ((ack = UNI_ALLOC()) == NULL) { + uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie); + uni_msg_destroy(m); + return; + } + ack->u.add_party_ack = req->ack; + MK_MSG_ORIG(ack, UNI_ADD_PARTY_ACK, p->call->cref, !p->call->mine); + uni_send_output(ack, p->call->uni); + UNI_FREE(ack); + + set_party_state(p, UNI_EPSTATE_ACTIVE); + + uni_msg_destroy(m); + uniapi_party_error(p, UNIAPI_OK, cookie); +} + +/* + * Add-party-rej.request + * + * Q.2971:Party-Control-U 6 PU2 + * Q.2971:Party-Control-N 6 PN2 + */ +static void +pun2_add_party_rej_request(struct party *p, struct uni_msg *m, uint32_t cookie) +{ + struct uni_all *rej; + struct uniapi_add_party_rej_request *req = + uni_msg_rptr(m, struct uniapi_add_party_rej_request *); + + if ((rej = UNI_ALLOC()) == NULL) { + uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie); + uni_msg_destroy(m); + return; + } + + stop_all_party_timers(p); + + rej->u.add_party_rej = req->rej; + MK_MSG_ORIG(rej, UNI_ADD_PARTY_REJ, p->call->cref, !p->call->mine); + uni_enq_call(p->call, SIGC_SEND_ADD_PARTY_REJ, cookie, NULL, rej); + + uni_msg_destroy(m); + p->state = UNI_EPSTATE_NULL; + uniapi_party_error(p, UNIAPI_OK, cookie); + + uni_destroy_party(p, 0); +} + +/* + * ADD PARTY in PU0, PN0 + * + * Q.2971:Party-Control-U 3/14 PU0 + */ +static void +pun0_add_party(struct party *p, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_add_party_indication *ind; + struct uni_msg *api; + + ind = ALLOC_API(struct uniapi_add_party_indication, api); + if (ind != NULL) { + ind->add.hdr = u->u.hdr; + copy_msg_add_party(&u->u.add_party, &ind->add); + p->call->uni->funcs->uni_output(p->call->uni, p->call->uni->arg, + UNIAPI_ADD_PARTY_indication, 0, api); + } + set_party_state(p, UNI_EPSTATE_ADD_RCVD); + + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * PARTY-ALERTING.request + * + * Q.2971:Party-Control-U 6 (PU2) + * Q.2971:Party-Control-N 6 (PN2) + */ +static void +pun2_party_alerting_request(struct party *p, struct uni_msg *api, + uint32_t cookie) +{ + struct uni_all *alert; + struct uniapi_party_alerting_request *req = + uni_msg_rptr(api, struct uniapi_party_alerting_request *); + + if ((alert = UNI_ALLOC()) == NULL) { + uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie); + uni_msg_destroy(api); + return; + } + alert->u.party_alerting = req->alert; + MK_MSG_ORIG(alert, UNI_PARTY_ALERTING, + p->call->cref, !p->call->mine); + uni_send_output(alert, p->call->uni); + UNI_FREE(alert); + + set_party_state(p, UNI_EPSTATE_ALERT_DLVD); + + uni_msg_destroy(api); + uniapi_party_error(p, UNIAPI_OK, cookie); +} + +/* + * PARTY-ALERTING in state PU1/PN1 + * + * Q.2971:Party-Control-U 14 + * Q.2971:Party-Control-N 5 + */ +static void +pun1_party_alerting(struct party *p, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_party_alerting_indication *ind; + struct uni_msg *api; + + ind = ALLOC_API(struct uniapi_party_alerting_indication, api); + if (ind == NULL) { + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + TIMER_STOP_PARTY(p, t399); + + ind->alert.hdr = u->u.hdr; + copy_msg_party_alerting(&u->u.party_alerting, &ind->alert); + + p->call->uni->funcs->uni_output(p->call->uni, p->call->uni->arg, + UNIAPI_PARTY_ALERTING_indication, 0, api); + + TIMER_START_PARTY(p, t397, p->call->uni->timer397); + + uni_msg_destroy(m); + UNI_FREE(u); + + set_party_state(p, UNI_EPSTATE_ALERT_RCVD); +} + +/* + * ADD-PARTY-ACK + * + * Q.2971:Party-Control-U 4 (PU1) + * Q.2971:Party-Control-U 7 (PU4) + * Q.2971:Party-Control-N 4 (PN1) + * Q.2971:Party-Control-N 7 (PN4) + */ +static void +pun1pun4_add_party_ack(struct party *p, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_add_party_ack_indication *ind; + struct uni_msg *api; + + ind = ALLOC_API(struct uniapi_add_party_ack_indication, api); + if (ind == NULL) { + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + + if (p->state == UNI_EPSTATE_ADD_INIT) + TIMER_STOP_PARTY(p, t399); + else + TIMER_STOP_PARTY(p, t397); + + ind->ack.hdr = u->u.hdr; + copy_msg_add_party_ack(&u->u.add_party_ack, &ind->ack); + + p->call->uni->funcs->uni_output(p->call->uni, p->call->uni->arg, + UNIAPI_ADD_PARTY_ACK_indication, 0, api); + + uni_msg_destroy(m); + UNI_FREE(u); + + set_party_state(p, UNI_EPSTATE_ACTIVE); +} + +/* + * ADD-PARTY-REJECT + * + * Q.2971:Party-Control-U 4 (PU1) + * Q.2971:Party-Control-N 4 (PN1) + */ +static void +pun1_add_party_rej(struct party *p, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_add_party_rej_indication *ind; + struct uni_msg *api; + + ind = ALLOC_API(struct uniapi_add_party_rej_indication, api); + if (ind == NULL) { + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + + TIMER_STOP_PARTY(p, t399); + + ind->rej.hdr = u->u.hdr; + copy_msg_add_party_rej(&u->u.add_party_rej, &ind->rej); + uni_enq_call(p->call, SIGC_ADD_PARTY_REJ_indication, 0, api, NULL); + + uni_destroy_party(p, 0); + + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * ADD-PARTY-REJECT + * + * Q.2971:Party-Control-U 10 (PU5) + * Q.2971:Party-Control-N 10 (PN5) + */ +static void +pun5_add_party_rej(struct party *p, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_drop_party_ack_indication *ind; + struct uni_msg *api; + + ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api); + if (ind == NULL) { + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + + ind->drop.hdr = u->u.hdr; + COPY_FROM_ADD_REJ(u, &ind->drop); + if (IE_ISGOOD(u->u.add_party_rej.crankback)) + ind->crankback = u->u.add_party_rej.crankback; + uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication, 0, api, NULL); + + TIMER_STOP_PARTY(p, t398); + + uni_destroy_party(p, 0); + + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * DROP-PARTY-ACKNOWLEDGE + * + * Q.2971:Party-Control-U 8 + * Q.2971:Party-Control-N 8 + * + * Message already verified in Call-Control! + */ +static void +punx_drop_party_ack(struct party *p, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_drop_party_ack_indication *ind; + struct uni_msg *api; + + stop_all_party_timers(p); + + ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api); + if (ind != NULL) { + ind->drop.hdr = u->u.hdr; + COPY_FROM_DROP_ACK(u, &ind->drop); + uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication, + 0, api, NULL); + } + + uni_destroy_party(p, 0); + + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * DROP PARTY message in any state except PU5/PN5 + * + * Q.2971:Party-Control-U 9 + * Q.2971:Party-Control-N 9 + */ +static void +punx_drop_party(struct party *p, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_drop_party_indication *ind; + struct uni_msg *api; + + ind = ALLOC_API(struct uniapi_drop_party_indication, api); + if (ind == NULL) { + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + + ind->drop.hdr = u->u.hdr; + copy_msg_drop_party(&u->u.drop_party, &ind->drop); + + /* need the cause even if it is bad */ + if (IE_ISERROR(u->u.drop_party.cause)) + ind->drop.cause = u->u.drop_party.cause; + + ind->my_cause = p->call->uni->cause; + + uni_enq_call(p->call, SIGC_DROP_PARTY_indication, 0, api, NULL); + + TIMER_STOP_PARTY(p, t397); + TIMER_STOP_PARTY(p, t399); + + uni_msg_destroy(m); + UNI_FREE(u); + + set_party_state(p, UNI_EPSTATE_DROP_RCVD); +} + +/* + * DROP PARTY message in state PU5/PN5 + * + * Q.2971:Party-Control-U 10 + * Q.2971:Party-Control-N 10 + */ +static void +pun5_drop_party(struct party *p, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_drop_party_ack_indication *ind; + struct uni_msg *api; + + ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api); + if (ind == NULL) { + uni_msg_destroy(m); + UNI_FREE(u); + return; + } + + ind->drop.hdr = u->u.hdr; + copy_msg_drop_party(&u->u.drop_party, &ind->drop); + + /* need the cause even if it is bad */ + if (IE_ISERROR(u->u.drop_party.cause)) + ind->drop.cause = u->u.drop_party.cause; + + uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication, 0, api, NULL); + + TIMER_STOP_PARTY(p, t398); + + uni_msg_destroy(m); + UNI_FREE(u); + + set_party_state(p, UNI_EPSTATE_DROP_RCVD); + + uni_destroy_party(p, 0); +} + +/************************************************************/ + +/* + * T399 + * + * Q.2971:Party-Control-U 4 (PU1) + * Q.2971:Party-Control-N 4 (PN1) + */ +static void +pun1_t399(struct party *p) +{ + if (p->call->uni->proto == UNIPROTO_UNI40N) { + MK_IE_CAUSE(p->call->uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_NO_RESPONSE); + } else { + MK_IE_CAUSE(p->call->uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_RECOVER); + ADD_CAUSE_TIMER(p->call->uni->cause, "399"); + } + + drop_partyE(p); +} + +/* + * T398 + * + * Q.2971:Party-Control-U 10 (PU5) + * Q.2971:Party-Control-N 10 (PN5) + */ +static void +pun5_t398(struct party *p) +{ + struct uniapi_drop_party_ack_indication *ind; + struct uni_all *drop; + struct uni_msg *api; + + MK_IE_CAUSE(p->call->uni->cause, + UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER); + ADD_CAUSE_TIMER(p->call->uni->cause, "398"); + /* + * Send indication to API + */ + ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api); + if (ind != NULL) { + ind->drop.hdr.cref.cref = p->call->cref; + ind->drop.hdr.cref.flag = p->call->mine; + ind->drop.hdr.act = UNI_MSGACT_DEFAULT; + MK_IE_EPREF(ind->drop.epref, p->epref, p->flags & PARTY_MINE); + ind->drop.cause = p->call->uni->cause; + uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication, + 0, api, NULL); + } + + /* + * Send DROP PARTY ACK + */ + if ((drop = UNI_ALLOC()) != NULL) { + MK_MSG_ORIG(drop, UNI_DROP_PARTY_ACK, + p->call->cref, !p->call->mine); + MK_IE_EPREF(drop->u.drop_party_ack.epref, + p->epref, !(p->flags & PARTY_MINE)); + drop->u.drop_party_ack.cause = p->call->uni->cause; + uni_enq_call(p->call, SIGC_SEND_DROP_PARTY_ACK, 0, NULL, drop); + } + + uni_destroy_party(p, 0); +} + +/* + * T397 + * + * Q.2971:Party-Control-U 7 (PU4) + * Q.2971:Party-Control-N 7 (PN4) + */ +static void +pun4_t397(struct party *p) +{ + MK_IE_CAUSE(p->call->uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_RECOVER); + ADD_CAUSE_TIMER(p->call->uni->cause, "397"); + + drop_partyE(p); +} + +/************************************************************/ + +/* + * Drop a party because of an error condition. + * This is label E on page Party-Control-U 8/14. + * + * It is assumed, that the caller has constructed the cause in + * p->call->uni->cause. + */ +static void +drop_partyE(struct party *p) +{ + struct uni_msg *api; + struct uniapi_drop_party_indication *ind; + struct uni_all *drop; + + /* + * Send indication to API + */ + if ((ind = ALLOC_API(struct uniapi_drop_party_indication, api)) != NULL) { + ind->drop.hdr.cref.cref = p->call->cref; + ind->drop.hdr.cref.flag = p->call->mine; + ind->drop.hdr.act = UNI_MSGACT_DEFAULT; + MK_IE_EPREF(ind->drop.epref, p->epref, p->flags & PARTY_MINE); + ind->drop.cause = p->call->uni->cause; + uni_enq_call(p->call, SIGC_DROP_PARTY_indication, 0, api, NULL); + } + TIMER_STOP_PARTY(p, t399); + TIMER_STOP_PARTY(p, t397); + TIMER_START_PARTY(p, t398, p->call->uni->timer398); + + if ((drop = UNI_ALLOC()) != NULL) { + drop->u.drop_party.cause = p->call->uni->cause; + MK_MSG_ORIG(drop, UNI_DROP_PARTY, p->call->cref, !p->call->mine); + MK_IE_EPREF(drop->u.drop_party.epref, p->epref, + !(p->flags & PARTY_MINE)); + uni_enq_call(p->call, SIGC_SEND_DROP_PARTY, 0, NULL, drop); + } + + set_party_state(p, UNI_EPSTATE_DROP_INIT); +} + +/* + * Drop party request in Px1, Px3, Px4 or Px7 + * + * Q.2971:Party-Control-U 8 + * Q.2971:Party-Control-N 8 + */ +static void +punx_drop_party_request(struct party *p, struct uni_msg *api, uint32_t cookie) +{ + struct uniapi_drop_party_request *req = + uni_msg_rptr(api, struct uniapi_drop_party_request *); + struct uni_all *drop; + + if ((drop = UNI_ALLOC()) == NULL) { + uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie); + uni_msg_destroy(api); + return; + } + + TIMER_STOP_PARTY(p, t399); + TIMER_STOP_PARTY(p, t397); + TIMER_START_PARTY(p, t398, p->call->uni->timer398); + + drop->u.drop_party = req->drop; + MK_MSG_ORIG(drop, UNI_DROP_PARTY, p->call->cref, !p->call->mine); + uni_enq_call(p->call, SIGC_SEND_DROP_PARTY, cookie, NULL, drop); + + set_party_state(p, UNI_EPSTATE_DROP_INIT); + + uni_msg_destroy(api); + uniapi_party_error(p, UNIAPI_OK, cookie); +} + +/* + * Drop-party-ack.request in Px6 + * + * Q.2971:Party-Control-U 9 + * Q.2971:Party-Control-N 9 + */ +static void +pun6_drop_party_ack_request(struct party *p, struct uni_msg *api, uint32_t cookie) +{ + struct uniapi_drop_party_ack_request *req = + uni_msg_rptr(api, struct uniapi_drop_party_ack_request *); + struct uni_all *ack; + + if ((ack = UNI_ALLOC()) == NULL) { + uni_msg_destroy(api); + uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie); + return; + } + ack->u.drop_party_ack = req->ack; + MK_MSG_ORIG(ack, UNI_DROP_PARTY_ACK, p->call->cref, !p->call->mine); + uni_enq_call(p->call, SIGC_SEND_DROP_PARTY_ACK, cookie, NULL, ack); + + stop_all_party_timers(p); + + uni_msg_destroy(api); + uniapi_party_error(p, UNIAPI_OK, cookie); + + uni_destroy_party(p, 0); +} +/************************************************************/ +/* + * Party status enquiry request from API or call-control + * + * Q.2971:Party-Control-U 12 + * Q.2971:Party-Control-N 12 + */ +static void +punx_status_enquiry_request(struct party *p, uint32_t cookie) +{ + struct uni_all *enq; + + if((enq = UNI_ALLOC()) == NULL) { + uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie); + return; + } + MK_IE_EPREF(enq->u.status_enq.epref, p->epref, + !(p->flags & PARTY_MINE)); + MK_MSG_ORIG(enq, UNI_STATUS_ENQ, p->call->cref, !p->call->mine); + uni_enq_call(p->call, SIGC_SEND_STATUS_ENQ, cookie, NULL, enq); + + uniapi_party_error(p, UNIAPI_OK, cookie); +} + +/* + * STATUS in any state except PU5/PN5 + * + * Q.2971:Party-Control-U 12 + * Q.2971:Party-Control-N 12 + */ +static void +punx_status(struct party *p, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_drop_party_ack_indication *ind; + struct uni_msg *api; + + if (u->u.status.epstate.state == UNI_EPSTATE_NULL) { + /* should not happend */ + ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api); + if (ind != NULL) { + ind->drop.hdr = u->u.hdr; + ind->drop.cause = u->u.status.cause; + ind->drop.epref = u->u.status.epref; + uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication, + 0, api, NULL); + } + stop_all_party_timers(p); + + uni_destroy_party(p, 0); + } else { + if (epstate_compat(p, u->u.status.epstate.state)) { + if(u->u.status.cause.cause == UNI_CAUSE_MANDAT || + u->u.status.cause.cause == UNI_CAUSE_MTYPE_NIMPL || + u->u.status.cause.cause == UNI_CAUSE_IE_NIMPL || + u->u.status.cause.cause == UNI_CAUSE_IE_INV) { + MK_IE_CAUSE(p->call->uni->cause, + UNI_CAUSE_LOC_USER, + UNI_CAUSE_UNSPEC); + drop_partyE(p); + } + } else { + MK_IE_CAUSE(p->call->uni->cause, + UNI_CAUSE_LOC_USER, + UNI_CAUSE_MSG_INCOMP); + drop_partyE(p); + } + } + + uni_msg_destroy(m); + UNI_FREE(u); +} + +/* + * STATUS in PU5/PN5 + * + * Q.2971:Party-Control-U 10 + * Q.2971:Party-Control-N 10 + */ +static void +pun5_status(struct party *p, struct uni_msg *m, struct uni_all *u) +{ + struct uniapi_drop_party_ack_indication *ind; + struct uni_msg *api; + + if (u->u.status.epstate.state == UNI_EPSTATE_NULL) { + ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api); + if (ind != NULL) { + ind->drop.hdr = u->u.hdr; + ind->drop.cause = u->u.status.cause; + ind->drop.epref = u->u.status.epref; + uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication, + 0, api, NULL); + } + TIMER_STOP_PARTY(p, t398); + + uni_destroy_party(p, 0); + } + + uni_msg_destroy(m); + UNI_FREE(u); +} + +/************************************************************/ + +void +uni_sig_party(struct party *p, enum party_sig sig, uint32_t cookie, + struct uni_msg *msg, struct uni_all *u) +{ + if (sig >= SIGP_END) { + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "Signal %d outside of range to Party-Control", sig); + if (msg) + uni_msg_destroy(msg); + if (u) + UNI_FREE(u); + return; + } + VERBOSE(p->call->uni, UNI_FAC_CALL, 1, + "Signal %s in state %u of party %u/%s (call %u/%s in state %s)" + "; cookie %u", party_sigs[sig], p->state, p->epref, + (p->flags & PARTY_MINE) ? "mine" : "his", p->call->cref, + p->call->mine ? "mine" : "his", callstates[p->call->cstate].name, + cookie); + + switch (sig) { + + case SIGP_PARTY_DELETE: + PARTY_FREE(p); + break; + + /* + * Messages + */ + case SIGP_SETUP: + if (p->state == UNI_EPSTATE_NULL) { + /* Q.2971:Call-Control-U 3/13 */ + /* Q.2971:Call-Control-N 3/13 */ + set_party_state(p, UNI_EPSTATE_ADD_RCVD); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "SETUP in ps=%u", p->state); + break; + + case SIGP_ALERTING: + if (p->state == UNI_EPSTATE_ADD_INIT) { + /* Q.2971:Call-Control-U 14 */ + /* Q.2971:Call-Control-N 5 */ + TIMER_START_PARTY(p, t397, p->call->uni->timer397); + set_party_state(p, UNI_EPSTATE_ALERT_RCVD); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "ALERTING in ps=%u", p->state); + break; + + case SIGP_CONNECT: + if (p->state == UNI_EPSTATE_ADD_INIT) { + /* Q.2971:Call-Control-U 4/13 */ + TIMER_STOP_PARTY(p, t399); + set_party_state(p, UNI_EPSTATE_ACTIVE); + break; + } + if (p->state == UNI_EPSTATE_ALERT_RCVD) { + /* Q.2971:Call-Control-U 7/13 */ + TIMER_STOP_PARTY(p, t397); + set_party_state(p, UNI_EPSTATE_ACTIVE); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "CONNECT in ps=%u", p->state); + break; + + case SIGP_CONNECT_ACK: + if (p->state == UNI_EPSTATE_ADD_RCVD || + p->state == UNI_EPSTATE_ALERT_DLVD) { + /* Q.2971:Call-Control-U 6/13 */ + /* Q.2971:Call-Control-U 7/13 */ + p->flags &= ~PARTY_CONNECT; + set_party_state(p, UNI_EPSTATE_ACTIVE); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "CONNECT in ps=%u", p->state); + break; + + case SIGP_RELEASE: + if (p->state == UNI_EPSTATE_DROP_INIT) { + /* Q.2971:Party-Control-U 10/14 */ + /* Q.2971:Party-Control-N 10/14 */ + TIMER_STOP_PARTY(p, t398); + uni_destroy_party(p, 0); + break; + } + /* Q.2971:Party-Control-U 11/14 */ + /* Q.2971:Party-Control-N 11/14 */ + TIMER_STOP_PARTY(p, t397); + TIMER_STOP_PARTY(p, t399); + uni_destroy_party(p, 0); + break; + + case SIGP_RELEASE_COMPL: + /* Q.2971:Party-Control-U 11/14 */ + /* Q.2971:Party-Control-N 11/14 */ + stop_all_party_timers(p); + uni_destroy_party(p, 0); + break; + + case SIGP_RELEASE_confirm: + /* not in the SDLs */ + stop_all_party_timers(p); + uni_destroy_party(p, 0); + break; + + case SIGP_RELEASE_request: + if (p->state == UNI_EPSTATE_DROP_INIT) { + /* Q.2971:Party-Control-U 10 */ + /* Q.2971:Party-Control-N 10 */ + uni_destroy_party(p, 0); + break; + } + /* Q.2971:Party-Control-U 11 */ + /* Q.2971:Party-Control-N 11 */ + TIMER_STOP_PARTY(p, t397); + TIMER_STOP_PARTY(p, t399); + uni_destroy_party(p, 0); + break; + + case SIGP_RELEASE_response: + /* Q.2971:Party-Control-U 11 */ + /* Q.2971:Party-Control-N 11 */ + stop_all_party_timers(p); + uni_destroy_party(p, 0); + break; + + case SIGP_ADD_PARTY: + if (p->state == UNI_EPSTATE_NULL) { + /* Q.2971:Party-Control-U 3 PU0 */ + /* Q.2971:Party-Control-N 3 PN0 */ + pun0_add_party(p, msg, u); + break; + } + if (p->state == UNI_EPSTATE_ADD_RCVD) { + /* Q.2971:Party-Control-U 6 PU2 */ + /* Q.2971:Party-Control-N 6 PN2 */ + uni_msg_destroy(msg); + UNI_FREE(u); + break; + } + uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP, + &u->u.add_party.epref, p->state); + uni_msg_destroy(msg); + UNI_FREE(u); + break; + + case SIGP_PARTY_ALERTING: + if (p->state == UNI_EPSTATE_ADD_INIT) { + /* Q.2971:Party-Control-U 14 */ + /* Q.2971:Party-Control-N 5 */ + pun1_party_alerting(p, msg, u); + break; + } + uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP, + &u->u.party_alerting.epref, p->state); + uni_msg_destroy(msg); + UNI_FREE(u); + break; + + case SIGP_ADD_PARTY_ACK: + if (p->state == UNI_EPSTATE_ADD_INIT || + p->state == UNI_EPSTATE_ALERT_RCVD) { + /* Q.2971:Party-Control-U 4 (PU1) */ + /* Q.2971:Party-Control-U 7 (PU4) */ + /* Q.2971:Party-Control-N 4 (PN1) */ + /* Q.2971:Party-Control-N 7 (PN4) */ + pun1pun4_add_party_ack(p, msg, u); + break; + } + uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP, + &u->u.add_party_ack.epref, p->state); + uni_msg_destroy(msg); + UNI_FREE(u); + break; + + case SIGP_ADD_PARTY_REJ: + if (p->state == UNI_EPSTATE_ADD_INIT) { + /* Q.2971:Party-Control-U 4 (PU1) */ + /* Q.2971:Party-Control-N 4 (PN1) */ + pun1_add_party_rej(p, msg, u); + break; + } + if (p->state == UNI_EPSTATE_DROP_INIT) { + /* Q.2971:Party-Control-U 10 (PU5) */ + /* Q.2971:Party-Control-N 10 (PN5) */ + pun5_add_party_rej(p, msg, u); + break; + } + uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP, + &u->u.add_party_rej.epref, p->state); + uni_msg_destroy(msg); + UNI_FREE(u); + break; + + case SIGP_DROP_PARTY_ACK: + /* Q.2971:Party-Control-U 8 */ + /* Q.2971:Party-Control-N 8 */ + punx_drop_party_ack(p, msg, u); + break; + + case SIGP_DROP_PARTY: + if (p->state == UNI_EPSTATE_DROP_INIT) + /* Q.2971:Party-Control-U 10 */ + /* Q.2971:Party-Control-N 10 */ + pun5_drop_party(p, msg, u); + else + /* Q.2971:Party-Control-U 9 */ + /* Q.2971:Party-Control-N 9 */ + punx_drop_party(p, msg, u); + break; + + case SIGP_STATUS: + if (p->state == UNI_EPSTATE_DROP_INIT) + /* Q.2971:Party-Control-U 10 */ + /* Q.2971:Party-Control-N 10 */ + pun5_status(p, msg, u); + else + /* Q.2971:Party-Control-U 12 */ + /* Q.2971:Party-Control-N 12 */ + punx_status(p, msg, u); + break; + + /* + * User + */ + case SIGP_SETUP_request: + if (p->state == UNI_EPSTATE_NULL) { + /* Q.2971:Party-Control-U 3 */ + /* Q.2971:Party-Control-N 3 */ + set_party_state(p, UNI_EPSTATE_ADD_INIT); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "SETUP.request in ps=%u", p->state); + uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie); + break; + + case SIGP_SETUP_response: + if (p->state == UNI_EPSTATE_ADD_RCVD || + p->state == UNI_EPSTATE_ALERT_DLVD) { + /* Q.2971:Party-Control-N 6 (PN2) */ + /* Q.2971:Party-Control-N 7 (PN3) */ + set_party_state(p, UNI_EPSTATE_ACTIVE); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "SETUP.response in ps=%u", p->state); + uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie); + break; + + case SIGP_SETUP_COMPL_request: + if (p->state == UNI_EPSTATE_ADD_INIT) { + /* Q.2971:Party-Control-N 4 */ + TIMER_STOP_PARTY(p, t399); + set_party_state(p, UNI_EPSTATE_ACTIVE); + break; + } + if (p->state == UNI_EPSTATE_ALERT_RCVD) { + /* Q.2971:Party-Control-N 7 */ + TIMER_STOP_PARTY(p, t397); + set_party_state(p, UNI_EPSTATE_ACTIVE); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "SETUP_COMPL.request in ps=%u", p->state); + uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie); + break; + + case SIGP_ADD_PARTY_request: + if (p->state == UNI_EPSTATE_NULL) { + /* Q.2971:Party-control-U 3 (PU0) */ + /* Q.2971:Party-control-N 3 (PN0) */ + pun0_add_party_request(p, msg, cookie); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "Add-party.request in ps=%u", p->state); + uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGP_ALERTING_request: + /* Q.2971:Party-Control-U 6 (PU2) */ + /* Q.2971:Party-Control-N 6 (PN2) */ + set_party_state(p, UNI_EPSTATE_ALERT_DLVD); + break; + + case SIGP_PARTY_ALERTING_request: + if (p->state == UNI_EPSTATE_ADD_RCVD) { + /* Q.2971:Party-Control-U 6 (PU2) */ + /* Q.2971:Party-Control-N 6 (PN2) */ + pun2_party_alerting_request(p, msg, cookie); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "Party-alerting.request in ps=%u", p->state); + uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGP_ADD_PARTY_ACK_request: + if (p->state == UNI_EPSTATE_ADD_RCVD || + p->state == UNI_EPSTATE_ALERT_DLVD) { + /* Q.2971:Party-Control-U 6 PU2 */ + /* Q.2971:Party-Control-U 7 PU3 */ + /* Q.2971:Party-Control-N 6 PN2 */ + /* Q.2971:Party-Control-N 7 PN3 */ + punx_add_party_ack_request(p, msg, cookie); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "Add-party-ack.request in ps=%u", p->state); + uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGP_ADD_PARTY_REJ_request: + if (p->state == UNI_EPSTATE_ADD_RCVD) { + /* Q.2971:Party-Control-U 6 PU2 */ + /* Q.2971:Party-Control-N 6 PN2 */ + pun2_add_party_rej_request(p, msg, cookie); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "Add-party-rej.request in ps=%u", p->state); + uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGP_DROP_PARTY_request: + if (p->state == UNI_EPSTATE_ADD_INIT || + p->state == UNI_EPSTATE_ALERT_DLVD || + p->state == UNI_EPSTATE_ALERT_RCVD || + p->state == UNI_EPSTATE_ACTIVE) { + /* Q.2971:Party-Control-U 8 */ + /* Q.2971:Party-Control-N 8 */ + punx_drop_party_request(p, msg, cookie); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "Drop-party.request in ps=%u", p->state); + uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGP_DROP_PARTY_ACK_request: + if (p->state == UNI_EPSTATE_DROP_RCVD) { + /* Q.2971:Party-Control-U 9 */ + /* Q.2971:Party-Control-N 9 */ + pun6_drop_party_ack_request(p, msg, cookie); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "Drop-party-ack.request in ps=%u", p->state); + uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie); + uni_msg_destroy(msg); + break; + + case SIGP_STATUS_ENQUIRY_request: + /* Q.2971:Party-Control-U 12 */ + /* Q.2971:Party-Control-N 12 */ + punx_status_enquiry_request(p, cookie); + break; + + /* + * Timers + */ + case SIGP_T397: + if (p->state == UNI_EPSTATE_ALERT_RCVD) { + /* Q.2971:Party-Control-U 7 (PU4) */ + /* Q.2971:Party-Control-N 7 (PN4) */ + pun4_t397(p); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "T397 in ps=%u", p->state); + break; + + case SIGP_T398: + if (p->state == UNI_EPSTATE_DROP_INIT) { + /* Q.2971:Party-Control-U 10 (PU5) */ + /* Q.2971:Party-Control-N 10 (PN5) */ + pun5_t398(p); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "T398 in ps=%u", p->state); + break; + + case SIGP_T399: + if (p->state == UNI_EPSTATE_ADD_INIT) { + /* Q.2971:Party-Control-U 4 (PU1) */ + /* Q.2971:Party-Control-N 4 (PN1) */ + pun1_t399(p); + break; + } + VERBOSE(p->call->uni, UNI_FAC_ERR, 1, + "T399 in ps=%u", p->state); + break; + + case SIGP_END: + break; + } +} + +static void +t397_func(struct party *p) +{ + uni_enq_party(p, SIGP_T397, 0, NULL, NULL); +} +static void +t398_func(struct party *p) +{ + uni_enq_party(p, SIGP_T398, 0, NULL, NULL); +} +static void +t399_func(struct party *p) +{ + uni_enq_party(p, SIGP_T399, 0, NULL, NULL); +} + +static int +epstate_compat(struct party *p, enum uni_epstate state) +{ + if (p->state == UNI_EPSTATE_ADD_INIT || + p->state == UNI_EPSTATE_ALERT_RCVD) + if (state == UNI_EPSTATE_ADD_INIT || + state == UNI_EPSTATE_ALERT_RCVD) + return (0); + if (p->state == UNI_EPSTATE_ADD_RCVD || + p->state == UNI_EPSTATE_ALERT_DLVD) + if (state == UNI_EPSTATE_ADD_RCVD || + state == UNI_EPSTATE_ALERT_DLVD) + return (0); + return (1); +} diff --git a/sys/contrib/ngatm/netnatm/sig/sig_print.c b/sys/contrib/ngatm/netnatm/sig/sig_print.c new file mode 100644 index 000000000000..af996128e7ea --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/sig_print.c @@ -0,0 +1,622 @@ +/* + * Copyright (c) 2002-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * Kendy Kutzner <kutzner@fokus.fraunhofer.de> + * + * $Begemot: libunimsg/netnatm/sig/sig_print.c,v 1.6 2004/08/05 07:11:02 brandt Exp $ + */ + +#include <sys/types.h> +#ifdef _KERNEL +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/libkern.h> +#include <machine/stdarg.h> +#else +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#endif + +#include <netnatm/saal/sscfu.h> +#include <netnatm/msg/uni_hdr.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#include <netnatm/msg/uniprint.h> +#include <netnatm/sig/uni.h> +#include <netnatm/sig/unisig.h> +#include <netnatm/sig/unidef.h> + +const char * +uni_strerr(u_int err) +{ + static const char *const errstr[] = { +#define DEF(NAME, VAL, STR) [UNIAPI_##NAME] = STR, +UNIAPI_DEF_ERRORS(DEF) +#undef DEF + }; + static char buf[100]; + + if (err >= sizeof(errstr)/sizeof(errstr[0]) || errstr[err] == NULL) { + sprintf(buf, "Unknown error %u", err); + return (buf); + } + return (errstr[err]); +} + +#define D(M) [M] = #M +static const char *const msgs[] = { + D(UNIAPI_ERROR), + D(UNIAPI_CALL_CREATED), + D(UNIAPI_CALL_DESTROYED), + D(UNIAPI_PARTY_CREATED), + D(UNIAPI_PARTY_DESTROYED), + D(UNIAPI_LINK_ESTABLISH_request), + D(UNIAPI_LINK_ESTABLISH_confirm), + D(UNIAPI_LINK_RELEASE_request), + D(UNIAPI_LINK_RELEASE_confirm), + D(UNIAPI_RESET_request), + D(UNIAPI_RESET_confirm), + D(UNIAPI_RESET_indication), + D(UNIAPI_RESET_ERROR_indication), + D(UNIAPI_RESET_response), + D(UNIAPI_RESET_ERROR_response), + D(UNIAPI_RESET_STATUS_indication), + D(UNIAPI_SETUP_request), + D(UNIAPI_SETUP_indication), + D(UNIAPI_SETUP_response), + D(UNIAPI_SETUP_confirm), + D(UNIAPI_SETUP_COMPLETE_indication), + D(UNIAPI_SETUP_COMPLETE_request), + D(UNIAPI_ALERTING_request), + D(UNIAPI_ALERTING_indication), + D(UNIAPI_PROCEEDING_request), + D(UNIAPI_PROCEEDING_indication), + D(UNIAPI_RELEASE_request), + D(UNIAPI_RELEASE_indication), + D(UNIAPI_RELEASE_response), + D(UNIAPI_RELEASE_confirm), + D(UNIAPI_NOTIFY_request), + D(UNIAPI_NOTIFY_indication), + D(UNIAPI_STATUS_indication), + D(UNIAPI_STATUS_ENQUIRY_request), + D(UNIAPI_ADD_PARTY_request), + D(UNIAPI_ADD_PARTY_indication), + D(UNIAPI_PARTY_ALERTING_request), + D(UNIAPI_PARTY_ALERTING_indication), + D(UNIAPI_ADD_PARTY_ACK_request), + D(UNIAPI_ADD_PARTY_ACK_indication), + D(UNIAPI_ADD_PARTY_REJ_request), + D(UNIAPI_ADD_PARTY_REJ_indication), + D(UNIAPI_DROP_PARTY_request), + D(UNIAPI_DROP_PARTY_indication), + D(UNIAPI_DROP_PARTY_ACK_request), + D(UNIAPI_DROP_PARTY_ACK_indication), + D(UNIAPI_ABORT_CALL_request), +}; +#undef D + +void +uni_print_api(char *buf, size_t bufsiz, u_int type, u_int cookie, + const void *msg, struct unicx *cx) +{ + int old_dont_init = cx->dont_init; + + uni_print_init(buf, bufsiz, cx); + cx->dont_init = 1; + + if (type >= sizeof(msgs) / sizeof(msgs[0]) || msgs[type] == NULL) { + uni_print_flag("UNIAPI_UNKNOWN", cx); + uni_print_entry(cx, "sig", "%u", type); + uni_print_entry(cx, "cookie", "%u", cookie); + goto out; + } + + uni_print_flag(msgs[type], cx); + uni_print_entry(cx, "cookie", "%u", cookie); + cx->indent++; + + switch (type) { + + case UNIAPI_ERROR: + { + const struct uniapi_error *api = msg; + + uni_print_eol(cx); + uni_print_entry(cx, "reason", "%s", uni_strerr(api->reason)); + uni_print_entry(cx, "state", "U%u", api->state); + break; + } + + case UNIAPI_CALL_CREATED: + { + const struct uniapi_call_created *api = msg; + + uni_print_cref(NULL, 0, &api->cref, cx); + break; + } + + case UNIAPI_CALL_DESTROYED: + { + const struct uniapi_call_destroyed *api = msg; + + uni_print_cref(NULL, 0, &api->cref, cx); + break; + } + + case UNIAPI_PARTY_CREATED: + { + const struct uniapi_party_created *api = msg; + + uni_print_cref(NULL, 0, &api->cref, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_EPREF, + (const union uni_ieall *)&api->epref, cx); + break; + } + + case UNIAPI_PARTY_DESTROYED: + { + const struct uniapi_party_destroyed *api = msg; + + uni_print_cref(NULL, 0, &api->cref, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_EPREF, + (const union uni_ieall *)&api->epref, cx); + break; + } + + case UNIAPI_LINK_ESTABLISH_request: + case UNIAPI_LINK_ESTABLISH_confirm: + case UNIAPI_LINK_RELEASE_request: + case UNIAPI_LINK_RELEASE_confirm: + break; + + case UNIAPI_RESET_request: + { + const struct uniapi_reset_request *api = msg; + + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_RESTART, + (const union uni_ieall *)&api->restart, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_CONNID, + (const union uni_ieall *)&api->restart, cx); + break; + } + + case UNIAPI_RESET_confirm: + { + const struct uniapi_reset_confirm *api = msg; + + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_RESTART, + (const union uni_ieall *)&api->restart, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_CONNID, + (const union uni_ieall *)&api->restart, cx); + break; + } + + case UNIAPI_RESET_indication: + { + const struct uniapi_reset_indication *api = msg; + + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_RESTART, + (const union uni_ieall *)&api->restart, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_CONNID, + (const union uni_ieall *)&api->restart, cx); + break; + } + + case UNIAPI_RESET_ERROR_indication: + { + const struct uniapi_reset_error_indication *api = msg; + static const struct uni_print_tbl reason[] = { +#define DEF(NAME, VALUE, STR) { STR, VALUE }, + UNIAPI_DEF_RESET_ERRORS(DEF) +#undef DEF + { NULL, 0 } + }; + static const struct uni_print_tbl source[] = { + { "start", 0 }, + { "respond", 1 }, + { NULL, 0 } + }; + + uni_print_eol(cx); + uni_print_tbl("source", api->source, source, cx); + uni_print_tbl("reason", api->reason, reason, cx); + break; + } + + case UNIAPI_RESET_response: + { + const struct uniapi_reset_response *api = msg; + + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_RESTART, + (const union uni_ieall *)&api->restart, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_CONNID, + (const union uni_ieall *)&api->restart, cx); + break; + } + + case UNIAPI_RESET_ERROR_response: + { + const struct uniapi_reset_error_response *api = msg; + + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_CAUSE, + (const union uni_ieall *)&api->cause, cx); + break; + } + + case UNIAPI_RESET_STATUS_indication: + { + const struct uniapi_reset_status_indication *api = msg; + + uni_print_cref(NULL, 0, &api->cref, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_CALLSTATE, + (const union uni_ieall *)&api->callstate, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_CAUSE, + (const union uni_ieall *)&api->cause, cx); + break; + } + + case UNIAPI_SETUP_request: + { + const struct uniapi_setup_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_SETUP, + (const union uni_msgall *)&api->setup, cx); + break; + } + + case UNIAPI_SETUP_indication: + { + const struct uniapi_setup_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_SETUP, + (const union uni_msgall *)&api->setup, cx); + break; + } + + case UNIAPI_SETUP_response: + { + const struct uniapi_setup_response *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_CONNECT, + (const union uni_msgall *)&api->connect, cx); + break; + } + + case UNIAPI_SETUP_confirm: + { + const struct uniapi_setup_confirm *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_CONNECT, + (const union uni_msgall *)&api->connect, cx); + break; + } + + case UNIAPI_SETUP_COMPLETE_indication: + { + const struct uniapi_setup_complete_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_CONNECT_ACK, + (const union uni_msgall *)&api->connect_ack, cx); + break; + } + + case UNIAPI_SETUP_COMPLETE_request: + { + const struct uniapi_setup_complete_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_CONNECT_ACK, + (const union uni_msgall *)&api->connect_ack, cx); + break; + } + + case UNIAPI_ALERTING_request: + { + const struct uniapi_alerting_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_ALERTING, + (const union uni_msgall *)&api->alerting, cx); + break; + } + + case UNIAPI_ALERTING_indication: + { + const struct uniapi_alerting_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_ALERTING, + (const union uni_msgall *)&api->alerting, cx); + break; + } + + case UNIAPI_PROCEEDING_request: + { + const struct uniapi_proceeding_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_CALL_PROC, + (const union uni_msgall *)&api->call_proc, cx); + break; + } + + case UNIAPI_PROCEEDING_indication: + { + const struct uniapi_proceeding_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_CALL_PROC, + (const union uni_msgall *)&api->call_proc, cx); + break; + } + + case UNIAPI_RELEASE_request: + { + const struct uniapi_release_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_RELEASE, + (const union uni_msgall *)&api->release, cx); + break; + } + + case UNIAPI_RELEASE_indication: + { + const struct uniapi_release_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_RELEASE, + (const union uni_msgall *)&api->release, cx); + break; + } + + case UNIAPI_RELEASE_response: + { + const struct uniapi_release_response *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_RELEASE_COMPL, + (const union uni_msgall *)&api->release_compl, cx); + break; + } + case UNIAPI_RELEASE_confirm: + { + const struct uniapi_release_confirm *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_RELEASE, + (const union uni_msgall *)&api->release, cx); + break; + } + + case UNIAPI_NOTIFY_request: + { + const struct uniapi_notify_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_NOTIFY, + (const union uni_msgall *)&api->notify, cx); + break; + } + + case UNIAPI_NOTIFY_indication: + { + const struct uniapi_notify_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_NOTIFY, + (const union uni_msgall *)&api->notify, cx); + break; + } + + case UNIAPI_STATUS_indication: + { + const struct uniapi_status_indication *api = msg; + + uni_print_cref(NULL, 0, &api->cref, cx); + uni_print_eol(cx); + uni_print_entry(cx, "my_state", "U%u", api->my_state); + uni_print_entry(cx, "my_cause", "%s", + uni_ie_cause2str(UNI_CODING_ITU, api->my_cause)); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_CALLSTATE, + (const union uni_ieall *)&api->his_state, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_CAUSE, + (const union uni_ieall *)&api->his_cause, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_EPREF, + (const union uni_ieall *)&api->epref, cx); + break; + } + + case UNIAPI_STATUS_ENQUIRY_request: + { + const struct uniapi_status_enquiry_request *api = msg; + + uni_print_cref(NULL, 0, &api->cref, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_EPREF, + (const union uni_ieall *)&api->epref, cx); + break; + } + + case UNIAPI_ADD_PARTY_request: + { + const struct uniapi_add_party_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_ADD_PARTY, + (const union uni_msgall *)&api->add, cx); + break; + } + + case UNIAPI_ADD_PARTY_indication: + { + const struct uniapi_add_party_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_ADD_PARTY, + (const union uni_msgall *)&api->add, cx); + break; + } + + case UNIAPI_PARTY_ALERTING_request: + { + const struct uniapi_party_alerting_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_PARTY_ALERTING, + (const union uni_msgall *)&api->alert, cx); + break; + } + + case UNIAPI_PARTY_ALERTING_indication: + { + const struct uniapi_party_alerting_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_PARTY_ALERTING, + (const union uni_msgall *)&api->alert, cx); + break; + } + + case UNIAPI_ADD_PARTY_ACK_request: + { + const struct uniapi_add_party_ack_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_ADD_PARTY_ACK, + (const union uni_msgall *)&api->ack, cx); + break; + } + + case UNIAPI_ADD_PARTY_ACK_indication: + { + const struct uniapi_add_party_ack_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_ADD_PARTY_ACK, + (const union uni_msgall *)&api->ack, cx); + break; + } + + case UNIAPI_ADD_PARTY_REJ_request: + { + const struct uniapi_add_party_rej_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_ADD_PARTY_REJ, + (const union uni_msgall *)&api->rej, cx); + break; + } + + case UNIAPI_ADD_PARTY_REJ_indication: + { + const struct uniapi_add_party_rej_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_ADD_PARTY_REJ, + (const union uni_msgall *)&api->rej, cx); + break; + } + + case UNIAPI_DROP_PARTY_request: + { + const struct uniapi_drop_party_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_DROP_PARTY, + (const union uni_msgall *)&api->drop, cx); + break; + } + + case UNIAPI_DROP_PARTY_indication: + { + const struct uniapi_drop_party_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_DROP_PARTY, + (const union uni_msgall *)&api->drop, cx); + break; + } + + case UNIAPI_DROP_PARTY_ACK_request: + { + const struct uniapi_drop_party_ack_request *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_DROP_PARTY_ACK, + (const union uni_msgall *)&api->ack, cx); + break; + } + + case UNIAPI_DROP_PARTY_ACK_indication: + { + const struct uniapi_drop_party_ack_indication *api = msg; + + uni_print_eol(cx); + uni_print_msg(NULL, 0, UNI_DROP_PARTY, + (const union uni_msgall *)&api->drop, cx); + uni_print_eol(cx); + uni_print_ie(NULL, 0, UNI_IE_CRANKBACK, + (const union uni_ieall *)&api->crankback, cx); + break; + } + + case UNIAPI_ABORT_CALL_request: + { + const struct uniapi_abort_call_request *api = msg; + + uni_print_cref(NULL, 0, &api->cref, cx); + break; + } + } + + out: + cx->dont_init = old_dont_init; +} diff --git a/sys/contrib/ngatm/netnatm/sig/sig_reset.c b/sys/contrib/ngatm/netnatm/sig/sig_reset.c new file mode 100644 index 000000000000..469b9f762a6e --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/sig_reset.c @@ -0,0 +1,827 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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/sig/sig_reset.c,v 1.11 2004/08/05 07:11:03 brandt Exp $ + * + * Reset-start and reset-respond + */ + +#include <netnatm/unimsg.h> +#include <netnatm/saal/sscfudef.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#include <netnatm/sig/uni.h> + +#include <netnatm/sig/unipriv.h> +#include <netnatm/sig/unimkmsg.h> + +static void response_restart(struct uni *, struct uni_msg *, struct uni_all *); +static void response_status(struct uni *, struct uni_msg *, struct uni_all *); + +static void response_t317(struct uni *); + +static void response_error(struct uni *, struct uniapi_reset_error_response *, + uint32_t cookie); +static void response_response(struct uni *, struct uniapi_reset_response *, + uint32_t); + +static void start_request(struct uni *, struct uniapi_reset_request *, + uint32_t); + +static void start_t316(struct uni *); + +static void start_restart_ack(struct uni *, struct uni_msg *, struct uni_all *); +static void start_status(struct uni *, struct uni_msg *, struct uni_all *); + +static int restart_forward(struct uni *, const struct uni_all *); + +#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME, +static const char *const start_sigs[] = { + DEF_START_SIGS +}; +#undef DEF_PRIV_SIG + +#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME, +static const char *const respond_sigs[] = { + DEF_RESPOND_SIGS +}; +#undef DEF_PRIV_SIG + +TIMER_FUNC_UNI(t317, t317_func) +TIMER_FUNC_UNI(t316, t316_func) + +/* + * Reset-Start process. + */ +void +uni_sig_start(struct uni *uni, u_int sig, uint32_t cookie, + struct uni_msg *m, struct uni_all *u) +{ + if (sig >= SIGS_END) { + VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to " + "Reset-Start", sig); + if (m) + uni_msg_destroy(m); + if (u) + UNI_FREE(u); + return; + } + + VERBOSE(uni, UNI_FAC_RESTART, 1, + "Signal %s in state %u of Reset-Start; cookie %u", + start_sigs[sig], uni->glob_start, cookie); + + switch (sig) { + + /* + * User requests + */ + case SIGS_RESET_request: + start_request(uni, + uni_msg_rptr(m, struct uniapi_reset_request *), cookie); + uni_msg_destroy(m); + break; + + /* + * Timers + */ + case SIGS_T316: + start_t316(uni); + break; + + /* + * SAAL + */ + case SIGS_RESTART_ACK: + start_restart_ack(uni, m, u); + uni_msg_destroy(m); + UNI_FREE(u); + break; + + case SIGS_STATUS: + start_status(uni, m, u); + uni_msg_destroy(m); + UNI_FREE(u); + break; + + case SIGS_END: + break; + } +} + +/* + * Reset-request from USER. + * + * Q.2931:Reset-Start 1/2 + */ +static void +start_request(struct uni *uni, struct uniapi_reset_request *req, uint32_t cookie) +{ + struct uni_all *resp; + int err; + + if (uni->glob_start != UNI_CALLSTATE_REST0) { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); + return; + } + + if ((resp = UNI_ALLOC()) == NULL) { + uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0); + return; + } + + MK_MSG_ORIG(resp, UNI_RESTART, 0, 0); + resp->u.restart.restart = req->restart; + resp->u.restart.connid = req->connid; + + if (restart_forward(uni, resp)) + return; + + uni->connid_start = req->connid; + uni->restart_start = req->restart; + + if ((err = uni_send_output(resp, uni)) != 0) + uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0); + UNI_FREE(resp); + if (err) + return; + + uni->cnt316 = 0; + TIMER_START_UNI(uni, t316, uni->timer316); + uni->glob_start = UNI_CALLSTATE_REST1; + + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 1"); + + + uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); +} + +/* + * T316 timeout function + */ +static void +t316_func(struct uni *uni) +{ + uni_enq_start(uni, SIGS_T316, 0, NULL, NULL); +} + +/* + * Q.2931:Reset-Start 1/2 + */ +static void +start_t316(struct uni *uni) +{ + if (uni->glob_start != UNI_CALLSTATE_REST1) { + VERBOSE0(uni, UNI_FAC_ERR, "T316 in state %d", + uni->glob_start); + return; + } + + if (++uni->cnt316 == uni->init316) { + struct uni_msg *app; + struct uniapi_reset_error_indication *resp; + + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start error"); + + resp = ALLOC_API(struct uniapi_reset_error_indication, app); + if (resp != NULL) { + resp->source = 0; + resp->reason = UNIAPI_RESET_ERROR_NO_RESPONSE, + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_ERROR_indication, 0, app); + } + + uni->glob_start = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0"); + } else { + struct uni_all *resp; + + if ((resp = UNI_ALLOC()) == NULL) + return; + + MK_MSG_ORIG(resp, UNI_RESTART, 0, 0); + resp->u.restart.restart = uni->restart_start; + resp->u.restart.connid = uni->connid_start; + + (void)uni_send_output(resp, uni); + + UNI_FREE(resp); + + TIMER_START_UNI(uni, t316, uni->timer316); + } +} + +/* + * Got RESTART_ACK. + */ +static void +start_restart_ack(struct uni *uni, struct uni_msg *m, struct uni_all *u) +{ + enum uni_callstate new_state; + struct uniapi_reset_confirm *conf; + struct uni_msg *app; + + if (uni->glob_start == UNI_CALLSTATE_REST0) { + uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_start, + UNI_CAUSE_MSG_INCOMP, UNI_RESTART_ACK); + return; + } + + if (uni->glob_start != UNI_CALLSTATE_REST1) { + ASSERT(0, ("bad global call state in Reset-Start")); + return; + } + + /* + * If body decoding fails, this is because IEs are wrong. + */ + (void)uni_decode_body(m, u, &uni->cx); + MANDATE_IE(uni, u->u.restart_ack.restart, UNI_IE_RESTART); + + if (IE_ISGOOD(u->u.restart_ack.restart)) { + /* + * Q.2931: 5.5.2.2 + */ + if (u->u.restart_ack.restart.rclass == UNI_RESTART_ALL && + IE_ISGOOD(u->u.restart_ack.connid)) { + (void)UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID, + u->u.restart_ack.connid.h.act, + UNI_IERR_UNK); + } else if ((u->u.restart_ack.restart.rclass == UNI_RESTART_PATH || + u->u.restart_ack.restart.rclass == UNI_RESTART_CHANNEL)) { + MANDATE_IE(uni, u->u.restart_ack.connid, UNI_IE_CONNID); + } + } + /* + * Compare the information elements now, because + * we may need the new callstate for the status message + * below. + */ + new_state = UNI_CALLSTATE_REST1; + + if (IE_ISGOOD(u->u.restart_ack.restart) && + IE_ISGOOD(uni->restart_start) && + u->u.restart_ack.restart.rclass == uni->restart_start.rclass && + !IE_ISGOOD(u->u.restart_ack.connid) == !IE_ISGOOD(uni->connid_start) && + (!IE_ISGOOD(uni->connid_start) || + (u->u.restart_ack.connid.vpci == uni->connid_start.vpci && + u->u.restart_ack.connid.vci == uni->connid_start.vci))) + new_state = UNI_CALLSTATE_REST0; + + switch (uni_verify(uni, u->u.hdr.act)) { + case VFY_RAIM: + case VFY_RAI: + uni_respond_status_verify(uni, &u->u.hdr.cref, + UNI_CALLSTATE_REST1, NULL, 0); + case VFY_I: + return; + + case VFY_CLR: + uni->glob_start = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, + "Reset-Start state := 0"); + return; + + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(uni, &u->u.hdr.cref, + new_state, NULL, 0); + case VFY_OK: + break; + } + + if (new_state == UNI_CALLSTATE_REST1) + /* + * Q.2931: 5.5.1.2/2 + */ + return; + + /* + * Build restart.confirm signal for application + */ + if (!IE_ISGOOD(u->u.restart_ack.connid)) + u->u.restart.connid.h.present = 0; + + + if ((conf = ALLOC_API(struct uniapi_reset_confirm, app)) == NULL) + return; + conf->restart = u->u.restart.restart; + conf->connid = u->u.restart.connid; + + TIMER_STOP_UNI(uni, t316); + + uni->funcs->uni_output(uni, uni->arg, UNIAPI_RESET_confirm, 0, app); + + uni->glob_start = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0"); +} + +/* + * Reset-Start got a STATUS message. + * + * Q.2931: Reset-Start 2/2 + * + * In Q.2931 only CALLSTATE_REST1 is allowed, this seems silly and to contradict + * 5.6.12. So allow it in any state. + * + * The following states are considered compatible: + * + * Sender Receiver(we) + * ------ -------- + * Rest0 Rest0 this is the normal state OK! + * Rest2 Rest0 this may be the result of no answer from the API + * on the remote end and the us finally timing out. ERROR! + * Rest2 Rest1 this is normal. OK! + * Rest0 Rest1 RESTART_ACK was probably lost. OK! + * + * All others are wrong. + */ +static void +start_status(struct uni *uni, struct uni_msg *m, struct uni_all *u) +{ + (void)uni_decode_body(m, u, &uni->cx); + MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE); + MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE); + switch (uni_verify(uni, u->u.hdr.act)) { + case VFY_CLR: + uni->glob_start = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0"); + return; + + case VFY_RAIM: + case VFY_RAI: + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(uni, &u->u.hdr.cref, uni->glob_start, + NULL, 0); + case VFY_I: + case VFY_OK: + break; + } + if (!IE_ISGOOD(u->u.status.callstate)) { + /* + * As a result of the strange handling above, we must + * process a STATUS with an invalid or missing callstate! + */ + return; + } + if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 && + uni->glob_start == UNI_CALLSTATE_REST0) || + (u->u.status.callstate.state == UNI_CALLSTATE_REST0 && + uni->glob_start == UNI_CALLSTATE_REST1) || + (u->u.status.callstate.state == UNI_CALLSTATE_REST2 && + uni->glob_start == UNI_CALLSTATE_REST1)) { + /* + * Implementation dependend procedure: + * Inform the API + */ + struct uniapi_reset_status_indication *resp; + struct uni_msg *app; + + resp = ALLOC_API(struct uniapi_reset_status_indication, app); + if (resp == NULL) + return; + resp->cref = u->u.hdr.cref; + resp->callstate = u->u.status.callstate; + if (IE_ISGOOD(u->u.status.cause)) + resp->cause = u->u.status.cause; + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_STATUS_indication, 0, app); + + } else { + struct uniapi_reset_error_indication *resp; + struct uni_msg *app; + + resp = ALLOC_API(struct uniapi_reset_error_indication, app); + if (resp != NULL) { + resp->source = 0; + resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE, + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_ERROR_indication, 0, app); + } + } +} + +/************************************************************/ +/* + * Reset-Respond process. + */ +void +uni_sig_respond(struct uni *uni, u_int sig, uint32_t cookie, + struct uni_msg *m, struct uni_all *u) +{ + if (sig >= SIGR_END) { + VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to " + "Reset-Respond", sig); + if (m) + uni_msg_destroy(m); + if (u) + UNI_FREE(u); + return; + } + + VERBOSE(uni, UNI_FAC_RESTART, 1, + "Signal %s in state %u of Reset-Respond; cookie %u", + respond_sigs[sig], uni->glob_respond, cookie); + + switch (sig) { + + /* + * SAAL + */ + case SIGR_RESTART: + response_restart(uni, m, u); + uni_msg_destroy(m); + UNI_FREE(u); + break; + + case SIGR_STATUS: + response_status(uni, m, u); + uni_msg_destroy(m); + UNI_FREE(u); + break; + + /* + * User + */ + case SIGR_RESET_ERROR_response: + response_error(uni, + uni_msg_rptr(m, struct uniapi_reset_error_response *), + cookie); + uni_msg_destroy(m); + break; + + case SIGR_RESET_response: + response_response(uni, + uni_msg_rptr(m, struct uniapi_reset_response *), cookie); + uni_msg_destroy(m); + break; + + /* + * Timers + */ + case SIGR_T317: + response_t317(uni); + return; + + case SIGR_END: + break; + } +} + +/* + * Send a RELEASE_COMPLETE to all affected calls as per + * F.2.3(3) + */ +static int +restart_forward(struct uni *uni, const struct uni_all *u) +{ + struct call *c; + struct uni_all *resp; + + if ((resp = UNI_ALLOC()) == NULL) + return (-1); + + TAILQ_FOREACH(c, &uni->calls, link) { + if (u->u.restart.restart.rclass == UNI_RESTART_ALL || + (IE_ISPRESENT(c->connid) && + u->u.restart.connid.vpci == c->connid.vpci && + (u->u.restart.restart.rclass == UNI_RESTART_PATH || + u->u.restart.connid.vci == c->connid.vci))) { + MK_MSG_ORIG(resp, UNI_RELEASE_COMPL, c->cref, c->mine); + uni_release_compl(c, resp); + } + } + + UNI_FREE(resp); + return (0); +} + +/* + * Respond process got a restart message. + * Doesn't free the messages. + */ +static void +response_restart(struct uni *uni, struct uni_msg *m, struct uni_all *u) +{ + struct uni_msg *app; + struct uniapi_reset_indication *ind; + + if (uni->glob_respond == UNI_CALLSTATE_REST0) { + /* + * If body decoding fails, this is because IEs are wrong. + */ + (void)uni_decode_body(m, u, &uni->cx); + MANDATE_IE(uni, u->u.restart.restart, UNI_IE_RESTART); + if (IE_ISGOOD(u->u.restart.restart)) { + /* + * Q.2931: 5.5.2.2 + */ + if (u->u.restart.restart.rclass == UNI_RESTART_ALL && + IE_ISGOOD(u->u.restart.connid)) { + (void)UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID, + u->u.restart.connid.h.act, + UNI_IERR_UNK); + } else if ((u->u.restart.restart.rclass == UNI_RESTART_PATH || + u->u.restart.restart.rclass == UNI_RESTART_CHANNEL)) { + MANDATE_IE(uni, u->u.restart.connid, UNI_IE_CONNID); + } + } + switch (uni_verify(uni, u->u.hdr.act)) { + case VFY_RAIM: + case VFY_RAI: + uni_respond_status_verify(uni, &u->u.hdr.cref, + UNI_CALLSTATE_REST0, NULL, 0); + case VFY_CLR: + case VFY_I: + return; + + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(uni, &u->u.hdr.cref, + UNI_CALLSTATE_REST2, NULL, 0); + case VFY_OK: + break; + } + if (!IE_ISGOOD(u->u.restart.connid)) + u->u.restart.connid.h.present = 0; + + /* + * Send a RELEASE_COMPLETE to all affected calls as per + * F.2.3(3) + */ + if (restart_forward(uni, u)) + return; + + /* + * Build restart signal for application + */ + if ((ind = ALLOC_API(struct uniapi_reset_indication, app)) == NULL) + return; + + ind->restart = u->u.restart.restart; + ind->connid = u->u.restart.connid; + + uni_enq_coord(uni, SIGO_RESET_indication, 0, app); + + TIMER_START_UNI(uni, t317, uni->timer317); + uni->glob_respond = UNI_CALLSTATE_REST2; + + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 2"); + + + } else if (uni->glob_respond == UNI_CALLSTATE_REST2) { + /* + * No need to decode the message. It is unexpected in this + * state so return a status. + */ + uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_respond, + UNI_CAUSE_MSG_INCOMP, UNI_RESTART); + + + } else + ASSERT(0, ("bad global call state in responder")); +} + +static void +response_t317(struct uni *uni) +{ + struct uniapi_reset_error_indication *resp; + struct uni_msg *app; + + if (uni->glob_respond != UNI_CALLSTATE_REST2) { + VERBOSE0(uni, UNI_FAC_ERR, "T317 in state %d", + uni->glob_respond); + return; + } + + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond error"); + + if ((resp = ALLOC_API(struct uniapi_reset_error_indication, app)) != NULL) { + resp->source = 1; + resp->reason = UNIAPI_RESET_ERROR_NO_CONFIRM; + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_ERROR_indication, 0, app); + } + + uni->glob_respond = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0"); +} + +/* + * Error response from USER + */ +static void +response_error(struct uni *uni, struct uniapi_reset_error_response *c, + uint32_t cookie) +{ + struct uni_all *resp; + + if (uni->glob_respond != UNI_CALLSTATE_REST2) { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); + return; + } + + if ((resp = UNI_ALLOC()) == NULL) { + uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0); + return; + } + + MK_MSG_ORIG(resp, UNI_STATUS, 0, 1); + MK_IE_CALLSTATE(resp->u.status.callstate, UNI_CALLSTATE_REST2); + + if (IE_ISGOOD(c->cause)) + resp->u.status.cause = c->cause; + else { + MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_CHANNEL_NEX); + if (IE_ISGOOD(uni->connid_respond)) + ADD_CAUSE_CHANNID(resp->u.status.cause, + uni->connid_respond.vpci, + uni->connid_respond.vci); + } + + if (uni_send_output(resp, uni) != 0) { + uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0); + UNI_FREE(resp); + return; + } + + uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); +} + +/* + * Reset-response from user. + */ +static void +response_response(struct uni *uni, struct uniapi_reset_response *arg, + uint32_t cookie) +{ + struct uni_all *resp; + + if (uni->glob_respond != UNI_CALLSTATE_REST2) { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); + return; + } + + if (!IE_ISGOOD(arg->restart)) { + uniapi_uni_error(uni, UNIAPI_ERROR_MISSING_IE, cookie, 0); + return; + } + + if ((resp = UNI_ALLOC()) == NULL) { + uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0); + return; + } + + TIMER_STOP_UNI(uni, t317); + + MK_MSG_ORIG(resp, UNI_RESTART_ACK, 0, 1); + resp->u.restart.restart = arg->restart; + if (IE_ISGOOD(arg->connid)) + resp->u.restart.connid = arg->connid; + + if (uni_send_output(resp, uni) != 0) { + uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0); + UNI_FREE(resp); + return; + } + + UNI_FREE(resp); + + uni->glob_respond = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0"); + + uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); +} + +/* + * Reset-Response got a STATUS message. + * + * Q.2931: Reset-Response 2/2 + * + * In Q.2931 only CALLSTATE_REST2 is allowed, this seems silly and to contradict + * 5.6.12. So allow it in any state. + * + * The following states are considered compatible: + * + * Sender Receiver + * ------ -------- + * Rest0 Rest0 this is the normal state OK! + * Rest0 Rest2 this may be the result of no answer from the API + * and the Sender finally timing out. ERROR! + * Rest1 Rest2 this is normal. OK! + * Rest1 Rest0 RESTART_ACK was probably lost. OK! + * + * All others are wrong. + */ +static void +response_status(struct uni *uni, struct uni_msg *m, struct uni_all *u) +{ + (void)uni_decode_body(m, u, &uni->cx); + MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE); + MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE); + switch (uni_verify(uni, u->u.hdr.act)) { + case VFY_CLR: + if (uni->proto == UNIPROTO_UNI40U) { + uni->glob_respond = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, + "Reset-Respond state := 0"); + return; + } + break; + + case VFY_RAIM: + case VFY_RAI: + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(uni, &u->u.hdr.cref, + uni->glob_respond, NULL, 0); + case VFY_I: + case VFY_OK: + break; + } + if (!IE_ISGOOD(u->u.status.callstate)) { + /* + * As a result of the strange handling above, we must + * process a STATUS with an invalid or missing callstate! + */ + return; + } + if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 && + uni->glob_respond == UNI_CALLSTATE_REST0) || + (u->u.status.callstate.state == UNI_CALLSTATE_REST1 && + uni->glob_respond == UNI_CALLSTATE_REST0) || + (u->u.status.callstate.state == UNI_CALLSTATE_REST1 && + uni->glob_respond == UNI_CALLSTATE_REST2)) { + /* + * Implementation dependend procedure: + * Inform the API + */ + struct uniapi_reset_status_indication *resp; + struct uni_msg *app; + + resp = ALLOC_API(struct uniapi_reset_status_indication, app); + if (resp == NULL) + return; + + resp->cref = u->u.hdr.cref; + resp->callstate = u->u.status.callstate; + if (IE_ISGOOD(u->u.status.cause)) + resp->cause = u->u.status.cause; + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_STATUS_indication, 0, app); + + } else { + struct uniapi_reset_error_indication *resp; + struct uni_msg *app; + + resp = ALLOC_API(struct uniapi_reset_error_indication, app); + if (resp != NULL) { + resp->source = 1; + resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE, + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_ERROR_indication, 0, app); + } + } +} + +/* + * T317 timeout function + */ +static void +t317_func(struct uni *uni) +{ + uni_enq_resp(uni, SIGR_T317, 0, NULL, NULL); +} diff --git a/sys/contrib/ngatm/netnatm/sig/sig_uni.c b/sys/contrib/ngatm/netnatm/sig/sig_uni.c new file mode 100644 index 000000000000..e620fa7521c0 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/sig_uni.c @@ -0,0 +1,749 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/sig/sig_uni.c,v 1.11 2004/08/05 07:11:03 brandt Exp $ + * + * Instance handling + */ + +#include <netnatm/unimsg.h> +#include <netnatm/saal/sscopdef.h> +#include <netnatm/saal/sscfudef.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#include <netnatm/sig/uni.h> +#include <netnatm/sig/unisig.h> + +#include <netnatm/sig/unipriv.h> + +#ifdef UNICORE +UNICORE +#endif + +#define STR(S) [S] = #S +static const char *custat_names[] = { + STR(CU_STAT0), + STR(CU_STAT1), + STR(CU_STAT2), + STR(CU_STAT3), +}; +static const char *globstat_names[] = { + STR(UNI_CALLSTATE_REST0), + STR(UNI_CALLSTATE_REST1), + STR(UNI_CALLSTATE_REST2), +}; + +static const char *sig_names[] = { + STR(UNIAPI_ERROR), + STR(UNIAPI_CALL_CREATED), + STR(UNIAPI_CALL_DESTROYED), + STR(UNIAPI_PARTY_CREATED), + STR(UNIAPI_PARTY_DESTROYED), + STR(UNIAPI_LINK_ESTABLISH_request), + STR(UNIAPI_LINK_ESTABLISH_confirm), + STR(UNIAPI_LINK_RELEASE_request), + STR(UNIAPI_LINK_RELEASE_confirm), + STR(UNIAPI_RESET_request), + STR(UNIAPI_RESET_confirm), + STR(UNIAPI_RESET_indication), + STR(UNIAPI_RESET_ERROR_indication), + STR(UNIAPI_RESET_response), + STR(UNIAPI_RESET_ERROR_response), + STR(UNIAPI_RESET_STATUS_indication), + STR(UNIAPI_SETUP_request), + STR(UNIAPI_SETUP_indication), + STR(UNIAPI_SETUP_response), + STR(UNIAPI_SETUP_confirm), + STR(UNIAPI_SETUP_COMPLETE_indication), + STR(UNIAPI_SETUP_COMPLETE_request), + STR(UNIAPI_ALERTING_request), + STR(UNIAPI_ALERTING_indication), + STR(UNIAPI_PROCEEDING_request), + STR(UNIAPI_PROCEEDING_indication), + STR(UNIAPI_RELEASE_request), + STR(UNIAPI_RELEASE_indication), + STR(UNIAPI_RELEASE_response), + STR(UNIAPI_RELEASE_confirm), + STR(UNIAPI_NOTIFY_request), + STR(UNIAPI_NOTIFY_indication), + STR(UNIAPI_STATUS_indication), + STR(UNIAPI_STATUS_ENQUIRY_request), + STR(UNIAPI_ADD_PARTY_request), + STR(UNIAPI_ADD_PARTY_indication), + STR(UNIAPI_PARTY_ALERTING_request), + STR(UNIAPI_PARTY_ALERTING_indication), + STR(UNIAPI_ADD_PARTY_ACK_request), + STR(UNIAPI_ADD_PARTY_ACK_indication), + STR(UNIAPI_ADD_PARTY_REJ_request), + STR(UNIAPI_ADD_PARTY_REJ_indication), + STR(UNIAPI_DROP_PARTY_request), + STR(UNIAPI_DROP_PARTY_indication), + STR(UNIAPI_DROP_PARTY_ACK_request), + STR(UNIAPI_DROP_PARTY_ACK_indication), + STR(UNIAPI_ABORT_CALL_request), +}; + +static const char *verb_names[] = { +# define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] = #D, + UNI_DEBUG_FACILITIES +# undef UNI_DEBUG_DEFINE +}; + +const char * +uni_facname(enum uni_verb fac) +{ + static char buf[40]; + + if (fac >= UNI_MAXFACILITY) { + sprintf(buf, "FAC%u", fac); + return (buf); + } + return (verb_names[fac]); +} + +const char * +uni_signame(enum uni_sig sig) +{ + static char buf[40]; + + if (sig >= UNIAPI_MAXSIG) { + sprintf(buf, "UNIAPI_SIG%u", sig); + return (buf); + } + return (sig_names[sig]); +} + +struct unicx * +uni_context(struct uni *uni) +{ + return (&uni->cx); +} + +static void +uni_init(struct uni *uni) +{ + uni->working = 0; + uni->cref_alloc = 12; + uni->custat = CU_STAT0; + uni->glob_start = UNI_CALLSTATE_REST0; + uni->glob_respond = UNI_CALLSTATE_REST0; +} + +static void +uni_stop(struct uni *uni) +{ + struct call *c; + + while ((c = TAILQ_FIRST(&uni->calls)) != NULL) { + TAILQ_REMOVE(&uni->calls, c, link); + uni_destroy_call(c, 1); + } + + SIGQ_CLEAR(&uni->workq); + SIGQ_CLEAR(&uni->delq); +} + +/* + * INSTANCE HANDLING + */ +struct uni * +uni_create(void *arg, const struct uni_funcs *funcs) +{ + struct uni *uni; + + if ((uni = INS_ALLOC()) == NULL) + return (NULL); + + uni_init(uni); + + uni->funcs = funcs; + uni->arg = arg; + uni->proto = UNIPROTO_UNI40U; + uni->sb_tb = 0; + TAILQ_INIT(&uni->workq); + TAILQ_INIT(&uni->delq); + TIMER_INIT_UNI(uni, t309); + uni->timer309 = UNI_T309_DEFAULT; + TAILQ_INIT(&uni->calls); + uni_initcx(&uni->cx); + TIMER_INIT_UNI(uni, t317); + TIMER_INIT_UNI(uni, t316); + + uni->timer301 = UNI_T301_DEFAULT; + uni->init303 = UNI_T303_CNT_DEFAULT; + uni->timer303 = UNI_T303_DEFAULT; + uni->init308 = UNI_T308_CNT_DEFAULT; + uni->timer308 = UNI_T308_DEFAULT; + uni->timer310 = UNI_T310U_DEFAULT; + uni->timer313 = UNI_T313_DEFAULT; + uni->init316 = UNI_T316_CNT_DEFAULT; + uni->timer316 = UNI_T316_DEFAULT; + uni->timer317 = UNI_T317_DEFAULT; + uni->timer322 = UNI_T322_DEFAULT; + uni->init322 = UNI_T322_CNT_DEFAULT; + uni->timer397 = UNI_T397_DEFAULT; + uni->timer398 = UNI_T398_DEFAULT; + uni->timer399 = UNI_T399U_DEFAULT; + + return (uni); +} + +void +uni_destroy(struct uni *uni) +{ + uni_stop(uni); + + TIMER_DESTROY_UNI(uni, t309); + TIMER_DESTROY_UNI(uni, t316); + TIMER_DESTROY_UNI(uni, t317); + + INS_FREE(uni); +} + +void +uni_reset(struct uni *uni) +{ + uni_stop(uni); + uni_init(uni); +} + + +/* + * DISPATCH SSCOP SIGNAL + */ +void +uni_saal_input(struct uni *uni, enum saal_sig sig, struct uni_msg *m) +{ + switch (sig) { + + case SAAL_ESTABLISH_indication: + if (m != NULL) + uni_msg_destroy(m); + uni_enq_coord(uni, SIGO_SAAL_ESTABLISH_indication, 0, NULL); + break; + + case SAAL_ESTABLISH_confirm: + if (m != NULL) + uni_msg_destroy(m); + uni_enq_coord(uni, SIGO_SAAL_ESTABLISH_confirm, 0, NULL); + break; + + case SAAL_RELEASE_confirm: + if (m != NULL) + uni_msg_destroy(m); + uni_enq_coord(uni, SIGO_SAAL_RELEASE_confirm, 0, NULL); + break; + + case SAAL_RELEASE_indication: + if (m != NULL) + uni_msg_destroy(m); + uni_enq_coord(uni, SIGO_SAAL_RELEASE_indication, 0, NULL); + break; + + case SAAL_DATA_indication: + uni_enq_coord(uni, SIGO_SAAL_DATA_indication, 0, m); + break; + + case SAAL_UDATA_indication: + uni_enq_coord(uni, SIGO_SAAL_UDATA_indication, 0, m); + break; + + default: + VERBOSE(uni, UNI_FAC_ERR, 1, "bogus saal signal %u", sig); + if (m != NULL) + uni_msg_destroy(m); + break; + } +} + +static struct { + const char *name; + enum uni_sig sig; + size_t arglen; + u_int coord_sig; + u_int proto; +#define UNIU 0x01 +#define UNIN 0x02 +#define PNNI 0x04 +} maptab[] = { + { "LINK-ESTABLISH.request", UNIAPI_LINK_ESTABLISH_request, + 0, + SIGO_LINK_ESTABLISH_request, UNIU | UNIN }, + { "LINK-RELEASE.request", UNIAPI_LINK_RELEASE_request, + 0, + SIGO_LINK_RELEASE_request, UNIU | UNIN }, + + { "RESET.request", UNIAPI_RESET_request, + sizeof(struct uniapi_reset_request), + SIGO_RESET_request, UNIU | UNIN }, + { "RESET-ERROR.response", UNIAPI_RESET_ERROR_response, + sizeof(struct uniapi_reset_error_response), + SIGO_RESET_ERROR_response, UNIU | UNIN }, + { "RESET.response", UNIAPI_RESET_response, + sizeof(struct uniapi_reset_response), + SIGO_RESET_response, UNIU | UNIN }, + + { "SETUP.request", UNIAPI_SETUP_request, + sizeof(struct uniapi_setup_request), + SIGO_SETUP_request, UNIU | UNIN }, + { "SETUP.response", UNIAPI_SETUP_response, + sizeof(struct uniapi_setup_response), + SIGO_SETUP_response, UNIU | UNIN }, + { "SETUP-COMPLETE.request", UNIAPI_SETUP_COMPLETE_request, + sizeof(struct uniapi_setup_complete_request), + SIGO_SETUP_COMPLETE_request, UNIN }, + { "PROCEEDING.request", UNIAPI_PROCEEDING_request, + sizeof(struct uniapi_proceeding_request), + SIGO_PROCEEDING_request, UNIU | UNIN }, + { "ALERTING.request", UNIAPI_ALERTING_request, + sizeof(struct uniapi_alerting_request), + SIGO_ALERTING_request, UNIU | UNIN }, + { "RELEASE.request", UNIAPI_RELEASE_request, + sizeof(struct uniapi_release_request), + SIGO_RELEASE_request, UNIU | UNIN }, + { "RELEASE.response", UNIAPI_RELEASE_response, + sizeof(struct uniapi_release_response), + SIGO_RELEASE_response, UNIU | UNIN }, + { "NOTIFY.request", UNIAPI_NOTIFY_request, + sizeof(struct uniapi_notify_request), + SIGO_NOTIFY_request, UNIU | UNIN }, + { "STATUS-ENQUIRY.request", UNIAPI_STATUS_ENQUIRY_request, + sizeof(struct uniapi_status_enquiry_request), + SIGO_STATUS_ENQUIRY_request, UNIU | UNIN }, + + { "ADD-PARTY.request", UNIAPI_ADD_PARTY_request, + sizeof(struct uniapi_add_party_request), + SIGO_ADD_PARTY_request, UNIU | UNIN }, + { "ADD-PARTY-ACK.request", UNIAPI_ADD_PARTY_ACK_request, + sizeof(struct uniapi_add_party_ack_request), + SIGO_ADD_PARTY_ACK_request, UNIU | UNIN }, + { "ADD-PARTY-REJ.request", UNIAPI_ADD_PARTY_REJ_request, + sizeof(struct uniapi_add_party_rej_request), + SIGO_ADD_PARTY_REJ_request, UNIU | UNIN }, + { "PARTY-ALERTING.request", UNIAPI_PARTY_ALERTING_request, + sizeof(struct uniapi_party_alerting_request), + SIGO_PARTY_ALERTING_request, UNIU | UNIN }, + { "DROP-PARTY.request", UNIAPI_DROP_PARTY_request, + sizeof(struct uniapi_drop_party_request), + SIGO_DROP_PARTY_request, UNIU | UNIN }, + { "DROP-PARTY-ACK.request", UNIAPI_DROP_PARTY_ACK_request, + sizeof(struct uniapi_drop_party_ack_request), + SIGO_DROP_PARTY_ACK_request, UNIU | UNIN }, + + { "ABORT-CALL.request", UNIAPI_ABORT_CALL_request, + sizeof(struct uniapi_abort_call_request), + SIGO_ABORT_CALL_request, UNIU | UNIN }, + + { NULL, 0, 0, 0, 0 } +}; + +void +uni_uni_input(struct uni *uni, enum uni_sig sig, uint32_t cookie, + struct uni_msg *m) +{ + u_int i; + + for (i = 0; maptab[i].name != NULL; i++) { + if (maptab[i].sig == sig) { + if (uni->proto == UNIPROTO_UNI40U) { + if (!(maptab[i].proto & UNIU)) + uniapi_uni_error(uni, + UNIAPI_ERROR_BAD_SIGNAL, cookie, 0); + } else if(uni->proto == UNIPROTO_UNI40N) { + if (!(maptab[i].proto & UNIN)) + uniapi_uni_error(uni, + UNIAPI_ERROR_BAD_SIGNAL, cookie, 0); + } else if(uni->proto == UNIPROTO_PNNI10) { + if (!(maptab[i].proto & PNNI)) + uniapi_uni_error(uni, + UNIAPI_ERROR_BAD_SIGNAL, cookie, 0); + } else { + uniapi_uni_error(uni, + UNIAPI_ERROR_BAD_SIGNAL, cookie, 0); + } + if (uni_msg_len(m) != maptab[i].arglen) { + VERBOSE(uni, UNI_FAC_ERR, 1, "bogus data in %s" + " (expecting %zu, got %zu)", maptab[i].name, + maptab[i].arglen, uni_msg_len(m)); + uni_msg_destroy(m); + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_ARG, + cookie, 0); + return; + } + if (maptab[i].arglen == 0) { + uni_msg_destroy(m); + m = NULL; + } + VERBOSE(uni, UNI_FAC_API, 1, "got signal %s - " + "delivering to Coord", maptab[i].name); + uni_enq_coord(uni, maptab[i].coord_sig, cookie, m); + return; + } + } + VERBOSE(uni, UNI_FAC_ERR, 1, "bogus uni signal %u", sig); + uni_msg_destroy(m); + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_SIGNAL, cookie, 0); +} +#undef UNIU +#undef UNIN +#undef PNNI + +/**************************************************************/ + +void +uni_work(struct uni *uni) +{ + struct sig *s; + + if (uni->working) + return; + uni->working = 1; + + while ((s = TAILQ_FIRST(&uni->workq)) != NULL) { + TAILQ_REMOVE(&uni->workq, s, link); + switch (s->type) { + + case SIG_COORD: + uni_sig_coord(uni, s->sig, s->cookie, s->msg); + break; + + case SIG_RESET_START: + uni_sig_start(uni, s->sig, s->cookie, s->msg, s->u); + break; + + case SIG_RESET_RESP: + uni_sig_respond(uni, s->sig, s->cookie, s->msg, s->u); + break; + + case SIG_CALL: + uni_sig_call(s->call, s->sig, s->cookie, s->msg, s->u); + break; + + case SIG_PARTY: + uni_sig_party(s->party, s->sig, s->cookie, s->msg, s->u); + break; + + default: + ASSERT(0, ("bad signal type")); + } + SIG_FREE(s); + } + + uni->working = 0; +} + +/* + * Enqueue a signal in the working queue + */ +void +uni_enq_sig(struct uni *uni, u_int type, struct call *call, + struct party *party, uint32_t sig, uint32_t cookie, + struct uni_msg *msg, struct uni_all *u) +{ + struct sig *s; + + if ((s = SIG_ALLOC()) != NULL) { + s->type = type; + s->sig = sig; + s->cookie = cookie; + s->msg = msg; + s->call = call; + s->party = party; + s->u = u; + TAILQ_INSERT_TAIL(&uni->workq, s, link); + } +} + +/* + * Enqueue a signal in the delayed queue + */ +void +uni_delenq_sig(struct uni *uni, u_int type, struct call *call, + struct party *party, uint32_t sig, uint32_t cookie, + struct uni_msg *msg, struct uni_all *u) +{ + struct sig *s; + + if ((s = SIG_ALLOC()) != NULL) { + s->type = type; + s->sig = sig; + s->cookie = cookie; + s->msg = msg; + s->call = call; + s->party = party; + s->u = u; + TAILQ_INSERT_TAIL(&uni->delq, s, link); + } +} + +/**************************************************************/ + +void +uniapi_uni_error(struct uni *uni, uint32_t reason, uint32_t cookie, + uint32_t state) +{ + struct uni_msg *resp; + struct uniapi_error *err; + + if (cookie == 0) + return; + + resp = uni_msg_alloc(sizeof(struct uniapi_error)); + err = uni_msg_wptr(resp, struct uniapi_error *); + resp->b_wptr += sizeof(struct uniapi_error); + + err->reason = reason; + err->state = state; + + uni->funcs->uni_output(uni, uni->arg, UNIAPI_ERROR, cookie, resp); +} + +void +uniapi_call_error(struct call *c, uint32_t reason, uint32_t cookie) +{ + uniapi_uni_error(c->uni, reason, cookie, callstates[c->cstate].ext); +} +void +uniapi_party_error(struct party *p, uint32_t reason, uint32_t cookie) +{ + uniapi_uni_error(p->call->uni, reason, cookie, + callstates[p->call->cstate].ext); +} + +/**************************************************************/ +void +uni_status(struct uni *uni, void *arg) +{ + uni->funcs->status(uni, uni->arg, arg, + "working: %s\n", uni->working ? "yes" : "no"); + uni->funcs->status(uni, uni->arg, arg, + "work queue: %sempty\n", TAILQ_EMPTY(&uni->workq)? "" : "not "); + uni->funcs->status(uni, uni->arg, arg, + "delayed work queue: %sempty\n", + TAILQ_EMPTY(&uni->delq)? "" : "not "); + uni->funcs->status(uni, uni->arg, arg, + "coordinator: %s\n", custat_names[uni->custat]); + uni->funcs->status(uni, uni->arg, arg, + "reset-start: %s\n", globstat_names[uni->glob_start]); + uni->funcs->status(uni, uni->arg, arg, + "reset-respond: %s\n", globstat_names[uni->glob_respond]); +} + +void +uni_undel(struct uni *uni, int (*filter)(struct sig *, void *), void *arg) +{ + struct sigqueue newq; + struct sig *s, *s1; + + if (TAILQ_EMPTY(&uni->delq)) + return; + + TAILQ_INIT(&newq); + + s = TAILQ_FIRST(&uni->delq); + while (s != NULL) { + s1 = TAILQ_NEXT(s, link); + if ((*filter)(s, arg)) { + TAILQ_REMOVE(&uni->delq, s, link); + TAILQ_INSERT_TAIL(&uni->workq, s, link); + } + s = s1; + } +} + +void +uni_delsig(struct uni *uni, u_int type, struct call *c, struct party *p) +{ + struct sig *s, *s1; + + s = TAILQ_FIRST(&uni->workq); + while (s != NULL) { + s1 = TAILQ_NEXT(s, link); + if ((type == SIG_CALL && s->type == SIG_CALL && + s->call == c) || + (type == SIG_PARTY && s->type == SIG_PARTY && + s->call == c && s->party == p)) { + TAILQ_REMOVE(&uni->workq, s, link); + if (s->msg) + uni_msg_destroy(s->msg); + if (s->u) + UNI_FREE(s->u); + SIG_FREE(s); + } + s = s1; + } + + s = TAILQ_FIRST(&uni->delq); + while (s != NULL) { + s1 = TAILQ_NEXT(s, link); + if ((type == SIG_CALL && s->type == SIG_CALL && + s->call == c) || + (type == SIG_PARTY && s->type == SIG_PARTY && + s->call == c && s->party == p)) { + TAILQ_REMOVE(&uni->delq, s, link); + if (s->msg) + uni_msg_destroy(s->msg); + if (s->u) + UNI_FREE(s->u); + SIG_FREE(s); \ + } + s = s1; + } +} + +/**************************************************************/ + +void +uni_get_config(const struct uni *uni, struct uni_config *config) +{ + config->proto = uni->proto; + + config->popt = 0; + if (uni->cx.q2932) + config->popt |= UNIPROTO_GFP; + + config->option = 0; + if (uni->cx.git_hard) + config->option |= UNIOPT_GIT_HARD; + if (uni->cx.bearer_hard) + config->option |= UNIOPT_BEARER_HARD; + if (uni->cx.cause_hard) + config->option |= UNIOPT_CAUSE_HARD; + if (uni->sb_tb) + config->popt |= UNIPROTO_SB_TB; + + config->timer301 = uni->timer301; + config->timer303 = uni->timer303; + config->init303 = uni->init303; + config->timer308 = uni->timer308; + config->init308 = uni->init308; + config->timer309 = uni->timer309; + config->timer310 = uni->timer310; + config->timer313 = uni->timer313; + config->timer316 = uni->timer316; + config->init316 = uni->init316; + config->timer317 = uni->timer317; + config->timer322 = uni->timer322; + config->init322 = uni->init322; + config->timer397 = uni->timer397; + config->timer398 = uni->timer398; + config->timer399 = uni->timer399; +} + +void +uni_set_config(struct uni *uni, const struct uni_config *config, + uint32_t *mask, uint32_t *popt_mask, uint32_t *opt_mask) +{ + int idle; + + idle = TAILQ_EMPTY(&uni->calls) && + TAILQ_EMPTY(&uni->workq) && + TAILQ_EMPTY(&uni->delq); + + if ((*mask & UNICFG_PROTO) && idle) { + switch (config->proto) { + + case UNIPROTO_UNI40U: + case UNIPROTO_UNI40N: + /* case UNIPROTO_PNNI10: XXX */ + uni->proto = config->proto; + *mask &= ~UNICFG_PROTO; + break; + } + } + if (*popt_mask & UNIPROTO_GFP) { + if (config->popt & UNIPROTO_GFP) { + uni->cx.q2932 = 1; + *popt_mask &= ~UNIPROTO_GFP; + } else { + if (!uni->cx.q2932 || idle) { + uni->cx.q2932 = 0; + *popt_mask &= ~UNIPROTO_GFP; + } + } + } + if (*popt_mask & UNIPROTO_SB_TB) { + uni->sb_tb = ((config->popt & UNIPROTO_SB_TB) != 0); + *popt_mask &= ~UNIPROTO_SB_TB; + } + if (*opt_mask & UNIOPT_GIT_HARD) { + uni->cx.git_hard = ((config->option & UNIOPT_GIT_HARD) != 0); + *opt_mask &= ~UNIOPT_GIT_HARD; + } + if (*opt_mask & UNIOPT_BEARER_HARD) { + uni->cx.bearer_hard = ((config->option & UNIOPT_BEARER_HARD) != 0); + *opt_mask &= ~UNIOPT_BEARER_HARD; + } + if (*opt_mask & UNIOPT_CAUSE_HARD) { + uni->cx.cause_hard = ((config->option & UNIOPT_CAUSE_HARD) != 0); + *opt_mask &= ~UNIOPT_CAUSE_HARD; + } + +#define SET_TIMER(NAME,name) \ + if (*mask & UNICFG_##NAME) { \ + uni->name = config->name; \ + *mask &= ~UNICFG_##NAME; \ + } + + SET_TIMER(TIMER301, timer301); + SET_TIMER(TIMER303, timer303); + SET_TIMER(INIT303, init303); + SET_TIMER(TIMER308, timer308); + SET_TIMER(INIT308, init308); + SET_TIMER(TIMER309, timer309); + SET_TIMER(TIMER310, timer310); + SET_TIMER(TIMER313, timer313); + SET_TIMER(TIMER316, timer316); + SET_TIMER(INIT316, init316); + SET_TIMER(TIMER317, timer317); + SET_TIMER(TIMER322, timer322); + SET_TIMER(INIT322, init322); + SET_TIMER(TIMER397, timer397); + SET_TIMER(TIMER398, timer398); + SET_TIMER(TIMER399, timer399); + +#undef SET_TIMER +} + +void +uni_set_debug(struct uni *uni, enum uni_verb fac, u_int level) +{ + uni->debug[fac] = level; +} + +u_int +uni_get_debug(const struct uni *uni, enum uni_verb fac) +{ + return (uni->debug[fac]); +} + +u_int +uni_getcustate(const struct uni *uni) +{ + return (uni->custat); +} diff --git a/sys/contrib/ngatm/netnatm/sig/sig_unimsgcpy.c b/sys/contrib/ngatm/netnatm/sig/sig_unimsgcpy.c new file mode 100644 index 000000000000..1653ba7438ec --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/sig_unimsgcpy.c @@ -0,0 +1,594 @@ +/* This file was created automatically + * Source file: $Begemot: libunimsg/atm/msg/msg.def,v 1.3 2003/09/19 11:58:15 hbb Exp $ + * $FreeBSD$ + */ + +#include <netnatm/msg/unistruct.h> +#include <netnatm/sig/unimsgcpy.h> + +void +copy_msg_alerting(struct uni_alerting *src, struct uni_alerting *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->connid)) + dst->connid = src->connid; + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->uu)) + dst->uu = src->uu; + if(IE_ISGOOD(src->report)) + dst->report = src->report; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_call_proc(struct uni_call_proc *src, struct uni_call_proc *dst) +{ + if(IE_ISGOOD(src->connid)) + dst->connid = src->connid; + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_connect(struct uni_connect *src, struct uni_connect *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->aal)) + dst->aal = src->aal; + if(IE_ISGOOD(src->blli)) + dst->blli = src->blli; + if(IE_ISGOOD(src->connid)) + dst->connid = src->connid; + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + if(IE_ISGOOD(src->conned)) + dst->conned = src->conned; + if(IE_ISGOOD(src->connedsub)) + dst->connedsub = src->connedsub; + if(IE_ISGOOD(src->eetd)) + dst->eetd = src->eetd; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->uu)) + dst->uu = src->uu; + if(IE_ISGOOD(src->traffic)) + dst->traffic = src->traffic; + if(IE_ISGOOD(src->exqos)) + dst->exqos = src->exqos; + if(IE_ISGOOD(src->facility)) + dst->facility = src->facility; + if(IE_ISGOOD(src->abrsetup)) + dst->abrsetup = src->abrsetup; + if(IE_ISGOOD(src->abradd)) + dst->abradd = src->abradd; + if(IE_ISGOOD(src->called_soft)) + dst->called_soft = src->called_soft; + if(IE_ISGOOD(src->report)) + dst->report = src->report; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_connect_ack(struct uni_connect_ack *src, struct uni_connect_ack *dst) +{ + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_release(struct uni_release *src, struct uni_release *dst) +{ + u_int s, d; + + for(s = d = 0; s < 2; s++) + if(IE_ISGOOD(src->cause[s])) + dst->cause[d++] = src->cause[s]; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->uu)) + dst->uu = src->uu; + if(IE_ISGOOD(src->facility)) + dst->facility = src->facility; + if(IE_ISGOOD(src->crankback)) + dst->crankback = src->crankback; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_release_compl(struct uni_release_compl *src, struct uni_release_compl *dst) +{ + u_int s, d; + + for(s = d = 0; s < 2; s++) + if(IE_ISGOOD(src->cause[s])) + dst->cause[d++] = src->cause[s]; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->uu)) + dst->uu = src->uu; + if(IE_ISGOOD(src->crankback)) + dst->crankback = src->crankback; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_setup(struct uni_setup *src, struct uni_setup *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->aal)) + dst->aal = src->aal; + if(IE_ISGOOD(src->traffic)) + dst->traffic = src->traffic; + if(IE_ISGOOD(src->bearer)) + dst->bearer = src->bearer; + if(IE_ISGOOD(src->bhli)) + dst->bhli = src->bhli; + if(IE_ISGOOD(src->blli_repeat)) + dst->blli_repeat = src->blli_repeat; + for(s = d = 0; s < UNI_NUM_IE_BLLI; s++) + if(IE_ISGOOD(src->blli[s])) + dst->blli[d++] = src->blli[s]; + if(IE_ISGOOD(src->called)) + dst->called = src->called; + for(s = d = 0; s < UNI_NUM_IE_CALLEDSUB; s++) + if(IE_ISGOOD(src->calledsub[s])) + dst->calledsub[d++] = src->calledsub[s]; + if(IE_ISGOOD(src->calling)) + dst->calling = src->calling; + for(s = d = 0; s < UNI_NUM_IE_CALLINGSUB; s++) + if(IE_ISGOOD(src->callingsub[s])) + dst->callingsub[d++] = src->callingsub[s]; + if(IE_ISGOOD(src->connid)) + dst->connid = src->connid; + if(IE_ISGOOD(src->qos)) + dst->qos = src->qos; + if(IE_ISGOOD(src->eetd)) + dst->eetd = src->eetd; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + if(IE_ISGOOD(src->scompl)) + dst->scompl = src->scompl; + for(s = d = 0; s < UNI_NUM_IE_TNS; s++) + if(IE_ISGOOD(src->tns[s])) + dst->tns[d++] = src->tns[s]; + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->atraffic)) + dst->atraffic = src->atraffic; + if(IE_ISGOOD(src->mintraffic)) + dst->mintraffic = src->mintraffic; + if(IE_ISGOOD(src->uu)) + dst->uu = src->uu; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->lij_callid)) + dst->lij_callid = src->lij_callid; + if(IE_ISGOOD(src->lij_param)) + dst->lij_param = src->lij_param; + if(IE_ISGOOD(src->lij_seqno)) + dst->lij_seqno = src->lij_seqno; + if(IE_ISGOOD(src->exqos)) + dst->exqos = src->exqos; + if(IE_ISGOOD(src->abrsetup)) + dst->abrsetup = src->abrsetup; + if(IE_ISGOOD(src->abradd)) + dst->abradd = src->abradd; + if(IE_ISGOOD(src->cscope)) + dst->cscope = src->cscope; + if(IE_ISGOOD(src->calling_soft)) + dst->calling_soft = src->calling_soft; + if(IE_ISGOOD(src->called_soft)) + dst->called_soft = src->called_soft; + if(IE_ISGOOD(src->dtl_repeat)) + dst->dtl_repeat = src->dtl_repeat; + for(s = d = 0; s < UNI_NUM_IE_DTL; s++) + if(IE_ISGOOD(src->dtl[s])) + dst->dtl[d++] = src->dtl[s]; + if(IE_ISGOOD(src->report)) + dst->report = src->report; + if(IE_ISGOOD(src->mdcr)) + dst->mdcr = src->mdcr; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_status(struct uni_status *src, struct uni_status *dst) +{ + if(IE_ISGOOD(src->callstate)) + dst->callstate = src->callstate; + if(IE_ISGOOD(src->cause)) + dst->cause = src->cause; + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->epstate)) + dst->epstate = src->epstate; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_status_enq(struct uni_status_enq *src, struct uni_status_enq *dst) +{ + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_notify(struct uni_notify *src, struct uni_notify *dst) +{ + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_restart(struct uni_restart *src, struct uni_restart *dst) +{ + if(IE_ISGOOD(src->connid)) + dst->connid = src->connid; + if(IE_ISGOOD(src->restart)) + dst->restart = src->restart; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_restart_ack(struct uni_restart_ack *src, struct uni_restart_ack *dst) +{ + if(IE_ISGOOD(src->connid)) + dst->connid = src->connid; + if(IE_ISGOOD(src->restart)) + dst->restart = src->restart; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_add_party(struct uni_add_party *src, struct uni_add_party *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->aal)) + dst->aal = src->aal; + if(IE_ISGOOD(src->bhli)) + dst->bhli = src->bhli; + if(IE_ISGOOD(src->blli)) + dst->blli = src->blli; + if(IE_ISGOOD(src->called)) + dst->called = src->called; + for(s = d = 0; s < UNI_NUM_IE_CALLEDSUB; s++) + if(IE_ISGOOD(src->calledsub[s])) + dst->calledsub[d++] = src->calledsub[s]; + if(IE_ISGOOD(src->calling)) + dst->calling = src->calling; + for(s = d = 0; s < UNI_NUM_IE_CALLINGSUB; s++) + if(IE_ISGOOD(src->callingsub[s])) + dst->callingsub[d++] = src->callingsub[s]; + if(IE_ISGOOD(src->scompl)) + dst->scompl = src->scompl; + for(s = d = 0; s < UNI_NUM_IE_TNS; s++) + if(IE_ISGOOD(src->tns[s])) + dst->tns[d++] = src->tns[s]; + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + if(IE_ISGOOD(src->eetd)) + dst->eetd = src->eetd; + if(IE_ISGOOD(src->uu)) + dst->uu = src->uu; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->lij_seqno)) + dst->lij_seqno = src->lij_seqno; + if(IE_ISGOOD(src->calling_soft)) + dst->calling_soft = src->calling_soft; + if(IE_ISGOOD(src->called_soft)) + dst->called_soft = src->called_soft; + if(IE_ISGOOD(src->dtl_repeat)) + dst->dtl_repeat = src->dtl_repeat; + for(s = d = 0; s < UNI_NUM_IE_DTL; s++) + if(IE_ISGOOD(src->dtl[s])) + dst->dtl[d++] = src->dtl[s]; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_add_party_ack(struct uni_add_party_ack *src, struct uni_add_party_ack *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->aal)) + dst->aal = src->aal; + if(IE_ISGOOD(src->blli)) + dst->blli = src->blli; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + if(IE_ISGOOD(src->eetd)) + dst->eetd = src->eetd; + if(IE_ISGOOD(src->conned)) + dst->conned = src->conned; + if(IE_ISGOOD(src->connedsub)) + dst->connedsub = src->connedsub; + if(IE_ISGOOD(src->uu)) + dst->uu = src->uu; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->called_soft)) + dst->called_soft = src->called_soft; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_party_alerting(struct uni_party_alerting *src, struct uni_party_alerting *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + if(IE_ISGOOD(src->uu)) + dst->uu = src->uu; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_add_party_rej(struct uni_add_party_rej *src, struct uni_add_party_rej *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->cause)) + dst->cause = src->cause; + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->uu)) + dst->uu = src->uu; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->crankback)) + dst->crankback = src->crankback; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_drop_party(struct uni_drop_party *src, struct uni_drop_party *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->cause)) + dst->cause = src->cause; + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + if(IE_ISGOOD(src->uu)) + dst->uu = src->uu; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_drop_party_ack(struct uni_drop_party_ack *src, struct uni_drop_party_ack *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->cause)) + dst->cause = src->cause; + if(IE_ISGOOD(src->uu)) + dst->uu = src->uu; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_leaf_setup_req(struct uni_leaf_setup_req *src, struct uni_leaf_setup_req *dst) +{ + u_int s, d; + + for(s = d = 0; s < UNI_NUM_IE_TNS; s++) + if(IE_ISGOOD(src->tns[s])) + dst->tns[d++] = src->tns[s]; + if(IE_ISGOOD(src->calling)) + dst->calling = src->calling; + for(s = d = 0; s < UNI_NUM_IE_CALLINGSUB; s++) + if(IE_ISGOOD(src->callingsub[s])) + dst->callingsub[d++] = src->callingsub[s]; + if(IE_ISGOOD(src->called)) + dst->called = src->called; + for(s = d = 0; s < UNI_NUM_IE_CALLEDSUB; s++) + if(IE_ISGOOD(src->calledsub[s])) + dst->calledsub[d++] = src->calledsub[s]; + if(IE_ISGOOD(src->lij_callid)) + dst->lij_callid = src->lij_callid; + if(IE_ISGOOD(src->lij_seqno)) + dst->lij_seqno = src->lij_seqno; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_leaf_setup_fail(struct uni_leaf_setup_fail *src, struct uni_leaf_setup_fail *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->cause)) + dst->cause = src->cause; + if(IE_ISGOOD(src->called)) + dst->called = src->called; + if(IE_ISGOOD(src->calledsub)) + dst->calledsub = src->calledsub; + if(IE_ISGOOD(src->lij_seqno)) + dst->lij_seqno = src->lij_seqno; + for(s = d = 0; s < UNI_NUM_IE_TNS; s++) + if(IE_ISGOOD(src->tns[s])) + dst->tns[d++] = src->tns[s]; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_cobisetup(struct uni_cobisetup *src, struct uni_cobisetup *dst) +{ + if(IE_ISGOOD(src->facility)) + dst->facility = src->facility; + if(IE_ISGOOD(src->called)) + dst->called = src->called; + if(IE_ISGOOD(src->calledsub)) + dst->calledsub = src->calledsub; + if(IE_ISGOOD(src->calling)) + dst->calling = src->calling; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_facility(struct uni_facility *src, struct uni_facility *dst) +{ + if(IE_ISGOOD(src->facility)) + dst->facility = src->facility; + if(IE_ISGOOD(src->called)) + dst->called = src->called; + if(IE_ISGOOD(src->calledsub)) + dst->calledsub = src->calledsub; + if(IE_ISGOOD(src->calling)) + dst->calling = src->calling; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_modify_req(struct uni_modify_req *src, struct uni_modify_req *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->traffic)) + dst->traffic = src->traffic; + if(IE_ISGOOD(src->atraffic)) + dst->atraffic = src->atraffic; + if(IE_ISGOOD(src->mintraffic)) + dst->mintraffic = src->mintraffic; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_modify_ack(struct uni_modify_ack *src, struct uni_modify_ack *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->report)) + dst->report = src->report; + if(IE_ISGOOD(src->traffic)) + dst->traffic = src->traffic; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_modify_rej(struct uni_modify_rej *src, struct uni_modify_rej *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->cause)) + dst->cause = src->cause; + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_conn_avail(struct uni_conn_avail *src, struct uni_conn_avail *dst) +{ + u_int s, d; + + if(IE_ISGOOD(src->notify)) + dst->notify = src->notify; + for(s = d = 0; s < UNI_NUM_IE_GIT; s++) + if(IE_ISGOOD(src->git[s])) + dst->git[d++] = src->git[s]; + if(IE_ISGOOD(src->report)) + dst->report = src->report; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} + +void +copy_msg_unknown(struct uni_unknown *src, struct uni_unknown *dst) +{ + if(IE_ISGOOD(src->epref)) + dst->epref = src->epref; + if(IE_ISGOOD(src->unrec)) + dst->unrec = src->unrec; +} diff --git a/sys/contrib/ngatm/netnatm/sig/sig_verify.c b/sys/contrib/ngatm/netnatm/sig/sig_verify.c new file mode 100644 index 000000000000..ae78ed8eb50f --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/sig_verify.c @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/sig/sig_verify.c,v 1.19 2004/07/08 08:22:23 brandt Exp $ + * + * Message verification with explicit action indicators. + */ + +#include <netnatm/unimsg.h> +#include <netnatm/saal/sscfudef.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#include <netnatm/sig/uni.h> + +#include <netnatm/sig/unipriv.h> +#include <netnatm/sig/unimkmsg.h> + +void +uni_mandate_ie(struct uni *uni, enum uni_ietype ie) +{ + struct uni_ierr *e; + + FOREACH_ERR(e, uni) + if (e->ie == ie) { + e->man = 1; + return; + } + if (UNI_SAVE_IERR(&uni->cx, ie, UNI_IEACT_DEFAULT, UNI_IERR_MIS)) + uni->cx.err[uni->cx.errcnt - 1].man = 1; +} + +/* + * This special handling is required for ADD PARTY, PARTY ALERTING and + * ADD PARTY ACKNOWLEDGE by Q.2971 9.5.3.2.1. + * It means, that the EPREF should be handled as mandatory only if + * no other IEs have explicit action indicators. + */ +void +uni_mandate_epref(struct uni *uni, struct uni_ie_epref *epref) +{ + struct uni_ierr *e; + int maxact; + + if (!IE_ISPRESENT(*epref)) { + /* + * 9.5.3.2.1 -- missing endpoint reference + */ + + /* + * a) if any unrecognized or IE with error has a CLEAR + * action indicator, this takes precedence. + * b) if any unrecognized or IE with error has a + * discard message and report action indicator, this takes + * precedence. + * c) if any unrecognized or IE with error has a + * discard message action indicator, this takes + * precedence. + * + * In any of these cases we must remove the EPREF IE + * if it has CLEAR, otherwise the CLEAR would take over. + */ + maxact = -1; + FOREACH_ERR(e, uni) { + if (e->ie == UNI_IE_EPREF) + continue; + if (e->act == UNI_IEACT_CLEAR) + maxact = UNI_IEACT_CLEAR; + else if (e->act == UNI_IEACT_MSG_REPORT) { + if (maxact == -1 && maxact != UNI_IEACT_CLEAR) + maxact = UNI_IEACT_MSG_REPORT; + } else if (e->act == UNI_IEACT_MSG_IGNORE) { + if (maxact == -1) + maxact = UNI_IEACT_MSG_IGNORE; + } + } + + if (maxact != -1) { + /* ok, second pass to remove UNI_IE_EPREF */ + FOREACH_ERR(e, uni) + if (e->ie == UNI_IE_EPREF) { + memmove(e, e + 1, + (uni->cx.errcnt - (e - uni->cx.err) + - 1) * sizeof(uni->cx.err[0])); + uni->cx.errcnt--; + break; + } + return; + + } + + /* + * d) if nothing of the above, the IE is mandatory + */ + uni_mandate_ie(uni, UNI_IE_EPREF); + return; + + } + if (IE_ISGOOD(*epref)) + return; + + /* + * It has an error obviously + * 9.5.3.2.2 + * + * It turns out, that Q.2931 handling just does the right thing + * if we don't mandate the IE. + */ + return; +} + +/* + * Look, what to do with this message. We assume, that the message itself is + * recognized. + * + * This is rather complicated. We must use the information provided in the + * fields of the context, because IEs with length errors may not be set + * altogether. + */ +enum verify +uni_verify(struct uni *uni, enum uni_msgact msgact) +{ + struct uni_ierr *e1; + + if (uni->debug[UNI_FAC_VERIFY] >= 2) { + FOREACH_ERR(e1, uni) { + VERBOSE(uni, UNI_FAC_VERIFY, 2, "ie=%02x err=%u man=%d" + " act=%u", e1->ie, e1->err, e1->man, e1->act); + } + } + + /* + * Look for missing mandatory IEs. The action indicator is ignored + * according to 5.6.7.1. If IEs are missing the action is to + * ignore the message and report status for all messages except + * RELEASE, RELEASE_COMPLETE and SETUP. Because we must differentiate + * this RAI from other RAIs in this case, use another return code. + * Note, that mandatory IEs with errors are not handled here. + */ + FOREACH_ERR(e1, uni) { + if (e1->err == UNI_IERR_MIS) { + MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_MANDAT); + VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAIM"); + return (VFY_RAIM); + } + } + + /* + * When any IE with error specifies a CLR action indicator, this + * takes precedence obviously. There are two cases here: + * unrecognized IEs and IEs with error. So we look through the + * error array twice and send only one STATUS. Unrecognized will + * take precedence. + * + * 5.7.2a) + */ + FOREACH_ERR(e1, uni) { + if (e1->act == UNI_IEACT_CLEAR && e1->err == UNI_IERR_UNK) { + MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_IE_NIMPL); + VERBOSE(uni, UNI_FAC_VERIFY, 1, "CLR1"); + return (VFY_CLR); + } + } + + FOREACH_ERR(e1, uni) { + if (e1->act == UNI_IEACT_CLEAR && + (e1->err == UNI_IERR_LEN || e1->err == UNI_IERR_BAD || + e1->err == UNI_IERR_ACC)) { + MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_IE_INV); + VERBOSE(uni, UNI_FAC_VERIFY, 1, "CLR2"); + return (VFY_CLR); + } + } + + /* + * Now check, whether anybody wants to explicitly ignore the message + * and report status. + * + * 5.7.2a) + */ + FOREACH_ERR(e1, uni) { + if (e1->act == UNI_IEACT_MSG_REPORT && e1->err == UNI_IERR_UNK) { + MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_IE_NIMPL); + VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI"); + return (VFY_RAI); + } + } + + FOREACH_ERR(e1, uni) { + if (e1->act == UNI_IEACT_MSG_REPORT && + (e1->err == UNI_IERR_LEN || e1->err == UNI_IERR_BAD || + e1->err == UNI_IERR_ACC)) { + MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_IE_INV); + VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI"); + return (VFY_RAI); + } + } + + /* + * Now look whether some IE wants to explicitely ignore the message + * without any report. + */ + FOREACH_ERR(e1, uni) { + if (e1->act == UNI_IEACT_MSG_IGNORE) { + VERBOSE(uni, UNI_FAC_VERIFY, 1, "I1"); + return (VFY_I); + } + } + + /* + * At this point we have left only + * mandatory and non-mandatory IEs with error that want the IE to be + * ignored or ignored with report or defaulted. + * Because a mandatory IE with errors lead to + * the message beeing ignored, we make this of higher + * precedence, than the rest. + */ + FOREACH_ERR(e1, uni) { + if (e1->man) { + MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_MANDAT); + VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI"); + return (VFY_RAI); + } + } + + /* + * Now look for ignoring the IE and reporting. This takes precedence + * over simply ignoring it. We also collect defaulted (non-mandatory) + * IEs. + * + * 5.7.2d) and 5.6.8.1 + */ + FOREACH_ERR(e1, uni) { + if ((e1->act == UNI_IEACT_DEFAULT || + e1->act == UNI_IEACT_REPORT) + && e1->err != UNI_IERR_UNK) { + MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_IE_INV); + VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAP"); + return (VFY_RAP); + } + } + + FOREACH_ERR(e1, uni) { + if ((e1->act == UNI_IEACT_DEFAULT || + e1->act == UNI_IEACT_REPORT) + && e1->err == UNI_IERR_UNK) { + MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_IE_NIMPL); + VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAPU"); + return (VFY_RAPU); + } + } + + /* + * This leaves us with IEs, that want to be ignored. Among these may + * be mandatory IEs. If we have an mandatory IEs here in the error + * array, then the message wil not contain enough information and + * must be handled according to 5.8 as either in 5.6.7.1 (this + * means, that mandatory IEs cannot really be ignored) or 5.7.1. + */ + FOREACH_ERR(e1, uni) { + if (e1->man) { + MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_MANDAT); + if (msgact == UNI_MSGACT_CLEAR) { + VERBOSE(uni, UNI_FAC_VERIFY, 1, "CLR3"); + return (VFY_CLR); + } + if (msgact == UNI_MSGACT_IGNORE) { + VERBOSE(uni, UNI_FAC_VERIFY, 1, "I2"); + return (VFY_I); + } + VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI"); + return (VFY_RAI); + } + } + + /* + * Now only non-mandatory IEs are left, that want to be explicitely + * ignored. + */ + if (uni->cx.errcnt != 0) + MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_IE_INV); + + VERBOSE(uni, UNI_FAC_VERIFY, 1, "OK"); + return (VFY_OK); +} + +/* + * Collect the IE identifiers for some of the known cause codes. + */ +void +uni_vfy_collect_ies(struct uni *uni) +{ + struct uni_ierr *e; + +#define STUFF_IE(IE) \ + uni->cause.u.ie.ie[uni->cause.u.ie.len++] = (IE); \ + if (uni->cause.u.ie.len == UNI_CAUSE_IE_N) \ + break; + + uni->cause.u.ie.len = 0; + if (uni->cause.cause == UNI_CAUSE_MANDAT) { + FOREACH_ERR(e, uni) { + if (e->err == UNI_IERR_MIS || e->man != 0) { + STUFF_IE(e->ie); + } + } + + } else if (uni->cause.cause == UNI_CAUSE_IE_NIMPL) { + FOREACH_ERR(e, uni) { + if (e->err == UNI_IERR_UNK) { + STUFF_IE(e->ie); + } + } + + } else if (uni->cause.cause == UNI_CAUSE_IE_INV) { + FOREACH_ERR(e, uni) { + if (e->err == UNI_IERR_LEN || + e->err == UNI_IERR_BAD || + e->err == UNI_IERR_ACC) { + STUFF_IE(e->ie); + } + } + } else + return; + + if (uni->cause.u.ie.len != 0) + uni->cause.h.present |= UNI_CAUSE_IE_P; +} + + +void +uni_respond_status_verify(struct uni *uni, struct uni_cref *cref, + enum uni_callstate cs, struct uni_ie_epref *epref, + enum uni_epstate ps) +{ + struct uni_all *resp; + + if ((resp = UNI_ALLOC()) == NULL) + return; + + uni_vfy_collect_ies(uni); + + MK_MSG_RESP(resp, UNI_STATUS, cref); + MK_IE_CALLSTATE(resp->u.status.callstate, cs); + resp->u.status.cause = uni->cause; + if (epref && IE_ISGOOD(*epref)) { + MK_IE_EPREF(resp->u.status.epref, epref->epref, !epref->flag); + MK_IE_EPSTATE(resp->u.status.epstate, ps); + } + + uni_send_output(resp, uni); + + UNI_FREE(resp); +} + +/* + * Handling of Q.2971 9.5.8.1: + */ +void +uni_vfy_remove_unknown(struct uni *uni) +{ + struct uni_ierr *e1, *e0; + int flag = 0; + + FOREACH_ERR(e1, uni) { + if (e1->err == UNI_IERR_UNK) { + if (e1->act == UNI_IEACT_CLEAR || + e1->act == UNI_IEACT_MSG_IGNORE || + e1->act == UNI_IEACT_MSG_REPORT) + return; + if (e1->act == UNI_IEACT_REPORT || + e1->act == UNI_IEACT_DEFAULT) + flag = 1; + } + } + if (flag) + return; + e0 = e1 = uni->cx.err; + while (e1 < uni->cx.err + uni->cx.errcnt) { + if (e1->err != UNI_IERR_UNK) { + if (e0 != e1) + *e0 = *e1; + e0++; + } + e1++; + } + uni->cx.errcnt = e0 - uni->cx.err; +} + +/* + * Handling for ADD_PARTY_REJ and DROP_PARTY_ACK with bad cause + */ +void +uni_vfy_remove_cause(struct uni *uni) +{ + struct uni_ierr *e1, *e0; + + e0 = e1 = uni->cx.err; + while (e1 < uni->cx.err + uni->cx.errcnt) { + if (e1->ie != UNI_IE_CAUSE) { + if (e0 != e1) + *e0 = *e1; + e0++; + } + e1++; + } + uni->cx.errcnt = e0 - uni->cx.err; +} diff --git a/sys/contrib/ngatm/netnatm/sig/uni.h b/sys/contrib/ngatm/netnatm/sig/uni.h new file mode 100644 index 000000000000..5af6c445d187 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/uni.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/sig/uni.h,v 1.5 2004/07/08 08:22:24 brandt Exp $ + * + * Public UNI interface + */ +#ifndef _NETNATM_SIG_UNI_H_ +#define _NETNATM_SIG_UNI_H_ + +#include <netnatm/sig/unidef.h> + +struct uni; + +/* functions to be supplied by the user */ +struct uni_funcs { + /* output to the upper layer */ + void (*uni_output)(struct uni *, void *, enum uni_sig, + uint32_t, struct uni_msg *); + + /* output to the SAAL */ + void (*saal_output)(struct uni *, void *, enum saal_sig, + struct uni_msg *); + + /* verbosity */ + void (*verbose)(struct uni *, void *, enum uni_verb, + const char *, ...) __printflike(4, 5); + + /* function to 'print' status */ + void (*status)(struct uni *, void *, void *, + const char *, ...) __printflike(4, 5); + +#ifndef _KERNEL + /* start a timer */ + void *(*start_timer)(struct uni *, void *, u_int, + void (*)(void *), void *); + + /* stop a timer */ + void (*stop_timer)(struct uni *, void *, void *); +#endif +}; + +/* create a UNI instance */ +struct uni *uni_create(void *, const struct uni_funcs *); + +/* destroy a UNI instance, free all resources */ +void uni_destroy(struct uni *); + +/* generate a status report */ +void uni_status(struct uni *, void *); + +/* get current instance configuration */ +void uni_get_config(const struct uni *, struct uni_config *); + +/* set new instance configuration */ +void uni_set_config(struct uni *, const struct uni_config *, + uint32_t *, uint32_t *, uint32_t *); + +/* input from the SAAL to the instance */ +void uni_saal_input(struct uni *, enum saal_sig, struct uni_msg *); + +/* input from the upper layer to the instance */ +void uni_uni_input(struct uni *, enum uni_sig, uint32_t, struct uni_msg *); + +/* do work on pending signals */ +void uni_work(struct uni *); + +/* set debuging level */ +void uni_set_debug(struct uni *, enum uni_verb, u_int level); +u_int uni_get_debug(const struct uni *, enum uni_verb); + +/* reset a UNI instance */ +void uni_reset(struct uni *); + +/* states */ +u_int uni_getcustate(const struct uni *); + +/* return a reference to the coding/decoding context */ +struct unicx *uni_context(struct uni *); + +#endif diff --git a/sys/contrib/ngatm/netnatm/sig/unidef.h b/sys/contrib/ngatm/netnatm/sig/unidef.h new file mode 100644 index 000000000000..7278db8b91cb --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/unidef.h @@ -0,0 +1,480 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/sig/unidef.h,v 1.9 2004/07/08 08:22:24 brandt Exp $ + * + * UNI public definitions. + */ +#ifndef _ATM_SIG_UNIDEF_H_ +#define _ATM_SIG_UNIDEF_H_ + +#ifdef _KERNEL +#include <sys/stdint.h> +#else +#include <stdint.h> +#endif + +/* + * Debug facilities + */ +#define UNI_DEBUG_FACILITIES \ + UNI_DEBUG_DEFINE(TIMEOUT) \ + UNI_DEBUG_DEFINE(RESTART) \ + UNI_DEBUG_DEFINE(SAAL) \ + UNI_DEBUG_DEFINE(PARSE) \ + UNI_DEBUG_DEFINE(CALL) \ + UNI_DEBUG_DEFINE(WARN) \ + UNI_DEBUG_DEFINE(COORD) \ + UNI_DEBUG_DEFINE(API) \ + UNI_DEBUG_DEFINE(MSG) \ + UNI_DEBUG_DEFINE(ERR) \ + UNI_DEBUG_DEFINE(VERIFY) \ + +enum uni_verb { +#define UNI_DEBUG_DEFINE(D) UNI_FAC_##D, + UNI_DEBUG_FACILITIES +#undef UNI_DEBUG_DEFINE + + UNI_MAXFACILITY, +}; + +/* + * Default timer values and repeat counts + */ +#define UNI_T301_DEFAULT 180000 +#define UNI_T303_DEFAULT 4000 +#define UNI_T303_CNT_DEFAULT 2 +#define UNI_T308_DEFAULT 30000 +#define UNI_T308_CNT_DEFAULT 2 +#define UNI_T309_DEFAULT 10000 +#define UNI_T310U_DEFAULT 30000 +#define UNI_T310N_DEFAULT 10000 +#define UNI_T313_DEFAULT 4000 +#define UNI_T316_DEFAULT 120000 +#define UNI_T316_CNT_DEFAULT 2 +#define UNI_T317_DEFAULT 90000 +#define UNI_T322_DEFAULT 4000 +#define UNI_T322_CNT_DEFAULT 2 +#define UNI_T397_DEFAULT UNI_T301_DEFAULT +#define UNI_T398_DEFAULT 4000 +#define UNI_T399U_DEFAULT (UNI_T303_DEFAULT + UNI_T310U_DEFAULT) +#define UNI_T399N_DEFAULT (UNI_T303_DEFAULT + UNI_T310N_DEFAULT) + +/* + * Protocol support + */ +enum uni_proto { + UNIPROTO_UNI40U, /* UNI4.0 user side */ + UNIPROTO_UNI40N, /* UNI4.0 network side */ + UNIPROTO_PNNI10, /* PNNI1.0 */ +}; +enum uni_popt { + UNIPROTO_GFP = 0x0001, /* enable GFP */ + UNIPROTO_SB_TB = 0x0002, /* Coincident Sb-Tb/Tb */ + + UNIPROTO_ALLMASK = 0x0003, +}; + +/* + * Other options + */ +enum uni_option { + UNIOPT_GIT_HARD = 0x0001, /* harder check of GIT IE */ + UNIOPT_BEARER_HARD = 0x0002, /* harder check of BEARER IE */ + UNIOPT_CAUSE_HARD = 0x0004, /* harder check of CAUSE IE */ + + UNIOPT_ALLMASK = 0x0007, +}; + +/* + * UNI configuration + */ +struct uni_config { + uint32_t proto; /* which protocol */ + uint32_t popt; /* protocol option */ + uint32_t option; /* other options */ + uint32_t timer301; /* T301 */ + uint32_t timer303; /* T303 */ + uint32_t init303; /* T303 retransmission count */ + uint32_t timer308; /* T308 */ + uint32_t init308; /* T308 retransmission count */ + uint32_t timer309; /* T309 */ + uint32_t timer310; /* T310 */ + uint32_t timer313; /* T313 */ + uint32_t timer316; /* T316 */ + uint32_t init316; /* T316 retransmission count */ + uint32_t timer317; /* T317 */ + uint32_t timer322; /* T322 */ + uint32_t init322; /* T322 retransmission count */ + uint32_t timer397; /* T397 */ + uint32_t timer398; /* T398 */ + uint32_t timer399; /* T399 */ +}; +enum uni_config_mask { + UNICFG_PROTO = 0x00000001, + UNICFG_TIMER301 = 0x00000002, + UNICFG_TIMER303 = 0x00000004, + UNICFG_INIT303 = 0x00000008, + UNICFG_TIMER308 = 0x00000010, + UNICFG_INIT308 = 0x00000020, + UNICFG_TIMER309 = 0x00000040, + UNICFG_TIMER310 = 0x00000080, + UNICFG_TIMER313 = 0x00000100, + UNICFG_TIMER316 = 0x00000200, + UNICFG_INIT316 = 0x00000400, + UNICFG_TIMER317 = 0x00000800, + UNICFG_TIMER322 = 0x00001000, + UNICFG_INIT322 = 0x00002000, + UNICFG_TIMER397 = 0x00004000, + UNICFG_TIMER398 = 0x00008000, + UNICFG_TIMER399 = 0x00010000, + + UNICFG_ALLMASK = 0x0001ffff, +}; + +/* + * API signals + */ +enum uni_sig { + UNIAPI_ERROR = 0, /* UNI -> API */ + + UNIAPI_CALL_CREATED = 1, /* UNI -> API */ + UNIAPI_CALL_DESTROYED = 2, /* UNI -> API */ + UNIAPI_PARTY_CREATED = 3, /* UNI -> API */ + UNIAPI_PARTY_DESTROYED = 4, /* UNI -> API */ + + UNIAPI_LINK_ESTABLISH_request = 5, /* API -> UNI */ + UNIAPI_LINK_ESTABLISH_confirm = 6, /* UNI -> API */ + UNIAPI_LINK_RELEASE_request = 7, /* API -> UNI */ + UNIAPI_LINK_RELEASE_confirm = 8, /* UNI -> API */ + + UNIAPI_RESET_request = 9, /* API -> UNI */ + UNIAPI_RESET_confirm = 10, /* UNI -> API */ + UNIAPI_RESET_indication = 11, /* UNI -> API */ + UNIAPI_RESET_ERROR_indication = 12, /* UNI -> API */ + UNIAPI_RESET_response = 13, /* API -> UNI */ + UNIAPI_RESET_ERROR_response = 14, /* API -> UNI */ + UNIAPI_RESET_STATUS_indication = 15, /* UNI -> API */ + + UNIAPI_SETUP_request = 16, /* API -> UNI */ + UNIAPI_SETUP_indication = 17, /* UNI -> API */ + UNIAPI_SETUP_response = 18, /* API -> UNI */ + UNIAPI_SETUP_confirm = 19, /* UNI -> API */ + UNIAPI_SETUP_COMPLETE_indication= 20, /* U-UNI -> API */ + UNIAPI_SETUP_COMPLETE_request = 46, /* API -> N-UNI */ + UNIAPI_ALERTING_request = 21, /* API -> UNI */ + UNIAPI_ALERTING_indication = 22, /* UNI -> API */ + UNIAPI_PROCEEDING_request = 23, /* API -> UNI */ + UNIAPI_PROCEEDING_indication = 24, /* UNI -> API */ + UNIAPI_RELEASE_request = 25, /* API -> UNI */ + UNIAPI_RELEASE_indication = 26, /* UNI -> API */ + UNIAPI_RELEASE_response = 27, /* API -> UNI */ + UNIAPI_RELEASE_confirm = 28, /* UNI -> API */ + UNIAPI_NOTIFY_request = 29, /* API -> UNI */ + UNIAPI_NOTIFY_indication = 30, /* UNI -> API */ + UNIAPI_STATUS_indication = 31, /* UNI -> API */ + UNIAPI_STATUS_ENQUIRY_request = 32, /* API -> UNI */ + + UNIAPI_ADD_PARTY_request = 33, /* API -> UNI */ + UNIAPI_ADD_PARTY_indication = 34, /* UNI -> API */ + UNIAPI_PARTY_ALERTING_request = 35, /* API -> UNI */ + UNIAPI_PARTY_ALERTING_indication= 36, /* UNI -> API */ + UNIAPI_ADD_PARTY_ACK_request = 37, /* API -> UNI */ + UNIAPI_ADD_PARTY_ACK_indication = 38, /* UNI -> API */ + UNIAPI_ADD_PARTY_REJ_request = 39, /* API -> UNI */ + UNIAPI_ADD_PARTY_REJ_indication = 40, /* UNI -> API */ + UNIAPI_DROP_PARTY_request = 41, /* API -> UNI */ + UNIAPI_DROP_PARTY_indication = 42, /* UNI -> API */ + UNIAPI_DROP_PARTY_ACK_request = 43, /* API -> UNI */ + UNIAPI_DROP_PARTY_ACK_indication= 44, /* UNI -> API */ + + UNIAPI_ABORT_CALL_request = 45, /* API -> UNI */ + + UNIAPI_MAXSIG = 47 +}; + +struct uniapi_error { + uint32_t reason; + uint32_t state; +}; +/* keep this in sync with atmapi.h:enum atmerr */ + +#define UNIAPI_DEF_ERRORS(MACRO) \ + MACRO(OK, 0, "no error") \ + MACRO(ERROR_BAD_SIGNAL, 1, "unknown signal") \ + MACRO(ERROR_BADCU, 2, "signal in bad co-ordinator state") \ + MACRO(ERROR_BAD_CALLSTATE, 3, "signal in bad call state") \ + MACRO(ERROR_BAD_EPSTATE, 4, "signal in bad endpoint state") \ + MACRO(ERROR_BAD_ARG, 5, "bad argument") \ + MACRO(ERROR_BAD_CALL, 6, "unknown call reference") \ + MACRO(ERROR_BAD_PARTY, 7, "unknown party") \ + MACRO(ERROR_BAD_CTYPE, 8, "bad type of call for signal") \ + MACRO(ERROR_BAD_IE, 9, "bad information element") \ + MACRO(ERROR_EPREF_INUSE, 10, "endpoint reference already in use") \ + MACRO(ERROR_MISSING_IE, 11, "missing information element") \ + MACRO(ERROR_ENCODING, 12, "error during message encoding") \ + MACRO(ERROR_NOMEM, 13, "out of memory") \ + MACRO(ERROR_BUSY, 14, "status enquiry busy") + +enum { +#define DEF(NAME, VAL, STR) UNIAPI_##NAME = VAL, +UNIAPI_DEF_ERRORS(DEF) +#undef DEF +}; + +struct uniapi_call_created { + struct uni_cref cref; +}; +struct uniapi_call_destroyed { + struct uni_cref cref; +}; +struct uniapi_party_created { + struct uni_cref cref; + struct uni_ie_epref epref; +}; +struct uniapi_party_destroyed { + struct uni_cref cref; + struct uni_ie_epref epref; +}; +struct uniapi_abort_call_request { + struct uni_cref cref; +}; + +struct uniapi_reset_request { + struct uni_ie_restart restart; + struct uni_ie_connid connid; +}; + +struct uniapi_reset_confirm { + struct uni_ie_restart restart; + struct uni_ie_connid connid; +}; + +struct uniapi_reset_indication { + struct uni_ie_restart restart; + struct uni_ie_connid connid; + +}; +struct uniapi_reset_error_indication { + uint32_t source; /* 0 - start, 1 - response */ + uint32_t reason; +}; + +#define UNIAPI_DEF_RESET_ERRORS(MACRO) \ + MACRO(UNIAPI_RESET_ERROR_NO_CONFIRM, 0, \ + "no confirmation") \ + MACRO(UNIAPI_RESET_ERROR_NO_RESPONSE, 1, \ + "no response") \ + MACRO(UNIAPI_RESET_ERROR_PEER_INCOMP_STATE, 2, \ + "incompatible state") +enum { +#define DEF(NAME, VALUE, STR) NAME = VALUE, +UNIAPI_DEF_RESET_ERRORS(DEF) +#undef DEF +}; + +struct uniapi_reset_response { + struct uni_ie_restart restart; + struct uni_ie_connid connid; +}; + +struct uniapi_reset_error_response { + struct uni_ie_cause cause; +}; + +struct uniapi_reset_status_indication { + struct uni_cref cref; /* STATUS message CREF */ + struct uni_ie_callstate callstate; + struct uni_ie_cause cause; +}; + +struct uniapi_setup_request { + struct uni_setup setup; +}; +struct uniapi_setup_indication { + struct uni_setup setup; +}; +struct uniapi_setup_response { + struct uni_connect connect; +}; +struct uniapi_setup_confirm { + struct uni_connect connect; +}; +struct uniapi_setup_complete_indication { + struct uni_connect_ack connect_ack; +}; +struct uniapi_setup_complete_request { + struct uni_connect_ack connect_ack; +}; + +struct uniapi_alerting_request { + struct uni_alerting alerting; +}; + +struct uniapi_alerting_indication { + struct uni_alerting alerting; +}; + +struct uniapi_proceeding_request { + struct uni_call_proc call_proc; +}; + +struct uniapi_proceeding_indication { + struct uni_call_proc call_proc; +}; + + +struct uniapi_release_request { + struct uni_release release; +}; +struct uniapi_release_indication { + struct uni_release release; +}; +struct uniapi_release_response { + struct uni_release_compl release_compl; +}; +/* + * A release confirm can come from a RELEASE COMPLETE or a RELEASE. + * Because the IEs in a RELEASE COMPLETE are a subset of a RELEASE, + * use the RELEASE here. + */ +struct uniapi_release_confirm { + struct uni_release release; +}; + +struct uniapi_notify_request { + struct uni_notify notify; +}; +struct uniapi_notify_indication { + struct uni_notify notify; +}; + +struct uniapi_status_indication { + struct uni_cref cref; + enum uni_callstate my_state; + enum uni_cause my_cause; + struct uni_ie_callstate his_state; + struct uni_ie_cause his_cause; + struct uni_ie_epref epref; + struct uni_ie_epstate epstate; +}; +struct uniapi_status_enquiry_request { + struct uni_cref cref; + struct uni_ie_epref epref; +}; + +struct uniapi_add_party_request { + struct uni_add_party add; +}; +struct uniapi_add_party_indication { + struct uni_add_party add; +}; + +struct uniapi_party_alerting_request { + struct uni_party_alerting alert; +}; +struct uniapi_party_alerting_indication { + struct uni_party_alerting alert; +}; + +struct uniapi_add_party_ack_request { + struct uni_add_party_ack ack; +}; +struct uniapi_add_party_ack_indication { + struct uni_add_party_ack ack; +}; +struct uniapi_add_party_rej_request { + struct uni_add_party_rej rej; +}; +struct uniapi_add_party_rej_indication { + struct uni_add_party_rej rej; +}; + +struct uniapi_drop_party_request { + struct uni_drop_party drop; +}; +struct uniapi_drop_party_indication { + struct uni_drop_party drop; + struct uni_ie_cause my_cause; +}; + +struct uniapi_drop_party_ack_request { + struct uni_drop_party_ack ack; +}; +struct uniapi_drop_party_ack_indication { + struct uni_drop_party drop; + struct uni_ie_crankback crankback; +}; + +union uniapi_all { + struct uniapi_error error; + struct uniapi_call_created call_created; + struct uniapi_call_destroyed call_destroyed; + struct uniapi_party_created party_created; + struct uniapi_party_destroyed party_destroyed; + struct uniapi_abort_call_request abort_call_request; + struct uniapi_reset_request reset_request; + struct uniapi_reset_confirm reset_confirm; + struct uniapi_reset_indication reset_indication; + struct uniapi_reset_error_indication reset_error_indication; + struct uniapi_reset_response reset_response; + struct uniapi_reset_error_response reset_error_response; + struct uniapi_reset_status_indication reset_status_indication; + struct uniapi_setup_request setup_request; + struct uniapi_setup_indication setup_indication; + struct uniapi_setup_response setup_response; + struct uniapi_setup_confirm setup_confirm; + struct uniapi_setup_complete_indication setup_complete_indication; + struct uniapi_setup_complete_request setup_complete_request; + struct uniapi_alerting_request alerting_request; + struct uniapi_alerting_indication alerting_indication; + struct uniapi_proceeding_request proceeding_request; + struct uniapi_proceeding_indication proceeding_indication; + struct uniapi_release_request release_request; + struct uniapi_release_indication release_indication; + struct uniapi_release_response release_response; + struct uniapi_release_confirm release_confirm; + struct uniapi_notify_request notify_request; + struct uniapi_notify_indication notify_indication; + struct uniapi_status_indication status_indication; + struct uniapi_status_enquiry_request status_enquiry_request; + struct uniapi_add_party_request add_party_request; + struct uniapi_add_party_indication add_party_indication; + struct uniapi_party_alerting_request party_alerting_request; + struct uniapi_party_alerting_indication party_alerting_indication; + struct uniapi_add_party_ack_request add_party_ack_request; + struct uniapi_add_party_ack_indication add_party_ack_indication; + struct uniapi_add_party_rej_request add_party_rej_request; + struct uniapi_add_party_rej_indication add_party_rej_indication; + struct uniapi_drop_party_request drop_party_request; + struct uniapi_drop_party_indication drop_party_indication; + struct uniapi_drop_party_ack_request drop_party_ack_request; + struct uniapi_drop_party_ack_indication drop_party_ack_indication; +}; + +#endif diff --git a/sys/contrib/ngatm/netnatm/sig/unimkmsg.h b/sys/contrib/ngatm/netnatm/sig/unimkmsg.h new file mode 100644 index 000000000000..80264e143b1c --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/unimkmsg.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/sig/unimkmsg.h,v 1.4 2003/09/19 12:03:34 hbb Exp $ + * + * Macros to make messages. + */ + +#define MK_MSG_ORIG(MSG,TYPE,CREF,FLAG) \ + do { \ + (MSG)->mtype = (TYPE); \ + (MSG)->u.hdr.cref.cref = (CREF); \ + (MSG)->u.hdr.cref.flag = (FLAG); \ + (MSG)->u.hdr.act = UNI_MSGACT_DEFAULT; \ + } while(0) + +#define MK_MSG_RESP(MSG,TYPE,CREF) \ + do { \ + (MSG)->mtype = (TYPE); \ + (MSG)->u.hdr.cref.cref = (CREF)->cref; \ + (MSG)->u.hdr.cref.flag = !(CREF)->flag; \ + (MSG)->u.hdr.act = UNI_MSGACT_DEFAULT; \ + } while(0) + +#define MK_IE_CALLSTATE(IE,CS) \ + do { \ + (IE).h.present = 0; \ + IE_SETPRESENT(IE); \ + (IE).h.coding = UNI_CODING_ITU; \ + (IE).h.act = UNI_IEACT_DEFAULT; \ + (IE).state = CS; \ + } while(0) + +#define MK_IE_EPREF(IE,EPREF,FLAG) \ + do { \ + (IE).h.present = 0; \ + IE_SETPRESENT(IE); \ + (IE).h.coding = UNI_CODING_ITU; \ + (IE).h.act = UNI_IEACT_DEFAULT; \ + (IE).epref = EPREF; \ + (IE).flag = FLAG; \ + } while(0) + +#define MK_IE_EPSTATE(IE,STATE) \ + do { \ + (IE).h.present = 0; \ + IE_SETPRESENT(IE); \ + (IE).h.coding = UNI_CODING_ITU; \ + (IE).h.act = UNI_IEACT_DEFAULT; \ + (IE).state = STATE; \ + } while(0) + +#define MK_IE_CAUSE(IE,LOC,CAUSE) \ + do { \ + (IE).h.present = 0; \ + IE_SETPRESENT(IE); \ + (IE).h.coding = UNI_CODING_ITU; \ + (IE).h.act = UNI_IEACT_DEFAULT; \ + (IE).loc = LOC; \ + (IE).cause = CAUSE; \ + } while(0) + +#define ADD_CAUSE_MTYPE(IE,MTYPE) \ + do { \ + (IE).h.present |= UNI_CAUSE_MTYPE_P; \ + (IE).u.mtype = MTYPE; \ + } while(0) + +#define ADD_CAUSE_CHANNID(IE,VPI,VCI) \ + do { \ + (IE).h.present |= UNI_CAUSE_VPCI_P; \ + (IE).u.vpci.vpci = VPI; \ + (IE).u.vpci.vci = VCI; \ + } while(0) + +#define ADD_CAUSE_TIMER(IE,TIMER) \ + do { \ + (IE).h.present |= UNI_CAUSE_TIMER_P; \ + (IE).u.timer[0] = (TIMER)[0]; \ + (IE).u.timer[1] = (TIMER)[1]; \ + (IE).u.timer[2] = (TIMER)[2]; \ + } while(0) + +/************************************************************/ + +#define COPY_FROM_RELEASE_COMPL(U,DEST) \ + do { \ + u_int _i, _j; \ + \ + for(_i = _j = 0; _i < 2; _i++) \ + if(IE_ISGOOD((U)->u.release_compl.cause[_i])) \ + (DEST)->cause[_j++] = \ + (U)->u.release_compl.cause[_i]; \ + for(_i = _j = 0; _i < UNI_NUM_IE_GIT; _i++) \ + if(IE_ISGOOD((U)->u.release_compl.git[_i])) \ + (DEST)->git[_j++] = \ + (U)->u.release_compl.git[_i]; \ + if(IE_ISGOOD((U)->u.release_compl.uu)) \ + (DEST)->uu = (U)->u.release_compl.uu; \ + if(IE_ISGOOD((U)->u.release_compl.crankback)) \ + (DEST)->crankback = (U)->u.release_compl.crankback; \ + } while(0) + +#define COPY_FROM_DROP_ACK(U,DEST) \ + do { \ + u_int _i, _j; \ + \ + if(IE_ISGOOD((U)->u.drop_party_ack.epref)) \ + (DEST)->epref = (U)->u.drop_party_ack.epref; \ + if(IE_ISGOOD((U)->u.drop_party_ack.cause)) \ + (DEST)->cause = (U)->u.drop_party_ack.cause; \ + if(IE_ISGOOD((U)->u.drop_party_ack.uu)) \ + (DEST)->uu = (U)->u.drop_party_ack.uu; \ + for(_i = _j = 0; _i < UNI_NUM_IE_GIT; _i++) \ + if(IE_ISGOOD((U)->u.drop_party_ack.git[_i])) \ + (DEST)->git[_j++] = \ + (U)->u.drop_party_ack.git[_i]; \ + } while(0) + +#define COPY_FROM_ADD_REJ(U,DEST) \ + do { \ + u_int _i, _j; \ + \ + if(IE_ISGOOD((U)->u.add_party_rej.epref)) \ + (DEST)->epref = (U)->u.add_party_rej.epref; \ + if(IE_ISGOOD((U)->u.add_party_rej.cause)) \ + (DEST)->cause = (U)->u.add_party_rej.cause; \ + if(IE_ISGOOD((U)->u.add_party_rej.uu)) \ + (DEST)->uu = (U)->u.add_party_rej.uu; \ + for(_i = _j = 0; _i < UNI_NUM_IE_GIT; _i++) \ + if(IE_ISGOOD((U)->u.add_party_rej.git[_i])) \ + (DEST)->git[_j++] = \ + (U)->u.add_party_rej.git[_i]; \ + } while(0) diff --git a/sys/contrib/ngatm/netnatm/sig/unimsgcpy.h b/sys/contrib/ngatm/netnatm/sig/unimsgcpy.h new file mode 100644 index 000000000000..70e4e2eeb8b4 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/unimsgcpy.h @@ -0,0 +1,113 @@ +/* This file was created automatically + * Source file: $Begemot: libunimsg/atm/msg/msg.def,v 1.3 2003/09/19 11:58:15 hbb Exp $ + * $FreeBSD$ + */ + + +void +copy_msg_alerting(struct uni_alerting *src, struct uni_alerting *dst); + + +void +copy_msg_call_proc(struct uni_call_proc *src, struct uni_call_proc *dst); + + +void +copy_msg_connect(struct uni_connect *src, struct uni_connect *dst); + + +void +copy_msg_connect_ack(struct uni_connect_ack *src, struct uni_connect_ack *dst); + + +void +copy_msg_release(struct uni_release *src, struct uni_release *dst); + + +void +copy_msg_release_compl(struct uni_release_compl *src, struct uni_release_compl *dst); + + +void +copy_msg_setup(struct uni_setup *src, struct uni_setup *dst); + + +void +copy_msg_status(struct uni_status *src, struct uni_status *dst); + + +void +copy_msg_status_enq(struct uni_status_enq *src, struct uni_status_enq *dst); + + +void +copy_msg_notify(struct uni_notify *src, struct uni_notify *dst); + + +void +copy_msg_restart(struct uni_restart *src, struct uni_restart *dst); + + +void +copy_msg_restart_ack(struct uni_restart_ack *src, struct uni_restart_ack *dst); + + +void +copy_msg_add_party(struct uni_add_party *src, struct uni_add_party *dst); + + +void +copy_msg_add_party_ack(struct uni_add_party_ack *src, struct uni_add_party_ack *dst); + + +void +copy_msg_party_alerting(struct uni_party_alerting *src, struct uni_party_alerting *dst); + + +void +copy_msg_add_party_rej(struct uni_add_party_rej *src, struct uni_add_party_rej *dst); + + +void +copy_msg_drop_party(struct uni_drop_party *src, struct uni_drop_party *dst); + + +void +copy_msg_drop_party_ack(struct uni_drop_party_ack *src, struct uni_drop_party_ack *dst); + + +void +copy_msg_leaf_setup_req(struct uni_leaf_setup_req *src, struct uni_leaf_setup_req *dst); + + +void +copy_msg_leaf_setup_fail(struct uni_leaf_setup_fail *src, struct uni_leaf_setup_fail *dst); + + +void +copy_msg_cobisetup(struct uni_cobisetup *src, struct uni_cobisetup *dst); + + +void +copy_msg_facility(struct uni_facility *src, struct uni_facility *dst); + + +void +copy_msg_modify_req(struct uni_modify_req *src, struct uni_modify_req *dst); + + +void +copy_msg_modify_ack(struct uni_modify_ack *src, struct uni_modify_ack *dst); + + +void +copy_msg_modify_rej(struct uni_modify_rej *src, struct uni_modify_rej *dst); + + +void +copy_msg_conn_avail(struct uni_conn_avail *src, struct uni_conn_avail *dst); + + +void +copy_msg_unknown(struct uni_unknown *src, struct uni_unknown *dst); + diff --git a/sys/contrib/ngatm/netnatm/sig/unipriv.h b/sys/contrib/ngatm/netnatm/sig/unipriv.h new file mode 100644 index 000000000000..35dc408b9fde --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/unipriv.h @@ -0,0 +1,563 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/sig/unipriv.h,v 1.17 2004/07/08 08:22:25 brandt Exp $ + * + * Private UNI stuff. + */ +#ifndef unipriv_h +#define unipriv_h + +#ifdef _KERNEL +#ifdef __FreeBSD__ +#include <netgraph/atm/uni/ng_uni_cust.h> +#endif +#else +#include "unicust.h" +#endif + +struct call; +struct party; + +enum cu_stat { + CU_STAT0, /* AAL connection released */ + CU_STAT1, /* awaiting establish */ + CU_STAT2, /* awaiting release */ + CU_STAT3, /* AAL connection established */ +}; + +/* + * Internal Signals + */ +#define DEF_COORD_SIGS \ + DEF_PRIV_SIG(O_SAAL_ESTABLISH_indication, SAAL) \ + DEF_PRIV_SIG(O_SAAL_ESTABLISH_confirm, SAAL) \ + DEF_PRIV_SIG(O_SAAL_RELEASE_indication, SAAL) \ + DEF_PRIV_SIG(O_SAAL_RELEASE_confirm, SAAL) \ + DEF_PRIV_SIG(O_SAAL_DATA_indication, SAAL) \ + DEF_PRIV_SIG(O_SAAL_UDATA_indication, SAAL) \ + DEF_PRIV_SIG(O_T309, Coord) \ + DEF_PRIV_SIG(O_DATA, Coord) \ + DEF_PRIV_SIG(O_LINK_ESTABLISH_request, API) \ + DEF_PRIV_SIG(O_LINK_RELEASE_request, API) \ + DEF_PRIV_SIG(O_RESET_request, API) \ + DEF_PRIV_SIG(O_RESET_response, API) \ + DEF_PRIV_SIG(O_RESET_ERROR_response, API) \ + DEF_PRIV_SIG(O_SETUP_request, API) \ + DEF_PRIV_SIG(O_SETUP_response, API) \ + DEF_PRIV_SIG(O_SETUP_COMPLETE_request, API) \ + DEF_PRIV_SIG(O_PROCEEDING_request, API) \ + DEF_PRIV_SIG(O_ALERTING_request, API) \ + DEF_PRIV_SIG(O_RELEASE_request, API) \ + DEF_PRIV_SIG(O_RELEASE_response, API) \ + DEF_PRIV_SIG(O_NOTIFY_request, API) \ + DEF_PRIV_SIG(O_STATUS_ENQUIRY_request, API) \ + DEF_PRIV_SIG(O_ADD_PARTY_request, API) \ + DEF_PRIV_SIG(O_PARTY_ALERTING_request, API) \ + DEF_PRIV_SIG(O_ADD_PARTY_ACK_request, API) \ + DEF_PRIV_SIG(O_ADD_PARTY_REJ_request, API) \ + DEF_PRIV_SIG(O_DROP_PARTY_request, API) \ + DEF_PRIV_SIG(O_DROP_PARTY_ACK_request, API) \ + DEF_PRIV_SIG(O_ABORT_CALL_request, API) \ + DEF_PRIV_SIG(O_CALL_DESTROYED, CallControl) \ + DEF_PRIV_SIG(O_RESET_indication, ResetRespond) \ + DEF_PRIV_SIG(O_END, Coord) + +#define DEF_RESPOND_SIGS \ + DEF_PRIV_SIG(R_RESTART, Coord) \ + DEF_PRIV_SIG(R_STATUS, Coord) \ + DEF_PRIV_SIG(R_RESET_response, Coord) \ + DEF_PRIV_SIG(R_RESET_ERROR_response, Coord) \ + DEF_PRIV_SIG(R_T317, ResetRespond) \ + DEF_PRIV_SIG(R_END, ResetRespond) + +#define DEF_START_SIGS \ + DEF_PRIV_SIG(S_RESTART_ACK, Coord) \ + DEF_PRIV_SIG(S_STATUS, Coord) \ + DEF_PRIV_SIG(S_RESET_request, Coord) \ + DEF_PRIV_SIG(S_T316, ResetStart) \ + DEF_PRIV_SIG(S_END, ResetStart) + +#define DEF_CALL_SIGS \ + DEF_PRIV_SIG(C_LINK_ESTABLISH_confirm, Coord) \ + DEF_PRIV_SIG(C_LINK_ESTABLISH_indication, Coord) \ + DEF_PRIV_SIG(C_LINK_ESTABLISH_ERROR_indication,Coord) \ + DEF_PRIV_SIG(C_LINK_RELEASE_indication, Coord) \ + DEF_PRIV_SIG(C_SETUP_request, Coord) \ + DEF_PRIV_SIG(C_SETUP_response, Coord) \ + DEF_PRIV_SIG(C_SETUP_COMPLETE_request, Coord) \ + DEF_PRIV_SIG(C_PROCEEDING_request, Coord) \ + DEF_PRIV_SIG(C_ALERTING_request, Coord) \ + DEF_PRIV_SIG(C_RELEASE_request, Coord) \ + DEF_PRIV_SIG(C_RELEASE_response, Coord) \ + DEF_PRIV_SIG(C_NOTIFY_request, Coord) \ + DEF_PRIV_SIG(C_STATUS_ENQUIRY_request, Coord) \ + DEF_PRIV_SIG(C_ADD_PARTY_request, Coord) \ + DEF_PRIV_SIG(C_PARTY_ALERTING_request, Coord) \ + DEF_PRIV_SIG(C_ADD_PARTY_ACK_request, Coord) \ + DEF_PRIV_SIG(C_ADD_PARTY_REJ_request, Coord) \ + DEF_PRIV_SIG(C_DROP_PARTY_request, Coord) \ + DEF_PRIV_SIG(C_DROP_PARTY_ACK_request, Coord) \ + DEF_PRIV_SIG(C_ABORT_CALL_request, Coord) \ + DEF_PRIV_SIG(C_UNKNOWN, Coord) \ + DEF_PRIV_SIG(C_SETUP, Coord) \ + DEF_PRIV_SIG(C_CALL_PROC, Coord) \ + DEF_PRIV_SIG(C_ALERTING, Coord) \ + DEF_PRIV_SIG(C_CONNECT, Coord) \ + DEF_PRIV_SIG(C_CONNECT_ACK, Coord) \ + DEF_PRIV_SIG(C_RELEASE, Coord) \ + DEF_PRIV_SIG(C_RELEASE_COMPL, Coord) \ + DEF_PRIV_SIG(C_COBISETUP, Coord) \ + DEF_PRIV_SIG(C_NOTIFY, Coord) \ + DEF_PRIV_SIG(C_STATUS, Coord) \ + DEF_PRIV_SIG(C_STATUS_ENQ, Coord) \ + DEF_PRIV_SIG(C_ADD_PARTY, Coord) \ + DEF_PRIV_SIG(C_PARTY_ALERTING, Coord) \ + DEF_PRIV_SIG(C_ADD_PARTY_ACK, Coord) \ + DEF_PRIV_SIG(C_ADD_PARTY_REJ, Coord) \ + DEF_PRIV_SIG(C_DROP_PARTY, Coord) \ + DEF_PRIV_SIG(C_DROP_PARTY_ACK, Coord) \ + DEF_PRIV_SIG(C_CALL_DELETE, CallControl) \ + DEF_PRIV_SIG(C_T301, CallControl) \ + DEF_PRIV_SIG(C_T303, CallControl) \ + DEF_PRIV_SIG(C_T308, CallControl) \ + DEF_PRIV_SIG(C_T310, CallControl) \ + DEF_PRIV_SIG(C_T313, CallControl) \ + DEF_PRIV_SIG(C_T322, CallControl) \ + DEF_PRIV_SIG(C_DROP_PARTY_indication, PartyControl) \ + DEF_PRIV_SIG(C_SEND_DROP_PARTY, PartyControl) \ + DEF_PRIV_SIG(C_DROP_PARTY_ACK_indication, PartyControl) \ + DEF_PRIV_SIG(C_SEND_DROP_PARTY_ACK, PartyControl) \ + DEF_PRIV_SIG(C_ADD_PARTY_REJ_indication, PartyControl) \ + DEF_PRIV_SIG(C_SEND_ADD_PARTY_REJ, PartyControl) \ + DEF_PRIV_SIG(C_SEND_STATUS_ENQ, PartyControl) \ + DEF_PRIV_SIG(C_PARTY_DESTROYED, PartyControl) \ + DEF_PRIV_SIG(C_END, CallControl) + +#define DEF_PARTY_SIGS \ + DEF_PRIV_SIG(P_SETUP, CallControl) \ + DEF_PRIV_SIG(P_ALERTING, CallControl) \ + DEF_PRIV_SIG(P_CONNECT, CallControl) \ + DEF_PRIV_SIG(P_CONNECT_ACK, CallControl) \ + DEF_PRIV_SIG(P_RELEASE, CallControl) \ + DEF_PRIV_SIG(P_RELEASE_COMPL, CallControl) \ + DEF_PRIV_SIG(P_STATUS, CallControl) \ + DEF_PRIV_SIG(P_ADD_PARTY, CallControl) \ + DEF_PRIV_SIG(P_PARTY_ALERTING, CallControl) \ + DEF_PRIV_SIG(P_ADD_PARTY_ACK, CallControl) \ + DEF_PRIV_SIG(P_ADD_PARTY_REJ, CallControl) \ + DEF_PRIV_SIG(P_DROP_PARTY, CallControl) \ + DEF_PRIV_SIG(P_DROP_PARTY_ACK, CallControl) \ + DEF_PRIV_SIG(P_SETUP_request, CallControl) \ + DEF_PRIV_SIG(P_SETUP_response, CallControl) \ + DEF_PRIV_SIG(P_SETUP_COMPL_request, CallControl) \ + DEF_PRIV_SIG(P_ALERTING_request, CallControl) \ + DEF_PRIV_SIG(P_RELEASE_request, CallControl) \ + DEF_PRIV_SIG(P_RELEASE_response, CallControl) \ + DEF_PRIV_SIG(P_RELEASE_confirm, CallControl) \ + DEF_PRIV_SIG(P_STATUS_ENQUIRY_request, CallControl) \ + DEF_PRIV_SIG(P_ADD_PARTY_request, CallControl) \ + DEF_PRIV_SIG(P_PARTY_ALERTING_request, CallControl) \ + DEF_PRIV_SIG(P_ADD_PARTY_ACK_request, CallControl) \ + DEF_PRIV_SIG(P_ADD_PARTY_REJ_request, CallControl) \ + DEF_PRIV_SIG(P_DROP_PARTY_request, CallControl) \ + DEF_PRIV_SIG(P_DROP_PARTY_ACK_request, CallControl) \ + DEF_PRIV_SIG(P_PARTY_DELETE, PartyControl) \ + DEF_PRIV_SIG(P_T397, PartyControl) \ + DEF_PRIV_SIG(P_T398, PartyControl) \ + DEF_PRIV_SIG(P_T399, PartyControl) \ + DEF_PRIV_SIG(P_END, PartyControl) + + +#define DEF_PRIV_SIG(NAME, FROM) SIG##NAME, +enum coord_sig { + DEF_COORD_SIGS +}; +enum respond_sig { + DEF_RESPOND_SIGS +}; +enum start_sig { + DEF_START_SIGS +}; +enum call_sig { + DEF_CALL_SIGS +}; +enum party_sig { + DEF_PARTY_SIGS +}; +#undef DEF_PRIV_SIG + +/************************************************************* + * + * SIGNALS and SIGNAL QUEUES + */ +enum { + SIG_COORD, + SIG_RESET_START, + SIG_RESET_RESP, + SIG_CALL, + SIG_PARTY, +}; + +struct sig { + TAILQ_ENTRY(sig) link; + u_int type; /* one of the above */ + struct call *call; /* call to send to */ + struct party *party; /* party to send to */ + uint32_t sig; /* the signal */ + uint32_t cookie; /* user cookie */ + struct uni_msg *msg; /* attached message */ + struct uni_all *u; /* dito */ +}; +TAILQ_HEAD(sigqueue, sig); + +#define SIGQ_CLEAR(Q) \ + do { \ + struct sig *s; \ + while(!TAILQ_EMPTY(Q)) { \ + s = TAILQ_FIRST(Q); \ + TAILQ_REMOVE(Q, s, link); \ + if(s->msg) uni_msg_destroy(s->msg); \ + if(s->u) UNI_FREE(s->u); \ + SIG_FREE(s); \ + } \ + } while(0) + +void uni_sig_party(struct party *, enum party_sig, uint32_t cookie, + struct uni_msg *, struct uni_all *); +void uni_sig_call(struct call *, enum call_sig, uint32_t cookie, + struct uni_msg *, struct uni_all *); +void uni_sig_coord(struct uni *, enum coord_sig, uint32_t cookie, + struct uni_msg *); +void uni_sig_start(struct uni *, enum start_sig, uint32_t cookie, + struct uni_msg *, struct uni_all *); +void uni_sig_respond(struct uni *, enum respond_sig, uint32_t cookie, + struct uni_msg *, struct uni_all *); + +/************************************************************* + * + * CALL INSTANCES + */ +struct party { + struct call *call; + TAILQ_ENTRY(party) link; + u_int epref; /* endpoint reference */ + u_int flags; /* flags */ + enum uni_epstate state; /* party state */ + + struct uni_timer t397; /* T397 */ + struct uni_timer t398; /* T398 */ + struct uni_timer t399; /* T399 */ +}; +#define PARTY_MINE 0x0001 /* must be 1 */ +#define PARTY_CONNECT 0x0002 /* connect request from this party */ + +TAILQ_HEAD(partyqueue, party); + +void uni_destroy_party(struct party *, int); +struct party *uni_find_party(struct call *, struct uni_ie_epref *); +struct party *uni_find_partyx(struct call *, u_int epref, u_int mine); +struct party *uni_create_party(struct call *, struct uni_ie_epref *); +struct party *uni_create_partyx(struct call *, u_int epref, u_int mine, + uint32_t cookie); +u_int uni_party_act_count(struct call *, int); + +enum call_type { + CALL_NULL, /* not known yet */ + CALL_P2P, /* normal point-to-point call */ + CALL_COBI, /* Q.2932.1 COBI call */ + CALL_ROOT, /* point-to-multipoint root */ + CALL_LEAF, /* point-to-multipoint leaf */ +}; + +enum call_state { + CALLST_NULL, + CALLST_U1, CALLST_U3, CALLST_U4, CALLST_U6, CALLST_U7, CALLST_U8, + CALLST_U9, CALLST_U10, CALLST_U11, CALLST_U12, + CALLST_N1, CALLST_N3, CALLST_N4, CALLST_N6, CALLST_N7, CALLST_N8, + CALLST_N9, CALLST_N10, CALLST_N11, CALLST_N12 +}; + +struct call { + TAILQ_ENTRY(call) link; /* link between calls */ + struct uni *uni; /* backpointer to owning UNI */ + u_int cref; /* call reference value or lij seqno */ + u_int mine; /* if TRUE this is my call */ + enum call_type type; /* what call is it */ + enum call_state cstate; /* the state of the call */ + struct uni_ie_connid connid; /* the connection ID */ + struct uni_setup msg_setup; /* retransmission */ + struct uni_release msg_release; /* retransmission */ + struct uni_ie_epref stat_epref; /* retransmission */ + struct partyqueue parties; + u_int se_active; /* status enquiry active */ + u_int epref_alloc; + + struct uni_timer t308; /* T303 */ + u_int cnt308; + + struct uni_timer t303; /* T303 */ + u_int cnt303; + + struct uni_timer t301; /* T301 */ + struct uni_timer t310; /* T310 */ + struct uni_timer t313; /* T313 */ + + struct uni_timer t322; /* T322 */ + u_int cnt322; +}; + +TAILQ_HEAD(callqueue, call); + +struct call *uni_find_call(struct uni *, struct uni_cref *); +struct call *uni_find_callx(struct uni *, u_int cref, u_int mine); +struct call *uni_create_call(struct uni *, u_int cref, u_int mine, + uint32_t cookie); +struct call *uni_create_new_call(struct uni *, uint32_t cookie); +void uni_destroy_call(struct call *, int); + +void uni_bad_message(struct call *, struct uni_all *, u_int, + struct uni_ie_epref *, int); + +extern const struct callstates { + const char *name; + enum uni_callstate ext; +} callstates[]; + +/************************************************************* + * + * UNI INSTANCE + */ +struct uni { + void *arg; /* user arg */ + const struct uni_funcs *funcs; + + enum uni_proto proto; /* protocol */ + struct unicx cx; /* decoding/coding context */ + int sb_tb : 1; /* Sb-Tb/Tb point */ + + struct sigqueue workq; /* work queue */ + struct sigqueue delq; /* delayed signal queue */ + int working; + + uint32_t cref_alloc; + + enum cu_stat custat; /* coordinator state */ + struct uni_timer t309; + u_int timer309; + + enum uni_callstate glob_start; + enum uni_callstate glob_respond; + struct uni_timer t316; + struct uni_timer t317; + struct uni_ie_connid connid_start; + struct uni_ie_connid connid_respond; + u_int cnt316; + struct uni_ie_restart restart_start; + + struct callqueue calls; + + struct uni_ie_cause cause; /* working area for verify */ + + /* tuneable parameters */ + u_int timer301; + u_int init303; + u_int timer303; + u_int init308; + u_int timer308; + u_int timer310; + u_int timer313; + u_int init316; + u_int timer316; + u_int timer317; + u_int timer322; + u_int init322; + u_int timer397; + u_int timer398; + u_int timer399; + + u_int debug[UNI_MAXFACILITY]; +}; + +void uniapi_uni_error(struct uni *uni, uint32_t reason, uint32_t cookie, + uint32_t state); +void uniapi_call_error(struct call *c, uint32_t reason, uint32_t cookie); +void uniapi_party_error(struct party *p, uint32_t reason, uint32_t cookie); + +/************************************************************* + * + * INLINE FUNCTIONS + */ + +/* Enqueue a signal in the working queue */ +void uni_enq_sig(struct uni *, u_int, struct call *, struct party *, + uint32_t, uint32_t, struct uni_msg *, struct uni_all *); + +/* Enqueue a signal in the delayed queue */ +void uni_delenq_sig(struct uni *, u_int, struct call *, struct party *, + uint32_t, uint32_t, struct uni_msg *, struct uni_all *); + +/* Enqueue a signal to the coordinator */ +#define uni_enq_coord(UNI, SIG, COOKIE, MSG) do { \ + uni_enq_sig((UNI), SIG_COORD, NULL, NULL, \ + (SIG), (COOKIE), (MSG), NULL); \ + } while (0) + +/* Enqueue a delayed signal to the coordinator */ +#define uni_delenq_coord(UNI, SIG, COOKIE, MSG) do { \ + uni_delenq_sig((UNI), SIG_COORD, NULL, NULL, \ + (SIG), (COOKIE), (MSG), NULL); \ + } while (0) + +/* Enqueue a signal to a call */ +#define uni_enq_call(CALL, SIG, COOKIE, MSG, U) do { \ + uni_enq_sig((CALL)->uni, SIG_CALL, (CALL), NULL, \ + (SIG), (COOKIE), (MSG), (U)); \ + } while (0) + +/* Enqueue a signal to a party */ +#define uni_enq_party(PARTY, SIG, COOKIE, MSG, U) do { \ + uni_enq_sig((PARTY)->call->uni, SIG_PARTY, (PARTY)->call, \ + (PARTY), (SIG), (COOKIE), (MSG), (U)); \ + } while (0) + +/* Enqueue a signal to RESET-START */ +#define uni_enq_start(UNI, SIG, COOKIE, MSG, U) do { \ + uni_enq_sig((UNI), SIG_RESET_START, NULL, NULL, \ + (SIG), (COOKIE), (MSG), (U)); \ + } while (0) + +/* Enqueue a signal to RESET-RESPOND */ +#define uni_enq_resp(UNI, SIG, COOKIE, MSG, U) do { \ + uni_enq_sig((UNI), SIG_RESET_RESP, NULL, NULL, \ + (SIG), (COOKIE), (MSG), (U)); \ + } while (0) + +int uni_send_output(struct uni_all *u, struct uni *uni); +void uni_undel(struct uni *, int (*)(struct sig *, void *), void *); +void uni_delsig(struct uni *, u_int, struct call *, struct party *); + +void uni_release_compl(struct call *, struct uni_all *); + +/*************************************************************/ +/* + * Message verification. + */ +#define MANDATE_IE(UNI,MSG,IE) \ + do { \ + if (!IE_ISGOOD(MSG)) \ + uni_mandate_ie(UNI, IE); \ + } while(0) + +enum verify { + VFY_OK, /* ok */ + VFY_RAP, /* report and proceed */ + VFY_RAPU, /* report and proceed becuase of unknown IEs */ + VFY_I, /* ignore */ + VFY_CLR, /* clear call */ + VFY_RAI, /* report and ignore */ + VFY_RAIM, /* report and ignore because if mandat. IE miss */ +}; + +void uni_mandate_ie(struct uni *, enum uni_ietype); +void uni_mandate_epref(struct uni *, struct uni_ie_epref *); +enum verify uni_verify(struct uni *, enum uni_msgact); +void uni_respond_status_verify(struct uni *, struct uni_cref *, + enum uni_callstate, struct uni_ie_epref *, enum uni_epstate); +void uni_vfy_remove_unknown(struct uni *); +void uni_vfy_remove_cause(struct uni *); +void uni_vfy_collect_ies(struct uni *); + + +void uni_respond_status(struct uni *uni, struct uni_cref *cref, + enum uni_callstate cs, enum uni_cause c1); +void uni_respond_status_mtype(struct uni *uni, struct uni_cref *cref, + enum uni_callstate cs, enum uni_cause c1, u_int mtype); + +#define FOREACH_ERR(E, UNI) \ + for ((E) = (UNI)->cx.err; (E) < (UNI)->cx.err + (UNI)->cx.errcnt; (E)++) + +#define ALLOC_API(TYPE,API) \ + ({ \ + TYPE *_tmp = NULL; \ + \ + if(((API) = uni_msg_alloc(sizeof(TYPE))) != NULL) { \ + _tmp = uni_msg_wptr((API), TYPE *); \ + (API)->b_wptr += sizeof(TYPE); \ + memset(_tmp, 0, sizeof(TYPE)); \ + } \ + _tmp; \ + }) + +#if defined(__GNUC__) && __GNUC__ < 3 + +#define VERBOSE(UNI, FAC, LEVEL, ARGS...) do { \ + if ((UNI)->debug[(FAC)] >= (LEVEL)) { \ + (UNI)->funcs->verbose((UNI), (UNI)->arg, (FAC) ,\ + ## ARGS); \ + } \ + } while(0) + +#define VERBOSE0(UNI, FAC, ARGS...) do { \ + (UNI)->funcs->verbose((UNI), (UNI)->arg, (FAC) , \ + ## ARGS); \ + } while(0) + +#else + +#define VERBOSE(UNI, FAC, LEVEL, ...) do { \ + if ((UNI)->debug[(FAC)] >= (LEVEL)) { \ + (UNI)->funcs->verbose((UNI), (UNI)->arg, (FAC), \ + __VA_ARGS__); \ + } \ + } while(0) + +#define VERBOSE0(UNI, FAC, ...) do { \ + (UNI)->funcs->verbose((UNI), (UNI)->arg, (FAC), \ + __VA_ARGS__); \ + } while(0) + +#endif + +#define TIMER_INIT_UNI(U,T) _TIMER_INIT(U,T) +#define TIMER_INIT_CALL(C,T) _TIMER_INIT(C,T) +#define TIMER_INIT_PARTY(P,T) _TIMER_INIT(P,T) + +#define TIMER_DESTROY_UNI(U,T) _TIMER_DESTROY(U, (U)->T) +#define TIMER_DESTROY_CALL(C,T) _TIMER_DESTROY((C)->uni, (C)->T) +#define TIMER_DESTROY_PARTY(P,T) _TIMER_DESTROY((P)->call->uni, (P)->T) + +#define TIMER_STOP_UNI(U,T) _TIMER_STOP(U, (U)->T) +#define TIMER_STOP_CALL(C,T) _TIMER_STOP((C)->uni, (C)->T) +#define TIMER_STOP_PARTY(P,T) _TIMER_STOP((P)->call->uni, (P)->T) + +#define TIMER_START_UNI(U,T,N) _TIMER_START(U, U, (U)->T, N, _##T##_func) +#define TIMER_START_CALL(C,T,N) _TIMER_START(C->uni, C, (C)->T, N, _##T##_func) +#define TIMER_START_PARTY(P,T,N) _TIMER_START(P->call->uni, P, (P)->T, N, _##T##_func) + +#endif diff --git a/sys/contrib/ngatm/netnatm/sig/unisig.h b/sys/contrib/ngatm/netnatm/sig/unisig.h new file mode 100644 index 000000000000..22ff671d2922 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/unisig.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/netnatm/sig/unisig.h,v 1.4 2004/07/08 08:22:26 brandt Exp $ + * + * Utility functions for signalling stuff + */ +#ifndef _NETNATM_SIG_UNISIG_H_ +#define _NETNATM_SIG_UNISIG_H_ + +#include <netnatm/sig/unidef.h> + +/* names */ +const char *uni_signame(enum uni_sig); +const char *uni_facname(enum uni_verb); + +/* return a string for the error code */ +const char *uni_strerr(u_int _err); + +/* format an API message */ +void uni_print_api(char *_buf, size_t _bufsiz, u_int _type, u_int _cookie, + const void *_msg, struct unicx *_cx); + +#endif diff --git a/sys/contrib/ngatm/netnatm/unimsg.h b/sys/contrib/ngatm/netnatm/unimsg.h new file mode 100644 index 000000000000..efc91c57a81f --- /dev/null +++ b/sys/contrib/ngatm/netnatm/unimsg.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * Redistribution 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 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 IS PROVIDED BY THE AUTHOR AND 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 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/unimsg.h,v 1.4 2004/07/08 08:21:46 brandt Exp $ + * + * This defines the structure of messages as handled by this library. + */ +#ifndef _NETNATM_UNIMSG_H_ +#define _NETNATM_UNIMSG_H_ + +#include <sys/types.h> +#ifdef _KERNEL +#ifdef __FreeBSD__ +#include <sys/systm.h> +#endif +#include <sys/stdint.h> +#else +#include <string.h> +#include <stdint.h> +#endif + +struct uni_msg { + u_char *b_wptr; /* tail pointer */ + u_char *b_rptr; /* head pointer */ + u_char *b_buf; /* data buffer */ + u_char *b_lim; /* end of data buffer */ +}; + +/* return the current length of the message */ +#define uni_msg_len(M) ((size_t)((M)->b_wptr - (M)->b_rptr)) + +/* return the number of space behind the message */ +#define uni_msg_space(M) ((size_t)((M)->b_lim - (M)->b_wptr)) + +/* return the amount of leading free space */ +#define uni_msg_leading(M) ((size_t)((M)->b_rptr - (M)->b_buf)) + +/* return the maximum size of the message (length plus free space) */ +#define uni_msg_size(M) ((size_t)((M)->b_lim - (M)->b_buf)); + +/* ensure that there is space for another S bytes. If reallocation fails + * free message and return -1 */ +#define uni_msg_ensure(M, S) \ + ((uni_msg_space(M) >= (S)) ? 0 : uni_msg_extend(M, S)) + +int uni_msg_append(struct uni_msg *, void *, size_t); +int uni_msg_extend(struct uni_msg *, size_t); + +#define uni_msg_rptr(MSG, TYPE) ((TYPE)(void *)(MSG)->b_rptr) +#define uni_msg_wptr(MSG, TYPE) ((TYPE)(void *)(MSG)->b_wptr) + +int uni_msg_prepend(struct uni_msg *, size_t); + +#ifndef _KERNEL + +struct uni_msg *uni_msg_alloc(size_t); +struct uni_msg *uni_msg_build(void *, ...); +void uni_msg_destroy(struct uni_msg *); +u_int uni_msg_strip32(struct uni_msg *); +u_int uni_msg_get32(struct uni_msg *); +int uni_msg_append32(struct uni_msg *, u_int); +int uni_msg_append8(struct uni_msg *, u_int); +u_int uni_msg_trail32(const struct uni_msg *, int); +struct uni_msg *uni_msg_dup(const struct uni_msg *); + +#endif /* _KERNEL */ +#endif |