summaryrefslogtreecommitdiffstats
path: root/sys/netatm/uni/unisig_vc_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/uni/unisig_vc_state.c')
-rw-r--r--sys/netatm/uni/unisig_vc_state.c2223
1 files changed, 2223 insertions, 0 deletions
diff --git a/sys/netatm/uni/unisig_vc_state.c b/sys/netatm/uni/unisig_vc_state.c
new file mode 100644
index 0000000..cfd7635
--- /dev/null
+++ b/sys/netatm/uni/unisig_vc_state.c
@@ -0,0 +1,2223 @@
+/*
+ *
+ * ===================================
+ * 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_vc_state.c,v 1.11 1998/08/06 18:16:29 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * VC state machine
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_vc_state.c,v 1.11 1998/08/06 18:16:29 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_decode.h>
+
+
+/*
+ * Local functions
+ */
+static int unisig_vc_invalid __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act01 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act02 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act03 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act04 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act05 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act06 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act07 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act08 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act09 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act10 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act11 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act12 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act13 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act14 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act15 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act16 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act17 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act18 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act19 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act20 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act21 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act22 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act23 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act24 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act25 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act26 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act27 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act28 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act29 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act30 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act31 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_clear_call __P((struct unisig *,
+ struct unisig_vccb *,
+ struct unisig_msg *,
+ int));
+
+
+/*
+ * State table
+ */
+static int unisig_vc_states[21][17] = {
+/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */
+{ 0, 2, 99, 5, 99, 99, 0, 99, 12, 99, 0, 14, 0, 3, 0, 0, 0 },
+{ 29, 4, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 6, 99, 6, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 10, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 8, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 7, 99, 15, 99, 99, 15, 99, 15, 99, 15, 16, 17, 0, 0, 0, 0 },
+{ 19, 3, 99, 3, 99, 99, 3, 99, 3, 99, 3, 13, 3, 0, 0, 0, 0 },
+{ 21, 21, 99, 21, 99, 99, 21, 99, 21, 99, 21, 21, 21, 0, 0, 0, 0 },
+{ 22, 22, 99, 22, 99, 99, 22, 99, 22, 99, 22, 22, 22, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 23, 17, 17, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 1, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 },
+{ 99, 25, 99, 25, 99, 99, 9, 99, 25, 99, 25, 25, 25, 25, 31, 25, 25 },
+{ 99, 25, 99, 25, 99, 99, 11, 99, 25, 99, 25, 25, 25, 25, 19, 25, 25 },
+{ 99, 12, 99, 12, 99, 99, 25, 99, 12, 99, 12, 19, 19, 30, 19, 99, 99 },
+{ 99, 12, 99, 12, 99, 99, 12, 99, 12, 99, 12, 3, 3, 3, 24, 26, 26 },
+{ 99, 3, 99, 3, 99, 99, 30, 99, 3, 99, 18, 3, 3, 0, 19, 27, 19 },
+{ 99, 7, 99, 7, 99, 99, 30, 99, 7, 99, 19, 19, 19, 20, 19, 19, 28 }
+};
+
+
+/*
+ * Action vector
+ *
+ * A given state, action pair selects an action number from the
+ * state table. This vector holds the address of the action routine
+ * for each action number.
+ */
+#define MAX_ACTION 32
+static int (*unisig_vc_act_vec[MAX_ACTION])
+ __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *)) = {
+ unisig_vc_invalid,
+ unisig_vc_act01,
+ unisig_vc_act02,
+ unisig_vc_act03,
+ unisig_vc_act04,
+ unisig_vc_act05,
+ unisig_vc_act06,
+ unisig_vc_act07,
+ unisig_vc_act08,
+ unisig_vc_act09,
+ unisig_vc_act10,
+ unisig_vc_act11,
+ unisig_vc_act12,
+ unisig_vc_act13,
+ unisig_vc_act14,
+ unisig_vc_act15,
+ unisig_vc_act16,
+ unisig_vc_act17,
+ unisig_vc_act18,
+ unisig_vc_act19,
+ unisig_vc_act20,
+ unisig_vc_act21,
+ unisig_vc_act22,
+ unisig_vc_act23,
+ unisig_vc_act24,
+ unisig_vc_act25,
+ unisig_vc_act26,
+ unisig_vc_act27,
+ unisig_vc_act28,
+ unisig_vc_act29,
+ unisig_vc_act30,
+ unisig_vc_act31
+};
+
+
+/*
+ * Process an event on a VC
+ *
+ * Arguments:
+ * usp pointer to the UNISIG instance
+ * uvp pointer to the VCCB for the affected VCC
+ * event a numeric indication of which event has occured
+ * msg pointer to a signalling message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+unisig_vc_state(usp, uvp, event, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ int event;
+ struct unisig_msg *msg;
+{
+ int action, rc, state;
+
+ /*
+ * Select an action from the state table
+ */
+ if (uvp)
+ state = uvp->uv_sstate;
+ else
+ state = UNI_NULL;
+ action = unisig_vc_states[event][state];
+ if (action >= MAX_ACTION || action < 0)
+ panic("unisig_vc_state: invalid action\n");
+
+ /*
+ * Perform the requested action
+ */
+ ATM_DEBUG4("unisig_vc_state: uvp=0x%x, state=%d, event=%d, action=%d\n",
+ (int) uvp, state, event, action);
+ rc = unisig_vc_act_vec[action](usp, uvp, msg);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 0
+ * Unexpected action - log an error message
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection (may
+ be null)
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_invalid(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ log(LOG_ERR, "unisig_vc_state: unexpected action\n");
+ return(EINVAL);
+}
+
+
+/*
+ * VC state machine action 1
+ * Setup handler called
+ *
+ * Send SETUP, start timer T303, go to UNI_CALL_INITIATED state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act01(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Send the setup message
+ */
+ rc = unisig_send_setup(usp, uvp);
+ if (rc)
+ return(rc);
+
+ /*
+ * Set timer T303
+ */
+ uvp->uv_retry = 0;
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T303);
+
+ /*
+ * Set the new state
+ */
+ uvp->uv_sstate = UNI_CALL_INITIATED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 2
+ * Timeout while waiting for CALL PROCEEDING or CONNECT
+ *
+ * If this is the second expiration, clear the call. Otherwise,
+ * retransmit the SETUP message and restart T303.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act02(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc = 0;
+
+ if (uvp->uv_retry) {
+ /*
+ * Clear the call
+ */
+ rc = unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NO_ROUTE_TO_DESTINATION);
+ } else {
+ uvp->uv_retry++;
+ (void) unisig_send_setup(usp, uvp);
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T303);
+ }
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 3
+ *
+ * Clear the call internally
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act03(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Clear the VCCB
+ */
+ rc = unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 4
+ * Received CALL PROCEEDING
+ *
+ * Start timer T310, go to UNI_CALL_OUT_PROC
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act04(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int cause, rc, vpi, vci;
+ struct atm_pif *pip = usp->us_pif;
+ struct ie_generic *iep;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Make sure a Connection ID is part of the message
+ */
+ if (msg->msg_ie_cnid) {
+ vpi = msg->msg_ie_cnid->ie_cnid_vpci;
+ vci = msg->msg_ie_cnid->ie_cnid_vci;
+ } else {
+ iep = (struct ie_generic *)atm_allocate(&unisig_iepool);
+ if (!iep)
+ return(ENOMEM);
+ iep->ie_ident = UNI_IE_CNID;
+ iep->ie_err_cause = UNI_IE_CAUS_MISSING;
+ MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR);
+ cause = UNI_IE_CAUS_MISSING;
+ ATM_DEBUG0("unisig_vc_act04: no CNID in Call Proc\n");
+ goto response04;
+ }
+
+ /*
+ * Make sure we can handle the specified VPI and VCI
+ */
+ if (vpi > pip->pif_maxvpi || vci > pip->pif_maxvci ||
+ vci < UNI_IE_CNID_MIN_VCI) {
+ cause = UNI_IE_CAUS_BAD_VCC;
+ ATM_DEBUG0("unisig_vc_act04: VPI/VCI invalid\n");
+ goto response04;
+ }
+
+ /*
+ * Make sure the specified VPI and VCI are not in use
+ */
+ if (unisig_find_vpvc(usp, vpi, vci, VCC_OUT)) {
+ cause = UNI_IE_CAUS_NA_VCC;
+ ATM_DEBUG0("unisig_vc_act04: VPI/VCI in use\n");
+ goto response04;
+ }
+
+ /*
+ * Start timer T310
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T310);
+
+ /*
+ * Save the specified VPI and VCI
+ */
+ uvp->uv_vpi = vpi;
+ uvp->uv_vci = vci;
+
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_CALL_OUT_PROC;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+
+response04:
+ /*
+ * Initiate call clearing
+ */
+ rc = unisig_vc_clear_call(usp, uvp, msg, cause);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 5
+ * Timeout in UNI_CALL_OUT_PROC
+ *
+ * Clear call towards network
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act05(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+ struct unisig_msg *rls_msg;
+ struct ie_generic *cause_ie;
+
+ /*
+ * Send 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 out 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_caus_loc = UNI_IE_CAUS_LOC_USER;
+ cause_ie->ie_caus_cause = UNI_IE_CAUS_TIMER;
+ KM_COPY("310", cause_ie->ie_caus_diagnostic, 3);
+
+ /*
+ * Send the RELEASE message.
+ */
+ rc = unisig_send_msg(usp, rls_msg);
+ unisig_free_msg(rls_msg);
+
+ /*
+ * Start timer T308
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308);
+
+ /*
+ * Set the new state
+ */
+ uvp->uv_sstate = UNI_RELEASE_REQUEST;
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 6
+ * Received CONNECT
+ *
+ * Send CONNECT ACK, go to UNI_ACTIVE state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act06(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int cause, rc, vci, vpi;
+ struct atm_pif *pip = usp->us_pif;
+ struct unisig_msg *cack_msg;
+ struct ie_generic *iep;
+ Atm_attributes *ap;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ ap = &uvp->uv_connvc->cvc_attr;
+
+ /*
+ * See if a VPI/VCI is specified
+ */
+ if (msg->msg_ie_cnid) {
+ /*
+ * Yes--VPI/VCI must be the first specification or must
+ * match what was specified before
+ */
+ vpi = msg->msg_ie_cnid->ie_cnid_vpci;
+ vci = msg->msg_ie_cnid->ie_cnid_vci;
+ if ((uvp->uv_vpi || uvp->uv_vci) &&
+ (vpi != uvp->uv_vpi ||
+ vci != uvp->uv_vci)) {
+ cause = UNI_IE_CAUS_BAD_VCC;
+ ATM_DEBUG0("unisig_vc_act06: VPI/VCI invalid\n");
+ goto response06;
+ }
+
+ /*
+ * Specified VPI/VCI must be within range
+ */
+ if (vpi > pip->pif_maxvpi || vci > pip->pif_maxvci ||
+ vci < UNI_IE_CNID_MIN_VCI) {
+ cause = UNI_IE_CAUS_BAD_VCC;
+ ATM_DEBUG0("unisig_vc_act06: VPI/VCI invalid\n");
+ goto response06;
+ }
+ uvp->uv_vpi = vpi;
+ uvp->uv_vci = vci;
+ } else {
+ /*
+ * No--VPI/VCI must have been specified earlier
+ */
+ if (!uvp->uv_vpi || !uvp->uv_vci) {
+ iep = (struct ie_generic *)atm_allocate(
+ &unisig_iepool);
+ if (!iep)
+ return(ENOMEM);
+ iep->ie_ident = UNI_IE_CNID;
+ iep->ie_err_cause = UNI_IE_CAUS_MISSING;
+ MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR);
+ cause = UNI_IE_CAUS_MISSING;
+ ATM_DEBUG0("unisig_vc_act06: CNID missing\n");
+ goto response06;
+ }
+ }
+
+ /*
+ * Handle AAL parameters negotiation
+ */
+ if (msg->msg_ie_aalp) {
+ struct ie_generic *aalp = msg->msg_ie_aalp;
+
+ /*
+ * AAL parameters must have been sent in SETUP
+ */
+ if ((ap->aal.tag != T_ATM_PRESENT) ||
+ (ap->aal.type != aalp->ie_aalp_aal_type)) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ goto response06;
+ }
+
+ switch (aalp->ie_aalp_aal_type) {
+
+ case UNI_IE_AALP_AT_AAL3:
+ /*
+ * Maximum SDU size negotiation
+ */
+ if (aalp->ie_aalp_4_fwd_max_sdu == T_ATM_ABSENT)
+ break;
+ if ((ap->aal.v.aal4.forward_max_SDU_size <
+ aalp->ie_aalp_4_fwd_max_sdu) ||
+ (ap->aal.v.aal4.backward_max_SDU_size <
+ aalp->ie_aalp_4_bkwd_max_sdu)) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ goto response06;
+ } else {
+ ap->aal.v.aal4.forward_max_SDU_size =
+ aalp->ie_aalp_4_fwd_max_sdu;
+ ap->aal.v.aal4.backward_max_SDU_size =
+ aalp->ie_aalp_4_bkwd_max_sdu;
+ }
+ break;
+
+ case UNI_IE_AALP_AT_AAL5:
+ /*
+ * Maximum SDU size negotiation
+ */
+ if (aalp->ie_aalp_5_fwd_max_sdu == T_ATM_ABSENT)
+ break;
+ if ((ap->aal.v.aal5.forward_max_SDU_size <
+ aalp->ie_aalp_5_fwd_max_sdu) ||
+ (ap->aal.v.aal5.backward_max_SDU_size <
+ aalp->ie_aalp_5_bkwd_max_sdu)) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ goto response06;
+ } else {
+ ap->aal.v.aal5.forward_max_SDU_size =
+ aalp->ie_aalp_5_fwd_max_sdu;
+ ap->aal.v.aal5.backward_max_SDU_size =
+ aalp->ie_aalp_5_bkwd_max_sdu;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Get memory for a CONNECT ACK message
+ */
+ cack_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (cack_msg == NULL)
+ return(ENOMEM);
+
+ /*
+ * Fill out the CONNECT ACK message
+ */
+ cack_msg->msg_call_ref = uvp->uv_call_ref;
+ cack_msg->msg_type = UNI_MSG_CACK;
+ cack_msg->msg_type_flag = 0;
+ cack_msg->msg_type_action = 0;
+
+ /*
+ * Send the CONNECT ACK message
+ */
+ rc = unisig_send_msg(usp, cack_msg);
+ unisig_free_msg(cack_msg);
+
+ /*
+ * Set the new state
+ */
+ uvp->uv_sstate = UNI_ACTIVE;
+ uvp->uv_ustate = VCCU_OPEN;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Notify the user that the connection is now active
+ */
+ atm_cm_connected(uvp->uv_connvc);
+
+ return(0);
+
+response06:
+ /*
+ * Initiate call clearing
+ */
+ rc = unisig_vc_clear_call(usp, uvp, msg, cause);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 7
+ * Abort routine called or signalling SAAL session reset while in
+ * one of the call setup states
+ *
+ * Clear the call, send RELEASE COMPLETE, notify the user.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act07(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Send a RELEASE COMPLETE message rejecting the connection
+ */
+ rc = unisig_send_release_complete(usp, uvp, msg,
+ UNI_IE_CAUS_TEMP);
+
+ /*
+ * Clear the call VCCB
+ */
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Notify the user
+ */
+ unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ atm_cm_cleared(uvp->uv_connvc);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 8
+ * Received SETUP
+ *
+ * Check call paramaters, notify user that a call has been received,
+ * set UNI_CALL_PRESENT state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act08(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int cause = 0, rc, vpi, vci;
+ struct atm_pif *pip = usp->us_pif;
+ struct atm_nif *nip;
+ Atm_addr_nsap *nap;
+ Atm_attributes attr;
+
+ ATM_DEBUG3("unisig_vc_act08: usp=0x%x, uvp=0x%x, msg=0x%x\n",
+ (int) usp, (int) uvp, (int) msg);
+
+ /*
+ * Make sure that the called address is the right format
+ */
+ if (msg->msg_ie_cdad->ie_cdad_plan != UNI_IE_CDAD_PLAN_NSAP) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ ATM_DEBUG0("unisig_vc_act08: bad address format\n");
+ goto response08;
+ }
+
+ /*
+ * Make sure that the called address is ours
+ */
+ nap = (Atm_addr_nsap *) msg->msg_ie_cdad->ie_cdad_addr.address;
+ if (bcmp(usp->us_addr.address, nap, /* XXX */
+ sizeof(Atm_addr_nsap)-1)) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ ATM_DEBUG0("unisig_vc_act08: address not mine\n");
+ goto response08;
+ }
+
+ /*
+ * Find the right NIF for the given selector byte
+ */
+ nip = pip->pif_nif;
+ while (nip && nip->nif_sel != nap->aan_sel) {
+ nip = nip->nif_pnext;
+ }
+ if (!nip) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ ATM_DEBUG0("unisig_vc_act08: bad selector byte\n");
+ goto response08;
+ }
+
+ /*
+ * See if we can handle the specified encapsulation
+ */
+ if (msg->msg_ie_blli->ie_blli_l2_id != UNI_IE_BLLI_L2P_LLC &&
+ (msg->msg_ie_blli->ie_blli_l2_id != 0 ||
+ msg->msg_ie_blli->ie_blli_l3_id !=
+ UNI_IE_BLLI_L3P_ISO9577)) {
+ cause = UNI_IE_CAUS_UNAVAIL;
+ ATM_DEBUG0("unisig_vc_act08: bad encapsulation\n");
+ goto response08;
+ }
+
+ /*
+ * See if we recognize the specified AAL
+ */
+ if (msg->msg_ie_aalp->ie_aalp_aal_type != UNI_IE_AALP_AT_AAL3 &&
+ msg->msg_ie_aalp->ie_aalp_aal_type !=
+ UNI_IE_AALP_AT_AAL5) {
+ cause = UNI_IE_CAUS_UAAL;
+ ATM_DEBUG0("unisig_vc_act08: bad AAL\n");
+ goto response08;
+ }
+
+ /*
+ * Should verify that we can handle requested
+ * connection QOS
+ */
+
+ /*
+ * Make sure the specified VPI/VCI is valid
+ */
+ vpi = msg->msg_ie_cnid->ie_cnid_vpci;
+ vci = msg->msg_ie_cnid->ie_cnid_vci;
+ if (vpi > pip->pif_maxvpi ||
+ vci > pip->pif_maxvci ||
+ vci < UNI_IE_CNID_MIN_VCI) {
+ cause = UNI_IE_CAUS_BAD_VCC;
+ ATM_DEBUG0("unisig_vc_act08: VPI/VCI invalid\n");
+ goto response08;
+ }
+
+ /*
+ * Make sure the specified VPI/VCI isn't in use already
+ */
+ if (unisig_find_vpvc(usp, vpi, vci, VCC_IN)) {
+ cause = UNI_IE_CAUS_NA_VCC;
+ ATM_DEBUG0("unisig_vc_act08: VPI/VCI in use\n");
+ goto response08;
+ }
+
+ /*
+ * Make sure it's a point-to-point connection
+ */
+ if (msg->msg_ie_bbcp->ie_bbcp_conn_config !=
+ UNI_IE_BBCP_CC_PP) {
+ cause = UNI_IE_CAUS_NI_BC;
+ ATM_DEBUG0("unisig_vc_act08: conn not pt-pt\n");
+ goto response08;
+ }
+
+ /*
+ * Fill in the VCCB fields that we can at this point
+ */
+ uvp->uv_type = VCC_SVC | VCC_IN | VCC_OUT;
+ uvp->uv_proto = pip->pif_sigmgr->sm_proto;
+ uvp->uv_sstate = UNI_CALL_PRESENT;
+ uvp->uv_ustate = VCCU_POPEN;
+ uvp->uv_pif = pip;
+ uvp->uv_nif = nip;
+ uvp->uv_vpi = msg->msg_ie_cnid->ie_cnid_vpci;
+ uvp->uv_vci = msg->msg_ie_cnid->ie_cnid_vci;
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Copy the connection attributes from the SETUP message
+ * to an attribute block
+ */
+ KM_ZERO(&attr, sizeof(attr));
+ attr.nif = nip;
+ attr.aal.tag = T_ATM_ABSENT;
+ attr.traffic.tag = T_ATM_ABSENT;
+ attr.bearer.tag = T_ATM_ABSENT;
+ attr.bhli.tag = T_ATM_ABSENT;
+ attr.blli.tag_l2 = T_ATM_ABSENT;
+ attr.blli.tag_l3 = T_ATM_ABSENT;
+ attr.llc.tag = T_ATM_ABSENT;
+ attr.called.tag = T_ATM_ABSENT;
+ attr.calling.tag = T_ATM_ABSENT;
+ attr.qos.tag = T_ATM_ABSENT;
+ attr.transit.tag = T_ATM_ABSENT;
+ attr.cause.tag = T_ATM_ABSENT;
+ unisig_save_attrs(usp, msg, &attr);
+
+ /*
+ * Notify the connection manager of the new VCC
+ */
+ ATM_DEBUG0("unisig_vc_act08: notifying user of connection\n");
+ rc = atm_cm_incoming((struct vccb *)uvp, &attr);
+ if (rc)
+ goto response08;
+
+ /*
+ * Wait for the connection recipient to issue an accept
+ * or reject
+ */
+ return(0);
+
+response08:
+ ATM_DEBUG1("unisig_vc_act08: reject with cause=%d\n", cause);
+
+ /*
+ * Clear the VCCB state
+ */
+ uvp->uv_sstate = UNI_NULL;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Some problem was detected with the request. Send a Q.2931
+ * message rejecting the connection.
+ */
+ rc = unisig_send_release_complete(usp, uvp, msg, cause);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 9
+ * Accept routine called by user
+ *
+ * Send CONNECT, start timer T313, go to UNI_CONNECT_REQUEST state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act09(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+ struct unisig_msg *conn_msg;
+
+ conn_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (conn_msg == NULL)
+ return(ENOMEM);
+
+ /*
+ * Fill out the response
+ */
+ conn_msg->msg_call_ref = uvp->uv_call_ref;
+ conn_msg->msg_type = UNI_MSG_CONN;
+ conn_msg->msg_type_flag = 0;
+ conn_msg->msg_type_action = 0;
+
+ /*
+ * Send the CONNECT message. If the send fails, the other
+ * side will eventually time out and close the connection.
+ */
+ rc = unisig_send_msg(usp, conn_msg);
+ unisig_free_msg(conn_msg);
+ if (rc) {
+ return(rc);
+ }
+
+ /*
+ * Start timer T313
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T313);
+
+ /*
+ * Set the new state
+ */
+ uvp->uv_sstate = UNI_CONNECT_REQUEST;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 10
+ * Received CONNECT ACK
+ *
+ * Go to UNI_ACTIVE state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act10(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_ACTIVE;
+ uvp->uv_ustate = VCCU_OPEN;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Notify the user that the call is up
+ */
+ atm_cm_connected(uvp->uv_connvc);
+
+ return (0);
+}
+
+
+/*
+ * VC state machine action 11
+ * Reject handler called
+ *
+ * Send RELEASE COMPLETE, clear the call
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act11(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Send a RELEASE COMPLETE message
+ */
+ rc = unisig_send_release_complete(usp, uvp, msg,
+ UNI_IE_CAUS_REJECT);
+
+ /*
+ * Clear the call VCCB
+ */
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 12
+ * Release or abort routine called
+ *
+ * Send RELEASE, start timer T308, go to UNI_RELEASE_REQUEST state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act12(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Send the RELEASE message
+ */
+ rc = unisig_vc_clear_call(usp, uvp, (struct unisig_msg *)0,
+ T_ATM_ABSENT);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 13
+ * RELEASE COMPLETE received
+ *
+ * Clear the call
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act13(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_FREE;
+ if (uvp->uv_ustate != VCCU_ABORT)
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Notify the user that the call is now closed
+ */
+ unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ atm_cm_cleared(uvp->uv_connvc);
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 14
+ * Timer expired while waiting for RELEASE COMPLETE
+ *
+ * If this is the second expiration, just clear the call. Otherwise,
+ * retransmit the RELEASE message and restart timer T308.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act14(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Check the retry count
+ */
+ if (uvp->uv_retry) {
+ /*
+ * Clear the connection
+ */
+ rc = unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ } else {
+ /*
+ * Increment the retry count
+ */
+ uvp->uv_retry++;
+
+ /*
+ * Resend the RELEASE message
+ */
+ rc = unisig_send_release(usp, uvp,
+ (struct unisig_msg *)0, T_ATM_ABSENT);
+ if (rc)
+ return(rc);
+
+ /*
+ * Restart timer T308
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308);
+ }
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 15
+ * RELEASE received in UNI_ACTIVE state
+ *
+ * Send RELEASE COMPLETE, go to UNI_FREE, notify the user
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act15(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int cause, rc;
+ struct ie_generic *iep;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * If there was no Cause IE, flag an error
+ */
+ if (!msg->msg_ie_caus) {
+ cause = UNI_IE_CAUS_MISSING;
+ for (iep=msg->msg_ie_err; iep; iep=iep->ie_next) {
+ if (iep->ie_ident == UNI_IE_CAUS &&
+ iep->ie_err_cause ==
+ UNI_IE_CAUS_IECONTENT) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ }
+ }
+ if (cause == UNI_IE_CAUS_MISSING) {
+ iep = (struct ie_generic *)atm_allocate(
+ &unisig_iepool);
+ if (!iep)
+ return(ENOMEM);
+ iep->ie_ident = UNI_IE_CNID;
+ iep->ie_err_cause = UNI_IE_CAUS_MISSING;
+ MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR);
+ }
+ } else {
+ cause = UNI_IE_CAUS_NORM_UNSP;
+ }
+
+ /*
+ * Send a RELEASE COMPLETE message
+ */
+ rc = unisig_send_release_complete(usp, uvp, msg, cause);
+
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Notify the user that the call is cleared
+ */
+ unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ atm_cm_cleared(uvp->uv_connvc);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 16
+ * RELEASE received in UNI_RELEASE_REQUEST state
+ *
+ * Clear the call
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act16(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Clear the VCCB
+ */
+ rc = unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 17
+ * Protocol error
+ *
+ * Send a STATUS message with cause 101, "message not compatible with
+ * call state"
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act17(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ ATM_DEBUG3("unisig_vc_perror: usp=0x%x, uvp=0x%x, msg=0x%x\n",
+ (int) usp, (int) uvp, (int) msg);
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Send a STATUS message
+ */
+ rc = unisig_send_status(usp, uvp, msg, UNI_IE_CAUS_STATE);
+
+ return(rc ? rc : EINVAL);
+}
+
+
+/*
+ * VC state machine action 18
+ * Signalling AAL connection has been lost
+ *
+ * Start timer T309. If the timer expires before the SAAL connection
+ * comes back, the VCC will be cleared.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act18(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Start timer T309
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T309);
+
+ /*
+ * Set new state
+ */
+ uvp->uv_sstate = UNI_SSCF_RECOV;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 19
+ * Ignore the event
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act19(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ return(0);
+}
+
+
+/*
+ * VC state machine action 20
+ * SSCF establish indication in UNI_SSCF_RECOV state -- signalling
+ * AAL has come up after an outage
+ *
+ * Send STATUS ENQ to make sure we're in compatible state with other end
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act20(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+ struct unisig_msg *stat_msg;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Get memory for a STATUS ENQUIRY message
+ */
+ stat_msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
+ if (stat_msg == NULL)
+ return(ENOMEM);
+
+ /*
+ * Fill out the message
+ */
+ stat_msg->msg_call_ref = uvp->uv_call_ref;
+ stat_msg->msg_type = UNI_MSG_SENQ;
+ stat_msg->msg_type_flag = 0;
+ stat_msg->msg_type_action = 0;
+
+ /*
+ * Send the STATUS ENQUIRY message
+ */
+ rc = unisig_send_msg(usp, stat_msg);
+ unisig_free_msg(stat_msg);
+
+ /*
+ * Return to active state
+ */
+ uvp->uv_sstate = UNI_ACTIVE;
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 21
+ * STATUS received
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection (may
+ * be NULL)
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act21(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int cause, rc;
+
+ /*
+ * Ignore a STATUS message with the global call reference
+ */
+ if (GLOBAL_CREF(msg->msg_call_ref)) {
+ return(0);
+ }
+
+ /*
+ * If the network thinks we're in NULL state, clear the VCC
+ */
+ if (msg->msg_ie_clst->ie_clst_state == UNI_NULL) {
+ if (uvp) {
+ (void)unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER);
+ }
+ return(0);
+ }
+
+ /*
+ * If we are in NULL state, send a RELEASE COMPLETE
+ */
+ if (!uvp || (uvp->uv_sstate == UNI_FREE) ||
+ (uvp->uv_sstate == UNI_NULL)) {
+ rc = unisig_send_release_complete(usp,
+ uvp, msg, UNI_IE_CAUS_STATE);
+ return(rc);
+ }
+
+ /*
+ * If the reported state doesn't match our state, close the VCC
+ * unless we're in UNI_RELEASE_REQUEST or UNI_RELEASE_IND
+ */
+ if (msg->msg_ie_clst->ie_clst_state != uvp->uv_sstate) {
+ if (uvp->uv_sstate == UNI_RELEASE_REQUEST ||
+ uvp->uv_sstate == UNI_RELEASE_IND) {
+ return(0);
+ }
+ rc = unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ }
+
+ /*
+ * States match, check for an error on one of our messages
+ */
+ cause = msg->msg_ie_caus->ie_caus_cause;
+ if (cause == UNI_IE_CAUS_MISSING ||
+ cause == UNI_IE_CAUS_MTEXIST ||
+ cause == UNI_IE_CAUS_IEEXIST ||
+ cause == UNI_IE_CAUS_IECONTENT ||
+ cause == UNI_IE_CAUS_STATE) {
+ ATM_DEBUG2("unisig_vc_act21: error %d on message 0x%x\n",
+ cause,
+ msg->msg_ie_caus->ie_caus_diagnostic[0]);
+ if (uvp) {
+ (void)unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_INVALID_INFO_ELEMENT_CONTENTS);
+ }
+ }
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 22
+ * Received STATUS ENQ
+ *
+ * Send STATUS with cause 30 "response to STATUS ENQUIRY" and
+ * current state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection (may
+ * be NULL)
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act22(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+ struct unisig_msg *status;
+ struct ie_generic *callst_ie, *cause_ie;
+
+ ATM_DEBUG3("unisig_vc_perror: usp=0x%x, uvp=0x%x, msg=0x%x\n",
+ (int) usp, (int) uvp, (int) msg);
+
+ /*
+ * Get memory for a STATUS message
+ */
+ status = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (status == NULL)
+ return(ENOMEM);
+ callst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (callst_ie == NULL) {
+ atm_free(status);
+ return(ENOMEM);
+ }
+ cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (cause_ie == NULL) {
+ atm_free(status);
+ atm_free(callst_ie);
+ return(ENOMEM);
+ }
+
+ /*
+ * Fill out the response
+ */
+ if (uvp) {
+ status->msg_call_ref = uvp->uv_call_ref;
+ } else if (msg) {
+ if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
+ status->msg_call_ref = msg->msg_call_ref &
+ UNI_MSG_CALL_REF_MASK;
+ else
+ status->msg_call_ref = msg->msg_call_ref |
+ UNI_MSG_CALL_REF_RMT;
+ } else {
+ status->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
+ }
+ status->msg_type = UNI_MSG_STAT;
+ status->msg_type_flag = 0;
+ status->msg_type_action = 0;
+ status->msg_ie_clst = callst_ie;
+ status->msg_ie_caus = cause_ie;
+
+ /*
+ * Fill out the call state IE
+ */
+ callst_ie->ie_ident = UNI_IE_CLST;
+ callst_ie->ie_coding = 0;
+ callst_ie->ie_flag = 0;
+ callst_ie->ie_action = 0;
+ if (uvp) {
+ switch(uvp->uv_sstate) {
+ case UNI_FREE:
+ callst_ie->ie_clst_state = UNI_NULL;
+ break;
+ default:
+ callst_ie->ie_clst_state = uvp->uv_sstate;
+ }
+ } else {
+ callst_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 = UNI_IE_CAUS_SENQ;
+
+ /*
+ * Send the STATUS message
+ */
+ rc = unisig_send_msg(usp, status);
+ unisig_free_msg(status);
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 23
+ * Received ADD PARTY
+ *
+ * We don't support multipoint connections, so send an ADD PARTY REJECT
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act23(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+ struct unisig_msg *apr_msg;
+
+ /*
+ * Get memory for the ADD PARTY REJECT message
+ */
+ apr_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (apr_msg == NULL)
+ return(ENOMEM);
+
+ /*
+ * Fill out the message
+ */
+ if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
+ apr_msg->msg_call_ref = msg->msg_call_ref &
+ UNI_MSG_CALL_REF_MASK;
+ else
+ apr_msg->msg_call_ref = msg->msg_call_ref |
+ UNI_MSG_CALL_REF_RMT;
+ apr_msg->msg_type = UNI_MSG_ADPR;
+ apr_msg->msg_type_flag = 0;
+ apr_msg->msg_type_action = 0;
+
+ /*
+ * Use the endpoint reference IE from the received message
+ */
+ apr_msg->msg_ie_eprf = msg->msg_ie_eprf;
+
+ /*
+ * Send the ADD PARTY REJECT message
+ */
+ rc = unisig_send_msg(usp, apr_msg);
+ apr_msg->msg_ie_eprf = NULL;
+ unisig_free_msg(apr_msg);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 24
+ * User error
+ *
+ * Return EALREADY
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act24(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ return(EALREADY);
+}
+
+
+/*
+ * VC state machine action 25
+ * User error
+ *
+ * Return EINVAL
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act25(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ return(EINVAL);
+}
+
+
+/*
+ * VC state machine action 26
+ * PVC abort
+ *
+ * The abort handler was called to abort a PVC. Clear the VCCB and
+ * notify the user.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act26(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Close the VCCB
+ */
+ rc = unisig_close_vcc(usp, uvp);
+ if (rc)
+ return(rc);
+
+ /*
+ * Notify the user
+ */
+ unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ atm_cm_cleared(uvp->uv_connvc);
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 27
+ * Signalling AAL failure
+ *
+ * Change PVC state to UNI_PVC_ACT_DOWN.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act27(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_PVC_ACT_DOWN;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 28
+ * Signalling AAL established
+ *
+ * Set PVC state to UNI_PVC_ACTIVE.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act28(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_PVC_ACTIVE;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 29
+ * Protocol error
+ *
+ * Send a RELEASE COMPLETE message with cause 81, "invalid call
+ * reference value"
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection (may
+ * be NULL)
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act29(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Send a RELEASE COMPLETE message
+ */
+ rc = unisig_send_release_complete(usp, uvp, msg,
+ UNI_IE_CAUS_CREF);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 30
+ * Release routine called while SSCF session down, or SSCF session
+ * reset or lost while in UNI_CALL_PRESENT
+ *
+ * Go to UNI_FREE state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act30(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Clear the call state
+ */
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 31
+ * Accept handler called in UNI_FREE state.
+ *
+ * The call was in UNI_CALL_PRESENT state when it was closed because
+ * of an SSCF failure. Return an error indication. The accept
+ * handler will free the VCCB and return the proper code to the
+ * caller.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act31(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ return(ENETDOWN);
+}
+
+
+/*
+ * Initiate clearing a call by sending a RELEASE message.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to UNI signalling message that the RELEASE
+ * responds to (may be NULL)
+ * cause the reason for clearing the call; 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
+ *
+ */
+static int
+unisig_vc_clear_call(usp, uvp, msg, cause)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+ int cause;
+{
+ int rc;
+
+ /*
+ * Clear the retry count
+ */
+ uvp->uv_retry = 0;
+
+ /*
+ * Make sure the ATM attributes block has a valid cause code,
+ * if needed
+ */
+ if (cause == T_ATM_ABSENT &&
+ uvp->uv_connvc->cvc_attr.cause.tag !=
+ T_ATM_PRESENT) {
+ uvp->uv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT;
+ uvp->uv_connvc->cvc_attr.cause.v.coding_standard =
+ T_ATM_ITU_CODING;
+ uvp->uv_connvc->cvc_attr.cause.v.location =
+ T_ATM_LOC_USER;
+ uvp->uv_connvc->cvc_attr.cause.v.cause_value =
+ usp->us_proto == ATM_SIG_UNI30 ?
+ T_ATM_CAUSE_UNSPECIFIED_NORMAL :
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING;
+ }
+
+ /*
+ * Send a RELEASE message
+ */
+ rc = unisig_send_release(usp, uvp, msg, cause);
+ if (rc)
+ return(rc);
+
+ /*
+ * Start timer T308
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308);
+
+ /*
+ * Set the VCCB state
+ */
+ uvp->uv_sstate = UNI_RELEASE_REQUEST;
+ if (uvp->uv_ustate != VCCU_ABORT)
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
OpenPOWER on IntegriCloud