diff options
Diffstat (limited to 'sys/netatm/uni/unisig_vc_state.c')
-rw-r--r-- | sys/netatm/uni/unisig_vc_state.c | 2223 |
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); +} |