summaryrefslogtreecommitdiffstats
path: root/sys/netatm/uni/unisig_msg.c
diff options
context:
space:
mode:
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