summaryrefslogtreecommitdiffstats
path: root/sys/netatm/uni/unisig_msg.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
committerphk <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
commitc3dd1fa899d435ea4bf79897f646a93cb80c94ac (patch)
tree98dfbc96e3c6aa7ff1f322855f6484c4e609819d /sys/netatm/uni/unisig_msg.c
parent9ed6892f4808d56de443849229e151f8f7ad43b0 (diff)
downloadFreeBSD-src-c3dd1fa899d435ea4bf79897f646a93cb80c94ac.zip
FreeBSD-src-c3dd1fa899d435ea4bf79897f646a93cb80c94ac.tar.gz
Add new files for HARP3
Host ATM Research Platform (HARP), Network Computing Services, Inc. This software was developed with the support of the Defense Advanced Research Projects Agency (DARPA).
Diffstat (limited to 'sys/netatm/uni/unisig_msg.c')
-rw-r--r--sys/netatm/uni/unisig_msg.c1002
1 files changed, 1002 insertions, 0 deletions
diff --git a/sys/netatm/uni/unisig_msg.c b/sys/netatm/uni/unisig_msg.c
new file mode 100644
index 0000000..22bf469
--- /dev/null
+++ b/sys/netatm/uni/unisig_msg.c
@@ -0,0 +1,1002 @@
+/*
+ *
+ * ===================================
+ * 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.
+ *
+ * @(#) $Id: unisig_msg.c,v 1.10 1998/08/26 23:29:22 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Message handling module
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_msg.c,v 1.10 1998/08/26 23:29:22 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/unisig.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>
+
+
+/*
+ * Local functions
+ */
+static void unisig_rcv_restart __P((struct unisig *, struct unisig_msg *));
+static void unisig_rcv_setup __P((struct unisig *, struct unisig_msg *));
+
+
+/*
+ * Local variables
+ */
+#ifdef DIAGNOSTIC
+static int unisig_print_msg = 0;
+#endif
+
+
+/*
+ * Set a Cause IE based on information in an ATM attribute block
+ *
+ * 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_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=0x%x, type=%d\n", msg,
+ msg->msg_type);
+
+ /*
+ * Make sure the network is up
+ */
+ if (usp->us_state != UNISIG_ACTIVE)
+ return(ENETDOWN);
+
+#ifdef DIAGNOSTIC
+ /*
+ * Print the message we're sending.
+ */
+ if (unisig_print_msg)
+ usp_print_msg(msg, UNISIG_MSG_OUT);
+#endif
+
+ /*
+ * 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);
+ }
+
+#ifdef DIAGNOSTIC
+ /*
+ * Print the converted message
+ */
+ if (unisig_print_msg > 1)
+ unisig_print_mbuf(usf.usf_m_base);
+#endif
+
+ /*
+ * 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=0x%x\n", (int) 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 = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
+ 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 = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ 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=0x%x, uvp=0x%x\n",
+ (int) usp, (int) uvp);
+
+ /*
+ * Get memory for a RELEASE message
+ */
+ rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (rls_msg == NULL) {
+ return(ENOMEM);
+ }
+ cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (cause_ie == NULL) {
+ atm_free(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=0x%x, uvp=0x%x, msg=0x%x, cause=%d\n",
+ (int) usp, (int) uvp, (int) msg, cause);
+
+ /*
+ * Get memory for a RELEASE COMPLETE message
+ */
+ rls_cmp = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (rls_cmp == NULL) {
+ return(ENOMEM);
+ }
+ cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (cause_ie == NULL) {
+ atm_free(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=0x%x, uvp=0x%x, msg=0x%x, cause=%d\n",
+ (int) usp, (int) uvp, (int) msg, cause);
+
+ /*
+ * Get memory for a STATUS message
+ */
+ stat_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (stat_msg == NULL) {
+ return(ENOMEM);
+ }
+ cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (cause_ie == NULL) {
+ atm_free(stat_msg);
+ return(ENOMEM);
+ }
+ clst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (clst_ie == NULL) {
+ atm_free(stat_msg);
+ atm_free(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=0x%x, msg=0x%x\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 = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ 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=0x%x, msg=0x%x\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 = (struct unisig_vccb *)atm_allocate(&unisig_vcpool);
+ 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);
+ atm_free(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=0x%x, len=%d\n", (int)m, KB_LEN(m));
+
+#ifdef NOTDEF
+ unisig_print_mbuf(m);
+#endif
+
+ /*
+ * Get storage for the message
+ */
+ msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
+ 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;
+ }
+
+#ifdef DIAGNOSTIC
+ /*
+ * Debug--print some information about the message
+ */
+ if (unisig_print_msg)
+ usp_print_msg(msg, UNISIG_MSG_IN);
+#endif
+
+ /*
+ * 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);
+}
OpenPOWER on IntegriCloud