96cdb64ea9
Pointed out by: phk
2234 lines
46 KiB
C
2234 lines
46 KiB
C
/*
|
|
*
|
|
* ===================================
|
|
* HARP | Host ATM Research Platform
|
|
* ===================================
|
|
*
|
|
*
|
|
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
|
* made available by Network Computing Services, Inc. ("NetworkCS")
|
|
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
|
* support of any kind.
|
|
*
|
|
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
|
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
|
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
|
* In no event shall NetworkCS be responsible for any damages, including
|
|
* but not limited to consequential damages, arising from or relating to
|
|
* any use of the Software or related support.
|
|
*
|
|
* Copyright 1994-1998 Network Computing Services, Inc.
|
|
*
|
|
* Copies of this Software may be made, however, the above copyright
|
|
* notice must be reproduced on all copies.
|
|
*
|
|
* @(#) $FreeBSD$
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* ATM Forum UNI 3.0/3.1 Signalling Manager
|
|
* ----------------------------------------
|
|
*
|
|
* VC state machine
|
|
*
|
|
*/
|
|
|
|
#include <netatm/kern_include.h>
|
|
|
|
#include <netatm/uni/unisig_var.h>
|
|
#include <netatm/uni/unisig_msg.h>
|
|
|
|
#ifndef lint
|
|
__RCSID("@(#) $FreeBSD$");
|
|
#endif
|
|
|
|
|
|
/*
|
|
* 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=%p, state=%d, event=%d, action=%d\n",
|
|
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, cause;
|
|
|
|
/*
|
|
* Set cause code
|
|
*/
|
|
if ((msg != NULL) && (msg->msg_ie_caus != NULL)) {
|
|
unisig_cause_attr_from_ie(&uvp->uv_connvc->cvc_attr,
|
|
msg->msg_ie_caus);
|
|
cause = T_ATM_ABSENT;
|
|
} else
|
|
cause = T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER;
|
|
|
|
/*
|
|
* Clear the VCCB
|
|
*/
|
|
rc = unisig_clear_vcc(usp, uvp, cause);
|
|
|
|
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
|
|
*/
|
|
if ((msg != NULL) && (msg->msg_ie_caus != NULL))
|
|
unisig_cause_attr_from_ie(&uvp->uv_connvc->cvc_attr,
|
|
msg->msg_ie_caus);
|
|
else
|
|
unisig_cause_attr_from_user(&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=%p, uvp=%p, msg=%p\n",
|
|
usp, uvp, 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 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, cause;
|
|
|
|
/*
|
|
* Send generic cause code if one is not already set
|
|
*/
|
|
if (uvp->uv_connvc->cvc_attr.cause.tag == T_ATM_PRESENT)
|
|
cause = T_ATM_ABSENT;
|
|
else
|
|
cause = T_ATM_CAUSE_CALL_REJECTED;
|
|
|
|
/*
|
|
* Send a RELEASE COMPLETE message
|
|
*/
|
|
rc = unisig_send_release_complete(usp, uvp, msg, cause);
|
|
|
|
/*
|
|
* 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 *)NULL,
|
|
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
|
|
*/
|
|
if (msg->msg_ie_caus != NULL)
|
|
unisig_cause_attr_from_ie(&uvp->uv_connvc->cvc_attr,
|
|
msg->msg_ie_caus);
|
|
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
|
|
*/
|
|
if (msg->msg_ie_caus != NULL)
|
|
unisig_cause_attr_from_ie(&uvp->uv_connvc->cvc_attr,
|
|
msg->msg_ie_caus);
|
|
else
|
|
unisig_cause_attr_from_user(&uvp->uv_connvc->cvc_attr,
|
|
T_ATM_CAUSE_UNSPECIFIED_NORMAL);
|
|
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_ABSENT);
|
|
|
|
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=%p, uvp=%p, msg=%p\n",
|
|
usp, uvp, 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_MESSAGE_INCOMPATIBLE_WITH_CALL_STATE);
|
|
}
|
|
|
|
/*
|
|
* 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, cause);
|
|
}
|
|
}
|
|
|
|
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=%p, uvp=%p, msg=%p\n",
|
|
usp, uvp, 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
|
|
*/
|
|
if (uvp->uv_connvc->cvc_attr.cause.tag != T_ATM_PRESENT)
|
|
unisig_cause_attr_from_user(&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);
|
|
}
|