freebsd-dev/sys/netatm/uni/unisig_msg.c
2005-01-07 01:45:51 +00:00

1011 lines
21 KiB
C

/*-
* ===================================
* HARP | Host ATM Research Platform
* ===================================
*
*
* This Host ATM Research Platform ("HARP") file (the "Software") is
* made available by Network Computing Services, Inc. ("NetworkCS")
* "AS IS". NetworkCS does not provide maintenance, improvements or
* support of any kind.
*
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
* In no event shall NetworkCS be responsible for any damages, including
* but not limited to consequential damages, arising from or relating to
* any use of the Software or related support.
*
* Copyright 1994-1998 Network Computing Services, Inc.
*
* Copies of this Software may be made, however, the above copyright
* notice must be reproduced on all copies.
*/
/*
* ATM Forum UNI 3.0/3.1 Signalling Manager
* ----------------------------------------
*
* Message handling module
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <netatm/port.h>
#include <netatm/queue.h>
#include <netatm/atm.h>
#include <netatm/atm_sys.h>
#include <netatm/atm_sap.h>
#include <netatm/atm_cm.h>
#include <netatm/atm_if.h>
#include <netatm/atm_vc.h>
#include <netatm/atm_sigmgr.h>
#include <netatm/atm_stack.h>
#include <netatm/atm_pcb.h>
#include <netatm/atm_var.h>
#include <netatm/uni/unisig_var.h>
#include <netatm/uni/unisig_msg.h>
#include <netatm/uni/unisig_mbuf.h>
#include <netatm/uni/unisig_print.h>
#include <vm/uma.h>
/*
* Local functions
*/
static void unisig_rcv_restart(struct unisig *, struct unisig_msg *);
static void unisig_rcv_setup(struct unisig *, struct unisig_msg *);
/*
* net.harp.uni.unisig_print_msg
*
* 0 - disable
* 1 - dump UNI message
* 2 - dump UNI message + print decoded form
*/
static int unisig_print_msg = 0;
SYSCTL_INT(_net_harp_uni, OID_AUTO, unisig_print_msg, CTLFLAG_RW,
&unisig_print_msg, 0, "dump UNI messages");
/*
* Set a Cause IE based on information in an ATM attribute block
*
* Arguments:
* iep pointer to a cause IE
* aap pointer to attribute block
*
* Returns:
* 0 message sent OK
* errno error encountered
*
*/
void
unisig_cause_from_attr(iep, aap)
struct ie_generic *iep;
Atm_attributes *aap;
{
/*
* Copy cause info from attribute block to IE
*/
iep->ie_ident = UNI_IE_CAUS;
iep->ie_coding = aap->cause.v.coding_standard;
iep->ie_caus_loc = aap->cause.v.location;
iep->ie_caus_cause = aap->cause.v.cause_value;
}
/*
* Set a Cause IE based on information in a UNI signalling message
*
* Arguments:
* iep pointer to a cause IE
* msg pointer to message
* cause cause code for the error
*
* Returns:
* 0 message sent OK
* errno error encountered
*
*/
void
unisig_cause_from_msg(iep, msg, cause)
struct ie_generic *iep;
struct unisig_msg *msg;
int cause;
{
struct ie_generic *ie1;
int i;
/*
* Fill out the cause IE fixed fields
*/
iep->ie_ident = UNI_IE_CAUS;
iep->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
iep->ie_caus_cause = cause;
/*
* Set diagnostics if indicated
*/
switch(cause) {
case UNI_IE_CAUS_IECONTENT:
iep->ie_caus_diag_len = 0;
for (i = 0, ie1 = msg->msg_ie_err;
ie1 && i < UNI_IE_CAUS_MAX_ID;
ie1 = ie1->ie_next) {
if (ie1->ie_err_cause == UNI_IE_CAUS_IECONTENT) {
iep->ie_caus_diagnostic[i] =
ie1->ie_ident;
iep->ie_caus_diag_len++;
i++;
}
}
break;
case UNI_IE_CAUS_REJECT:
iep->ie_caus_diag_len = 2;
iep->ie_caus_diagnostic[0] = UNI_IE_EXT_BIT +
(UNI_IE_CAUS_RR_USER << UNI_IE_CAUS_RR_SHIFT) +
UNI_IE_CAUS_RC_TRANS;
iep->ie_caus_diagnostic[1] = 0;
break;
case UNI_IE_CAUS_MISSING:
iep->ie_caus_diag_len = 0;
for (i = 0, ie1 = msg->msg_ie_err;
ie1 && i < UNI_IE_CAUS_MAX_ID;
ie1 = ie1->ie_next) {
if (ie1->ie_err_cause == UNI_IE_CAUS_MISSING) {
iep->ie_caus_diagnostic[i] =
ie1->ie_ident;
iep->ie_caus_diag_len++;
i++;
}
}
}
}
/*
* Send a UNISIG signalling message
*
* Called to send a Q.2931 message. This routine encodes the message
* and hands it to SSCF for transmission.
*
* Arguments:
* usp pointer to UNISIG protocol instance block
* msg pointer to message
*
* Returns:
* 0 message sent OK
* errno error encountered
*
*/
int
unisig_send_msg(usp, msg)
struct unisig *usp;
struct unisig_msg *msg;
{
int err = 0;
struct usfmt usf;
ATM_DEBUG2("unisig_send_msg: msg=%p, type=%d\n", msg,
msg->msg_type);
/*
* Make sure the network is up
*/
if (usp->us_state != UNISIG_ACTIVE)
return(ENETDOWN);
/*
* Print the message we're sending.
*/
if (unisig_print_msg)
usp_print_msg(msg, UNISIG_MSG_OUT);
/*
* Convert message to network order
*/
err = usf_init(&usf, usp, (KBuffer *) 0, USF_ENCODE,
usp->us_headout);
if (err)
return(err);
err = usf_enc_msg(&usf, msg);
if (err) {
ATM_DEBUG1("unisig_send_msg: encode failed with %d\n",
err);
KB_FREEALL(usf.usf_m_base);
return(EIO);
}
/*
* Print the converted message
*/
if (unisig_print_msg > 1)
unisig_print_mbuf(usf.usf_m_base);
/*
* Send the message
*/
err = atm_cm_saal_data(usp->us_conn, usf.usf_m_base);
if (err)
KB_FREEALL(usf.usf_m_base);
return(err);
}
/*
* Send a SETUP request
*
* Build and send a Q.2931 SETUP message.
*
* Arguments:
* usp pointer to UNISIG protocol instance block
* uvp pointer to VCCB for which the request is being sent
*
* Returns:
* none
*
*/
int
unisig_send_setup(usp, uvp)
struct unisig *usp;
struct unisig_vccb *uvp;
{
int err = 0;
struct unisig_msg *setup;
Atm_attributes *ap = &uvp->uv_connvc->cvc_attr;
ATM_DEBUG1("unisig_send_setup: uvp=%p\n", uvp);
/*
* Make sure required connection attriutes are set
*/
if (ap->aal.tag != T_ATM_PRESENT ||
ap->traffic.tag != T_ATM_PRESENT ||
ap->bearer.tag != T_ATM_PRESENT ||
ap->called.tag != T_ATM_PRESENT ||
ap->qos.tag != T_ATM_PRESENT) {
err = EINVAL;
setup = NULL;
goto done;
}
/*
* Get memory for a SETUP message
*/
setup = uma_zalloc(unisig_msg_zone, M_ZERO | M_NOWAIT);
if (setup == NULL) {
err = ENOMEM;
goto done;
}
/*
* Fill in the SETUP message
*/
if (!uvp->uv_call_ref)
uvp->uv_call_ref = unisig_alloc_call_ref(usp);
setup->msg_call_ref = uvp->uv_call_ref;
setup->msg_type = UNI_MSG_SETU;
/*
* Set IEs from connection attributes
*/
err = unisig_set_attrs(usp, setup, ap);
if (err)
goto done;
/*
* Attach a Calling Party Number IE if the user didn't
* specify one in the attribute block
*/
if (ap->calling.tag != T_ATM_PRESENT) {
setup->msg_ie_cgad = uma_zalloc(unisig_ie_zone, M_NOWAIT);
if (setup->msg_ie_cgad == NULL) {
err = ENOMEM;
goto done;
}
setup->msg_ie_cgad->ie_ident = UNI_IE_CGAD;
ATM_ADDR_COPY(&usp->us_addr,
&setup->msg_ie_cgad->ie_cgad_addr);
ATM_ADDR_SEL_COPY(&usp->us_addr,
uvp->uv_nif ? uvp->uv_nif->nif_sel : 0,
&setup->msg_ie_cgad->ie_cgad_addr);
}
/*
* Send the SETUP message
*/
err = unisig_send_msg(usp, setup);
done:
if (setup)
unisig_free_msg(setup);
return(err);
}
/*
* Send a RELEASE message
*
* Arguments:
* usp pointer to UNISIG protocol instance block
* uvp pointer to VCCB for which the RELEASE is being sent
* msg pointer to UNI signalling message that the RELEASE
* responds to (may be NULL)
* cause the reason for the RELEASE; a value of
* T_ATM_ABSENT indicates that the cause code is
* in the VCC's ATM attributes block
*
* Returns:
* none
*
*/
int
unisig_send_release(usp, uvp, msg, cause)
struct unisig *usp;
struct unisig_vccb *uvp;
struct unisig_msg *msg;
int cause;
{
int err = 0;
struct unisig_msg *rls_msg;
struct ie_generic *cause_ie;
ATM_DEBUG2("unisig_send_release: usp=%p, uvp=%p\n",
usp, uvp);
/*
* Get memory for a RELEASE message
*/
rls_msg = uma_zalloc(unisig_msg_zone, M_ZERO | M_NOWAIT);
if (rls_msg == NULL) {
return(ENOMEM);
}
cause_ie = uma_zalloc(unisig_ie_zone, M_ZERO | M_NOWAIT);
if (cause_ie == NULL) {
uma_zfree(unisig_msg_zone, rls_msg);
return(ENOMEM);
}
/*
* Fill in the RELEASE message
*/
rls_msg->msg_call_ref = uvp->uv_call_ref;
rls_msg->msg_type = UNI_MSG_RLSE;
rls_msg->msg_type_flag = 0;
rls_msg->msg_type_action = 0;
rls_msg->msg_ie_caus = cause_ie;
/*
* Fill out the cause IE
*/
cause_ie->ie_ident = UNI_IE_CAUS;
if (cause == T_ATM_ABSENT) {
unisig_cause_from_attr(cause_ie,
&uvp->uv_connvc->cvc_attr);
} else {
cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
unisig_cause_from_msg(cause_ie, msg, cause);
}
/*
* Send the RELEASE
*/
err = unisig_send_msg(usp, rls_msg);
unisig_free_msg(rls_msg);
return(err);
}
/*
* Send a RELEASE COMPLETE message
*
* Arguments:
* usp pointer to UNISIG protocol instance block
* uvp pointer to VCCB for which the RELEASE is being sent.
* NULL indicates that a VCCB wasn't found for a call
* reference value.
* msg pointer to the message which triggered the send
* cause the cause code for the message; a value of
* T_ATM_ABSENT indicates that the cause code is
* in the VCC's ATM attributes block
*
* Returns:
* 0 success
* errno error encountered
*
*/
int
unisig_send_release_complete(usp, uvp, msg, cause)
struct unisig *usp;
struct unisig_vccb *uvp;
struct unisig_msg *msg;
int cause;
{
int err = 0;
struct unisig_msg *rls_cmp;
struct ie_generic *cause_ie;
ATM_DEBUG4("unisig_send_release_complete usp=%p, uvp=%p, msg=%p, cause=%d\n",
usp, uvp, msg, cause);
/*
* Get memory for a RELEASE COMPLETE message
*/
rls_cmp = uma_zalloc(unisig_msg_zone, M_ZERO | M_NOWAIT);
if (rls_cmp == NULL) {
return(ENOMEM);
}
cause_ie = uma_zalloc(unisig_ie_zone, M_ZERO | M_NOWAIT);
if (cause_ie == NULL) {
uma_zfree(unisig_msg_zone, rls_cmp);
return(ENOMEM);
}
/*
* Fill in the RELEASE COMPLETE message
*/
if (uvp) {
rls_cmp->msg_call_ref = uvp->uv_call_ref;
} else if (msg) {
rls_cmp->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref);
} else {
rls_cmp->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
}
rls_cmp->msg_type = UNI_MSG_RLSC;
rls_cmp->msg_type_flag = 0;
rls_cmp->msg_type_action = 0;
rls_cmp->msg_ie_caus = cause_ie;
/*
* Fill out the cause IE
*/
cause_ie->ie_ident = UNI_IE_CAUS;
if (cause == T_ATM_ABSENT) {
unisig_cause_from_attr(cause_ie,
&uvp->uv_connvc->cvc_attr);
} else {
cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
unisig_cause_from_msg(cause_ie, msg, cause);
}
/*
* Send the RELEASE COMPLETE
*/
err = unisig_send_msg(usp, rls_cmp);
unisig_free_msg(rls_cmp);
return(err);
}
/*
* Send a STATUS message
*
* Arguments:
* usp pointer to UNISIG protocol instance block
* uvp pointer to VCCB for which the STATUS is being sent.
* NULL indicates that a VCCB wasn't found for a call
* reference value.
* msg pointer to the message which triggered the send
* cause the cause code to include in the message
*
* Returns:
* none
*
*/
int
unisig_send_status(usp, uvp, msg, cause)
struct unisig *usp;
struct unisig_vccb *uvp;
struct unisig_msg *msg;
int cause;
{
int err = 0, i;
struct unisig_msg *stat_msg;
struct ie_generic *cause_ie, *clst_ie, *iep;
ATM_DEBUG4("unisig_send_status: usp=%p, uvp=%p, msg=%p, cause=%d\n",
usp, uvp, msg, cause);
/*
* Get memory for a STATUS message
*/
stat_msg = uma_zalloc(unisig_msg_zone, M_ZERO | M_NOWAIT);
if (stat_msg == NULL) {
return(ENOMEM);
}
cause_ie = uma_zalloc(unisig_ie_zone, M_ZERO | M_NOWAIT);
if (cause_ie == NULL) {
uma_zfree(unisig_msg_zone, stat_msg);
return(ENOMEM);
}
clst_ie = uma_zalloc(unisig_ie_zone, M_ZERO | M_NOWAIT);
if (clst_ie == NULL) {
uma_zfree(unisig_msg_zone, stat_msg);
uma_zfree(unisig_ie_zone, cause_ie);
return(ENOMEM);
}
/*
* Fill in the STATUS message
*/
if (uvp) {
stat_msg->msg_call_ref = uvp->uv_call_ref;
} else if (msg) {
stat_msg->msg_call_ref =
EXTRACT_CREF(msg->msg_call_ref);
} else {
stat_msg->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
}
stat_msg->msg_type = UNI_MSG_STAT;
stat_msg->msg_type_flag = 0;
stat_msg->msg_type_action = 0;
stat_msg->msg_ie_clst = clst_ie;
stat_msg->msg_ie_caus = cause_ie;
/*
* Fill out the call state IE
*/
clst_ie->ie_ident = UNI_IE_CLST;
clst_ie->ie_coding = 0;
clst_ie->ie_flag = 0;
clst_ie->ie_action = 0;
if (uvp) {
clst_ie->ie_clst_state = uvp->uv_sstate;
} else {
clst_ie->ie_clst_state = UNI_NULL;
}
/*
* Fill out the cause IE
*/
cause_ie->ie_ident = UNI_IE_CAUS;
cause_ie->ie_coding = 0;
cause_ie->ie_flag = 0;
cause_ie->ie_action = 0;
cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
cause_ie->ie_caus_cause = cause;
switch (cause) {
case UNI_IE_CAUS_MTEXIST:
case UNI_IE_CAUS_STATE:
if (msg) {
cause_ie->ie_caus_diagnostic[0] = msg->msg_type;
}
break;
case UNI_IE_CAUS_MISSING:
case UNI_IE_CAUS_IECONTENT:
case UNI_IE_CAUS_IEEXIST:
for (i=0, iep=msg->msg_ie_err;
iep && i<UNI_MSG_IE_CNT;
i++, iep = iep->ie_next) {
if (iep->ie_err_cause == cause) {
cause_ie->ie_caus_diagnostic[i] =
iep->ie_ident;
}
}
}
/*
* Send the STATUS message
*/
err = unisig_send_msg(usp, stat_msg);
unisig_free_msg(stat_msg);
return(err);
}
/*
* Process a RESTART message
*
* Arguments:
* usp pointer to UNISIG protocol instance block
* msg pointer to the RESTART message
*
* Returns:
* none
*
*/
static void
unisig_rcv_restart(usp, msg)
struct unisig *usp;
struct unisig_msg *msg;
{
struct unisig_vccb *uvp, *uvnext;
struct unisig_msg *rsta_msg;
int s;
ATM_DEBUG2("unisig_rcv_restart: usp=%p, msg=%p\n",
usp, msg);
/*
* Check what class of VCCs we're supposed to restart
*/
if (msg->msg_ie_rsti->ie_rsti_class == UNI_IE_RSTI_IND_VC) {
/*
* Just restart the indicated VCC
*/
if (msg->msg_ie_cnid) {
uvp = unisig_find_vpvc(usp,
msg->msg_ie_cnid->ie_cnid_vpci,
msg->msg_ie_cnid->ie_cnid_vci,
0);
if (uvp && uvp->uv_type & VCC_SVC) {
(void) unisig_clear_vcc(usp, uvp,
T_ATM_CAUSE_NORMAL_CALL_CLEARING);
}
}
} else {
/*
* Restart all VCCs
*/
s = splnet();
for (uvp=Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
uvp=uvnext) {
uvnext = Q_NEXT(uvp, struct unisig_vccb,
uv_sigelem);
if (uvp->uv_type & VCC_SVC) {
(void) unisig_clear_vcc(usp, uvp,
T_ATM_CAUSE_NORMAL_CALL_CLEARING);
}
}
(void) splx(s);
}
/*
* Get memory for a RESTART ACKNOWLEDGE message
*/
rsta_msg = uma_zalloc(unisig_msg_zone, M_NOWAIT);
if (rsta_msg == NULL) {
return;
}
/*
* Fill out the message
*/
rsta_msg->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref);
rsta_msg->msg_type = UNI_MSG_RSTA;
rsta_msg->msg_type_flag = 0;
rsta_msg->msg_type_action = 0;
rsta_msg->msg_ie_rsti = msg->msg_ie_rsti;
if (msg->msg_ie_cnid) {
rsta_msg->msg_ie_cnid = msg->msg_ie_cnid;
}
/*
* Send the message
*/
(void) unisig_send_msg(usp, rsta_msg);
rsta_msg->msg_ie_rsti = NULL;
rsta_msg->msg_ie_cnid = NULL;
unisig_free_msg(rsta_msg);
return;
}
/*
* Process a SETUP message
*
* Arguments:
* usp pointer to UNISIG protocol instance block
* msg pointer to the SETUP message
*
* Returns:
* none
*
*/
static void
unisig_rcv_setup(usp, msg)
struct unisig *usp;
struct unisig_msg *msg;
{
struct unisig_vccb *uvp = NULL;
struct ie_generic *iep;
ATM_DEBUG2("unisig_rcv_setup: usp=%p, msg=%p\n", usp, msg);
/*
* If we already have a VCC with the call reference,
* ignore the SETUP message
*/
uvp = unisig_find_conn(usp, EXTRACT_CREF(msg->msg_call_ref));
if (uvp)
return;
/*
* If the call reference flag is incorrectly set,
* ignore the SETUP message
*/
if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
return;
/*
* If there are missing mandatory IEs, send a
* RELEASE COMPLETE message and ignore the SETUP
*/
for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) {
if (iep->ie_err_cause == UNI_IE_CAUS_MISSING) {
(void) unisig_send_release_complete(usp,
uvp, msg, UNI_IE_CAUS_MISSING);
return;
}
}
/*
* If there are mandatory IEs with invalid content, send a
* RELEASE COMPLETE message and ignore the SETUP
*/
for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) {
if (iep->ie_err_cause == UNI_IE_CAUS_IECONTENT) {
(void) unisig_send_release_complete(usp,
uvp, msg,
UNI_IE_CAUS_IECONTENT);
return;
}
}
/*
* Get a new VCCB for the connection
*/
uvp = uma_zalloc(unisig_vc_zone, M_ZERO | M_NOWAIT);
if (uvp == NULL) {
return;
}
/*
* Put the VCCB on the UNISIG queue
*/
ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
/*
* Set the state and call reference value
*/
uvp->uv_sstate = UNI_NULL;
uvp->uv_call_ref = EXTRACT_CREF(msg->msg_call_ref);
/*
* Pass the VCCB and message to the VC state machine
*/
(void) unisig_vc_state(usp, uvp, UNI_VC_SETUP_MSG, msg);
/*
* If the VCCB state is NULL, the open failed and the
* VCCB should be released
*/
if (uvp->uv_sstate == UNI_NULL) {
DEQUEUE(uvp, struct unisig_vccb, uv_sigelem,
usp->us_vccq);
uma_zfree(unisig_vc_zone, uvp);
}
return;
}
/*
* Process a UNISIG signalling message
*
* Called when a UNISIG message is received. The message is decoded
* and passed to the UNISIG state machine. Unrecognized and
* unexpected messages are logged.
*
* Arguments:
* usp pointer to UNISIG protocol instance block
* m pointer to a buffer chain containing the UNISIG message
*
* Returns:
* none
*
*/
int
unisig_rcv_msg(usp, m)
struct unisig *usp;
KBuffer *m;
{
int err;
u_int cref;
struct usfmt usf;
struct unisig_msg *msg = 0;
struct unisig_vccb *uvp = 0;
struct ie_generic *iep;
ATM_DEBUG2("unisig_rcv_msg: bfr=%p, len=%d\n", m, KB_LEN(m));
#ifdef NOTDEF
unisig_print_mbuf(m);
#endif
/*
* Get storage for the message
*/
msg = uma_zalloc(unisig_msg_zone, M_ZERO | M_NOWAIT);
if (msg == NULL) {
err = ENOMEM;
goto done;
}
/*
* Convert the message from network order to internal format
*/
err = usf_init(&usf, usp, m, USF_DECODE, 0);
if (err) {
if (err == EINVAL)
panic("unisig_rcv_msg: invalid parameter\n");
ATM_DEBUG1("unisig_rcv_msg: decode init failed with %d\n",
err);
goto done;
}
err = usf_dec_msg(&usf, msg);
if (err) {
ATM_DEBUG1("unisig_rcv_msg: decode failed with %d\n",
err);
goto done;
}
/*
* Debug--print some information about the message
*/
if (unisig_print_msg)
usp_print_msg(msg, UNISIG_MSG_IN);
/*
* Get the call reference value
*/
cref = EXTRACT_CREF(msg->msg_call_ref);
/*
* Any message with the global call reference value except
* RESTART, RESTART ACK, or STATUS is in error
*/
if (GLOBAL_CREF(cref) &&
msg->msg_type != UNI_MSG_RSTR &&
msg->msg_type != UNI_MSG_RSTA &&
msg->msg_type != UNI_MSG_STAT) {
/*
* Send STATUS message indicating the error
*/
err = unisig_send_status(usp, (struct unisig_vccb *) 0,
msg, UNI_IE_CAUS_CREF);
goto done;
}
/*
* Check for missing mandatory IEs. Checks for SETUP,
* RELEASE, and RELEASE COMPLETE are handled elsewhere.
*/
if (msg->msg_type != UNI_MSG_SETU &&
msg->msg_type != UNI_MSG_RLSE &&
msg->msg_type != UNI_MSG_RLSC) {
for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) {
if (iep->ie_err_cause == UNI_IE_CAUS_MISSING) {
err = unisig_send_status(usp,
uvp, msg,
UNI_IE_CAUS_MISSING);
goto done;
}
}
}
/*
* Find the VCCB associated with the message
*/
uvp = unisig_find_conn(usp, cref);
/*
* Process the message based on its type
*/
switch(msg->msg_type) {
case UNI_MSG_CALP:
(void) unisig_vc_state(usp, uvp,
UNI_VC_CALLP_MSG, msg);
break;
case UNI_MSG_CONN:
(void) unisig_vc_state(usp, uvp,
UNI_VC_CONNECT_MSG, msg);
break;
case UNI_MSG_CACK:
(void) unisig_vc_state(usp, uvp,
UNI_VC_CNCTACK_MSG, msg);
break;
case UNI_MSG_SETU:
unisig_rcv_setup(usp, msg);
break;
case UNI_MSG_RLSE:
(void) unisig_vc_state(usp, uvp,
UNI_VC_RELEASE_MSG, msg);
break;
case UNI_MSG_RLSC:
/*
* Ignore a RELEASE COMPLETE with an unrecognized
* call reference value
*/
if (uvp) {
(void) unisig_vc_state(usp, uvp,
UNI_VC_RLSCMP_MSG, msg);
}
break;
case UNI_MSG_RSTR:
unisig_rcv_restart(usp, msg);
break;
case UNI_MSG_RSTA:
break;
case UNI_MSG_STAT:
(void) unisig_vc_state(usp, uvp,
UNI_VC_STATUS_MSG, msg);
break;
case UNI_MSG_SENQ:
(void) unisig_vc_state(usp, uvp,
UNI_VC_STATUSENQ_MSG, msg);
break;
case UNI_MSG_ADDP:
(void) unisig_vc_state(usp, uvp,
UNI_VC_ADDP_MSG, msg);
break;
case UNI_MSG_ADPA:
(void) unisig_vc_state(usp, uvp,
UNI_VC_ADDPACK_MSG, msg);
break;
case UNI_MSG_ADPR:
(void) unisig_vc_state(usp, uvp,
UNI_VC_ADDPREJ_MSG, msg);
break;
case UNI_MSG_DRPP:
(void) unisig_vc_state(usp, uvp,
UNI_VC_DROP_MSG, msg);
break;
case UNI_MSG_DRPA:
(void) unisig_vc_state(usp, uvp,
UNI_VC_DROPACK_MSG, msg);
break;
default:
/*
* Message size didn't match size received
*/
err = unisig_send_status(usp, uvp, msg,
UNI_IE_CAUS_MTEXIST);
}
done:
/*
* Handle message errors that require a response
*/
switch(err) {
case EMSGSIZE:
/*
* Message size didn't match size received
*/
err = unisig_send_status(usp, uvp, msg,
UNI_IE_CAUS_LEN);
break;
}
/*
* Free the incoming message (both buffer and internal format)
* if necessary.
*/
if (msg)
unisig_free_msg(msg);
if (m)
KB_FREEALL(m);
return (err);
}