1759 lines
62 KiB
C
1759 lines
62 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipl2tp_v3_state.c,v $ $Revision: 1.8.12.2 $
|
|
* $Source: /home/interpeak/CVSRoot/ipl2tp/src/ipl2tp_v3_state.c,v $
|
|
* $Author: hxu0 $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#include "ipl2tp_h.h"
|
|
#include "ipl2tp_api.h"
|
|
#include "ipl2tp_avp.h"
|
|
#include "ipl2tp_data.h"
|
|
#include "ipl2tp_message.h"
|
|
#include "ipl2tp_state.h"
|
|
#include "ipl2tp_pseudowire.h"
|
|
#include "ipl2tp_trpt.h"
|
|
|
|
#include "ipl2tp_v3.h"
|
|
#include "ipl2tp_v3_state.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tpv2_compulsory_avp_*
|
|
*===========================================================================
|
|
*
|
|
* Indicates which AVP types that are compulsory in a message.
|
|
*/
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_void[] =
|
|
{
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_sccrq[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_ROUTER_ID,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_HOST_NAME,
|
|
IPL2TP_AVP_PSEUDOWIRE_CAPABILITIES_LIST,
|
|
IPL2TP_AVP_ASSIGNED_CONTROL_CONNECTION_ID,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_sccrp[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_ROUTER_ID,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_HOST_NAME,
|
|
IPL2TP_AVP_PSEUDOWIRE_CAPABILITIES_LIST,
|
|
IPL2TP_AVP_ASSIGNED_CONTROL_CONNECTION_ID,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_scccn[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_stopccn[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_RESULT_CODE,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_hello[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_icrq[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_LOCAL_SESSION_ID,
|
|
IPL2TP_AVP_REMOTE_SESSION_ID,
|
|
IPL2TP_AVP_CALL_SERIAL_NUMBER,
|
|
IPL2TP_AVP_PSEUDOWIRE_TYPE,
|
|
IPL2TP_AVP_REMOTE_END_ID,
|
|
IPL2TP_AVP_CIRCUIT_STATUS,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_icrp[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_LOCAL_SESSION_ID,
|
|
IPL2TP_AVP_REMOTE_SESSION_ID,
|
|
IPL2TP_AVP_CIRCUIT_STATUS,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_iccn[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_LOCAL_SESSION_ID,
|
|
IPL2TP_AVP_REMOTE_SESSION_ID,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_ocrq[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_LOCAL_SESSION_ID,
|
|
IPL2TP_AVP_REMOTE_SESSION_ID,
|
|
IPL2TP_AVP_CALL_SERIAL_NUMBER,
|
|
IPL2TP_AVP_PSEUDOWIRE_TYPE,
|
|
IPL2TP_AVP_REMOTE_END_ID,
|
|
IPL2TP_AVP_CIRCUIT_STATUS,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_ocrp[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_LOCAL_SESSION_ID,
|
|
IPL2TP_AVP_REMOTE_SESSION_ID,
|
|
IPL2TP_AVP_CIRCUIT_STATUS,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_occn[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_LOCAL_SESSION_ID,
|
|
IPL2TP_AVP_REMOTE_SESSION_ID,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_cdn[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_RESULT_CODE,
|
|
IPL2TP_AVP_LOCAL_SESSION_ID,
|
|
IPL2TP_AVP_REMOTE_SESSION_ID,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_wen[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_LOCAL_SESSION_ID,
|
|
IPL2TP_AVP_REMOTE_SESSION_ID,
|
|
IPL2TP_AVP_CALL_ERRORS,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v3_compulsory_avp_sli[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_LOCAL_SESSION_ID,
|
|
IPL2TP_AVP_REMOTE_SESSION_ID,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 *ipl2tp_v3_avp_compulsory[] =
|
|
{
|
|
ipl2tp_v3_compulsory_avp_void, /* (0) reserved */
|
|
ipl2tp_v3_compulsory_avp_sccrq, /* (1) sccrq */
|
|
ipl2tp_v3_compulsory_avp_sccrp, /* (2) sccrp */
|
|
ipl2tp_v3_compulsory_avp_scccn, /* (3) scccn */
|
|
ipl2tp_v3_compulsory_avp_stopccn, /* (4) stopccn */
|
|
ipl2tp_v3_compulsory_avp_void, /* (5) reserved */
|
|
ipl2tp_v3_compulsory_avp_hello, /* (6) hello */
|
|
ipl2tp_v3_compulsory_avp_ocrq, /* (7) ocrq */
|
|
ipl2tp_v3_compulsory_avp_ocrp, /* (8) ocrp */
|
|
ipl2tp_v3_compulsory_avp_occn, /* (9) occn */
|
|
ipl2tp_v3_compulsory_avp_icrq, /* (10) icrq */
|
|
ipl2tp_v3_compulsory_avp_icrp, /* (11) icrp */
|
|
ipl2tp_v3_compulsory_avp_iccn, /* (12) iccn */
|
|
ipl2tp_v3_compulsory_avp_void, /* (13) reserved */
|
|
ipl2tp_v3_compulsory_avp_cdn, /* (14) cdn */
|
|
ipl2tp_v3_compulsory_avp_wen, /* (15) wen */
|
|
ipl2tp_v3_compulsory_avp_sli, /* (16) sli */
|
|
ipl2tp_v3_compulsory_avp_void, /* (17) unimplemented */
|
|
ipl2tp_v3_compulsory_avp_void, /* (18) unimplemented */
|
|
ipl2tp_v3_compulsory_avp_void, /* (19) unimplemented */
|
|
ipl2tp_v3_compulsory_avp_void, /* (20) unimplemented */
|
|
IP_NULL
|
|
};
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_tunnel_setup
|
|
*===========================================================================
|
|
* Description: Check if AVPs in SCCRQ or SCCRP message are appropriate.
|
|
* Parameters: tunnel - Tunnel descriptor.
|
|
* avp - Parsed AVPs from the message.
|
|
* Returns: IPL2TP_STATUS_OK if ok.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipl2tp_v3_state_tunnel_setup(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
/*
|
|
* No need to check that the compulsory AVPs exist since
|
|
* they already should have been checked when parsing.
|
|
*/
|
|
|
|
/* Host name */
|
|
IPL2TP_SAFE_SWAP(avp->host_name, tunnel->common.host_name);
|
|
/* Vendor name */
|
|
IPL2TP_SAFE_SWAP(avp->vendor_name, tunnel->common.vendor_name);
|
|
|
|
/* Authentication method */
|
|
if (avp->message_digest.head.ok && avp->message_type.value == IPL2TP_MSG_SCCRQ)
|
|
{
|
|
tunnel->attr.authentication = IPL2TP_MIB_AUTH_DIGEST;
|
|
tunnel->attr.hmac = avp->message_digest.type;
|
|
}
|
|
|
|
/* Router Identifier */
|
|
tunnel->v.v3.router_id = avp->router_id.value;
|
|
|
|
/* Assigned tunnel ID */
|
|
if (avp->assigned_control_connection_id.value == 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_IDZERO,
|
|
IPL2TP_RES_StopCCN_GENERAL_ERROR,
|
|
IPL2TP_ERR_OUT_OF_RANGE,
|
|
"Assigned tunnel ID is 0");
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%s): Assigned tunnel ID is 0 in %s",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
|
|
/* Assign peer ID */
|
|
IPL2TP_TUNNEL_ASSIGN_PEER_ID(tunnel, avp);
|
|
|
|
/* Pseudo wires capabilities */
|
|
ipl2tp_util_vector_dup(&tunnel->v.v3.pseudo_wires,
|
|
&avp->pseudo_wires_list.vec);
|
|
|
|
/* Preferred language */
|
|
IPL2TP_SAFE_SWAP(avp->preferred_language, tunnel->v.v3.preferred_language);
|
|
|
|
/* RWS */
|
|
if (avp->receive_window_size.head.ok &&
|
|
(tunnel->common.receive_window_size = avp->receive_window_size.value) == 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_BADRECWIN,
|
|
IPL2TP_RES_StopCCN_GENERAL_ERROR,
|
|
IPL2TP_ERR_OUT_OF_RANGE,
|
|
"Receive window size is 0");
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%s): Receive window size is 0 in %s",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
|
|
/* Handle host name authentication */
|
|
if (tunnel->attr.authentication == IPL2TP_MIB_AUTH_SIMPLE)
|
|
{
|
|
if (tunnel->attr.peer_host_name == IP_NULL)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_BADAUTH,
|
|
IPL2TP_RES_StopCCN_NOT_AUTHORIZED,
|
|
0,
|
|
"No peer host name configured");
|
|
IPCOM_LOG3(WARNING,
|
|
"%s(%d,%s): No peer host name configured",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
else if (ipcom_strcmp(tunnel->common.host_name,
|
|
tunnel->attr.peer_host_name) != 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_BADAUTH,
|
|
IPL2TP_RES_StopCCN_NOT_AUTHORIZED,
|
|
0,
|
|
"Host name authentication failure");
|
|
IPCOM_LOG3(WARNING,
|
|
"%s(%d,%s): Host name authentication failure",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG3(DEBUG,
|
|
"%s(%d,%s): Host name authentication OK",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
}
|
|
}
|
|
|
|
/* Tie breaker */
|
|
IPL2TP_SAFE_VEC(avp->tie_breaker, tunnel->common.tie_breaker);
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_tunnel_initialize
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v3_state_tunnel_initialize(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
int cb;
|
|
|
|
/* Setup the tunnel */
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_OK,
|
|
IPL2TP_OUTGOING_REQUEST,
|
|
0,
|
|
"Outgoing tunnel request");
|
|
|
|
IPL2TP_AVAILABLE();
|
|
cb = IPL2TP_SAFE_ICALLBACK(tunnel->attr.scallback,
|
|
(tunnel->attr.user_data,
|
|
&tunnel->local.key,
|
|
&tunnel->last_result));
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
if (cb != 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_TEARDOWN,
|
|
IPL2TP_RES_StopCCN_GENERAL_ERROR,
|
|
IPL2TP_ERR_VENDOR_ERROR_LAC,
|
|
"Tunnel creation aborted");
|
|
IPCOM_LOG3(WARNING,
|
|
"%s(%d,%s): Tunnel creation aborted",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
|
|
/* Send reply */
|
|
if (ipl2tp_message_sccrp(tunnel, avp) != IPL2TP_STATUS_OK)
|
|
return IPL2TP_STATUS_ERROR;
|
|
|
|
/* Final fixup */
|
|
IPCOM_LOG3(INFO,
|
|
"%s(%d,%s): Received good SCCRQ, sent SCCRP",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
(void)ipl2tp_state_establish_tunnel_timeout_init(tunnel, 1);
|
|
tunnel->state = IPL2TP_TSTATE_WAIT_CTL_CONN;
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_tunnel_finalize
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v3_state_tunnel_finalize(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_avp *avp,
|
|
Ip_u16 code)
|
|
{
|
|
int cb;
|
|
|
|
IPL2TP_UNUSED(avp);
|
|
|
|
(void)ipl2tp_state_establish_tunnel_timeout_init(tunnel, 0);
|
|
tunnel->state = IPL2TP_TSTATE_ESTABLISHED;
|
|
|
|
/* Notify client */
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_OK,
|
|
code,
|
|
0,
|
|
"Tunnel established");
|
|
|
|
IPL2TP_AVAILABLE();
|
|
cb = IPL2TP_SAFE_ICALLBACK(tunnel->attr.scallback,
|
|
(tunnel->attr.user_data,
|
|
&tunnel->local.key,
|
|
&tunnel->last_result));
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
if (cb != 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_TEARDOWN,
|
|
IPL2TP_RES_StopCCN_GENERAL_ERROR,
|
|
IPL2TP_ERR_VENDOR_ERROR_LAC,
|
|
"Tunnel creation aborted");
|
|
IPCOM_LOG3(WARNING,
|
|
"%s(%d,%s): Tunnel creation aborted",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
else
|
|
{
|
|
Ipl2tp_session *session;
|
|
|
|
/* Start HELLO processing */
|
|
ipl2tp_trpt_hello_init(tunnel);
|
|
|
|
IPCOM_LOG4(INFO,
|
|
"%s(%d,%s): Tunnel established, remote id is %d",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
(int)tunnel->remote.key.ident);
|
|
|
|
/* Start session negotiations */
|
|
for (session = IPCOM_LIST_FIRST(&tunnel->session_list);
|
|
session != IP_NULL;
|
|
session = IPCOM_LIST_NEXT(&session->head))
|
|
{
|
|
ipl2tp_message_rq(session);
|
|
}
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_sequencing_verify
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipl2tp_v3_state_sequencing_verify(Ipl2tp_session *session,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
/* Check if allowed framing */
|
|
if (avp->l2_sublayer.head.ok)
|
|
{
|
|
switch (avp->l2_sublayer.value)
|
|
{
|
|
case IPL2TP_ATTR_L2_SUBLAYER_NONE:
|
|
break;
|
|
case IPL2TP_ATTR_L2_SUBLAYER_DEFAULT:
|
|
session->attr.l2_sublayer = (Ip_u8)IPL2TP_ATTR_L2_SUBLAYER_DEFAULT;
|
|
break;
|
|
default:
|
|
IPL2TP_TUNNEL_RESULT_SET(session->tunnel,
|
|
IPL2TP_STATUS_BADL2,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
IPL2TP_ERR_OUT_OF_RANGE,
|
|
"Unknown L2 specific sublayer");
|
|
IPCOM_LOG5(WARNING,
|
|
"%s(%d,%d,%s): Invalid L2 sublayer type %d",
|
|
ipl2tp_versions[session->tunnel->local.key.version],
|
|
(int) session->tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr),
|
|
avp->l2_sublayer.value);
|
|
|
|
return IP_FALSE;
|
|
}
|
|
}
|
|
|
|
/* Data sequencing? */
|
|
if (avp->data_sequencing.head.ok)
|
|
{
|
|
switch (avp->data_sequencing.value)
|
|
{
|
|
case IPL2TP_ATTR_DATA_SEQUENCING_NEVER:
|
|
break;
|
|
case IPL2TP_ATTR_DATA_SEQUENCING_NONIPONLY:
|
|
case IPL2TP_ATTR_DATA_SEQUENCING_ALWAYS:
|
|
if (session->attr.l2_sublayer == 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(session->tunnel,
|
|
IPL2TP_STATUS_BADSEQUENCING,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
IPL2TP_ERR_OUT_OF_RANGE,
|
|
"Sequencing required, but no L2 sublayer specified");
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%d,%s): Data sequencing required, but no L2 sublayer specified",
|
|
ipl2tp_versions[session->tunnel->local.key.version],
|
|
(int) session->tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/* Store the value */
|
|
session->attr.data_sequencing = (Ip_u8) avp->data_sequencing.value;
|
|
break;
|
|
default:
|
|
IPL2TP_TUNNEL_RESULT_SET(session->tunnel,
|
|
IPL2TP_STATUS_BADSEQUENCING,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
IPL2TP_ERR_OUT_OF_RANGE,
|
|
"Unknown data sequencing type");
|
|
IPCOM_LOG5(WARNING,
|
|
"%s(%d,%d,%s): Invalid data sequencing type %d",
|
|
ipl2tp_versions[session->tunnel->local.key.version],
|
|
(int) session->tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr),
|
|
avp->data_sequencing.value);
|
|
return IP_FALSE;
|
|
}
|
|
}
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_session_sli
|
|
*===========================================================================
|
|
* Description: Update the SLI parameters for this session, and invoke
|
|
* the callbacks if required.
|
|
* Parameters: session - The session.
|
|
* avp - The AVP
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipl2tp_v3_state_session_sli(Ipl2tp_session *session,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
Ip_u16 mval;
|
|
|
|
if (IP_BIT_ISSET(avp->circuit_status.value, IPL2TP_ATTR_CIRCUIT_STATUS_ACTIVE))
|
|
{
|
|
/* Remote end of circuit is up */
|
|
mval = IPL2TP_MIB_UP;
|
|
}
|
|
else
|
|
{
|
|
/* Remote end of circuit is down */
|
|
mval = IPL2TP_MIB_DOWN;
|
|
}
|
|
|
|
/* The same? */
|
|
if (session->v.v3.circuit_status != mval)
|
|
{
|
|
session->v.v3.circuit_status = mval;
|
|
if (IP_BIT_ISFALSE(avp->circuit_status.value, IPL2TP_ATTR_CIRCUIT_STATUS_NEW))
|
|
{
|
|
IPL2TP_AVAILABLE();
|
|
IPL2TP_SAFE_CALLBACK(session->attr.slicallback,
|
|
(session->attr.user_data,
|
|
&session->local.key,
|
|
mval,
|
|
session->attr.circuit_status));
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_session_setup
|
|
*===========================================================================
|
|
* Description: Check if AVPs in ICRP or OCRQ message are appropriate.
|
|
* Parameters: session - Session descriptor.
|
|
* avp - Parsed AVPs from the message.
|
|
* Returns: IPL2TP_STATUS_OK if ok.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipl2tp_v3_state_session_setup(Ipl2tp_session *session,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
Ipl2tp_tunnel *tunnel = session->tunnel;
|
|
|
|
/*
|
|
* No need to check that the compulsory AVPs exist since
|
|
* they already should have been checked when parsing.
|
|
*/
|
|
|
|
/* Assigned session ID */
|
|
if ((session->remote.key.ident = avp->local_session_id.value) == 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_IDZERO,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
IPL2TP_ERR_OUT_OF_RANGE,
|
|
"Local session ID is 0");
|
|
|
|
IPCOM_LOG5(WARNING,
|
|
"%s(%d,%d,%s): Assigned session Id is 0 in %s",
|
|
ipl2tp_versions[tunnel->local.key.version],
|
|
(int) tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
|
|
if (avp->message_type.value == IPL2TP_MSG_OCRQ ||
|
|
avp->message_type.value == IPL2TP_MSG_ICRQ)
|
|
{
|
|
/* Check if allowed bearer */
|
|
if (ipl2tp_pw_valid_type(tunnel, avp->pseudo_wire_type.value) == IP_FALSE)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_BADPW,
|
|
IPL2TP_RES_CDN_PW_TYPE,
|
|
IPL2TP_ERR_OUT_OF_RANGE,
|
|
"Invalid pseudo wire type in session");
|
|
|
|
IPCOM_LOG5(WARNING,
|
|
"%s(%d,%d,%s): Invalid pseudo wire type %d",
|
|
ipl2tp_versions[tunnel->local.key.version],
|
|
(int) tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
avp->pseudo_wire_type.value);
|
|
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
|
|
session->attr.pw_type = (Ip_u8) avp->pseudo_wire_type.value;
|
|
|
|
if (ipl2tp_v3_state_sequencing_verify(session, avp) == IP_FALSE)
|
|
return IPL2TP_STATUS_ERROR;
|
|
|
|
/* Remote circuit status */
|
|
ipl2tp_v3_state_session_sli(session,avp);
|
|
|
|
/* Set common values */
|
|
session->common.call_serial_number = avp->call_serial_number.value;
|
|
|
|
/* The optionals */
|
|
|
|
/* Only if they exist */
|
|
IPL2TP_SAFE_ASSIGN(avp->tx_connect_speed64, session->attr.tx_connect_speed64);
|
|
IPL2TP_SAFE_ASSIGN(avp->rx_connect_speed64, session->attr.rx_connect_speed64);
|
|
|
|
/* */
|
|
IPL2TP_SAFE_VEC(avp->assigned_cookie, session->remote.cookie);
|
|
|
|
/* Store the remote end ID */
|
|
ipl2tp_util_vector_dup(&session->attr.remote_end_id, &avp->remote_end_id.vec);
|
|
|
|
if (avp->message_type.value == IPL2TP_MSG_ICRQ)
|
|
{
|
|
IPL2TP_SAFE_ASSIGN(avp->physical_channel_id, session->attr.phys_chan_id);
|
|
}
|
|
}
|
|
else if (avp->message_type.value == IPL2TP_MSG_OCRP ||
|
|
avp->message_type.value == IPL2TP_MSG_ICRP ||
|
|
avp->message_type.value == IPL2TP_MSG_ICCN ||
|
|
avp->message_type.value == IPL2TP_MSG_OCCN)
|
|
{
|
|
/* Check if allowed framing */
|
|
if (ipl2tp_v3_state_sequencing_verify(session, avp) == IP_FALSE)
|
|
return IPL2TP_STATUS_ERROR;
|
|
|
|
/* Session SLI */
|
|
ipl2tp_v3_state_session_sli(session,avp);
|
|
|
|
/* The optionals */
|
|
IPL2TP_SAFE_ASSIGN(avp->tx_connect_speed64, session->attr.tx_connect_speed64);
|
|
IPL2TP_SAFE_ASSIGN(avp->rx_connect_speed64, session->attr.rx_connect_speed64);
|
|
|
|
/* */
|
|
if (avp->message_type.value == IPL2TP_MSG_OCRP ||
|
|
avp->message_type.value == IPL2TP_MSG_ICRP)
|
|
{
|
|
IPL2TP_SAFE_ASSIGN(avp->physical_channel_id, session->attr.phys_chan_id);
|
|
IPL2TP_SAFE_VEC(avp->assigned_cookie, session->remote.cookie);
|
|
}
|
|
}
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_session_callback
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v3_state_session_callback(Ipl2tp_session *session,
|
|
Ip_u16 code,
|
|
const char *what)
|
|
{
|
|
int cb;
|
|
Ipl2tp_tunnel *tunnel = session->tunnel;
|
|
|
|
/* Notify waiting clients */
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_OK,
|
|
code,
|
|
0,
|
|
what);
|
|
|
|
IPL2TP_AVAILABLE();
|
|
cb = IPL2TP_SAFE_ICALLBACK(session->attr.scallback,
|
|
(session->attr.user_data,
|
|
&session->local.key,
|
|
&tunnel->last_result));
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
if (cb != 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_TEARDOWN,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
0,
|
|
"Session creation aborted");
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%d,%s): Session creation aborted",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG6(INFO,
|
|
"%s(%d,%d,%s): %s, remote id is %d",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
what,
|
|
(int)session->remote.key.ident);
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_machine_session
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v3_state_machine_session(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_session *session,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
/* Teardown? */
|
|
if (avp->status & (1L << IPL2TP_STATUS_TEARDOWN))
|
|
goto stopcdn;
|
|
|
|
/* The session specific functions */
|
|
switch (avp->message_type.value)
|
|
{
|
|
case IPL2TP_MSG_ICRQ:
|
|
/* Only valid if we're waiting for the reply */
|
|
if (session->state != IPL2TP_SSTATE_IDLE)
|
|
goto errstate;
|
|
|
|
/* Setup the session based on the AVP */
|
|
if (ipl2tp_v3_state_session_setup(session, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
/* Status callback */
|
|
session->state = IPL2TP_SSTATE_WAIT_CS_ANSWER;
|
|
ipl2tp_state_establish_session_timeout_init(session, 1);
|
|
|
|
if (ipl2tp_v3_state_session_callback(session,
|
|
IPL2TP_INCOMING_REQUEST,
|
|
"Incoming session request") != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
/* Ready to fly */
|
|
tunnel->needzlb = 1;
|
|
break;
|
|
case IPL2TP_MSG_ICRP:
|
|
/* Only valid if we're waiting for the reply */
|
|
if (session->state != IPL2TP_SSTATE_WAIT_REPLY)
|
|
goto errstate;
|
|
|
|
/* Setup the session based on the AVP */
|
|
if (ipl2tp_v3_state_session_setup(session, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
/* Ready to fly */
|
|
ipl2tp_message_iccn(session);
|
|
ipl2tp_state_establish_session_timeout_init(session, 0);
|
|
session->state = IPL2TP_SSTATE_ESTABLISHED;
|
|
|
|
tunnel->statistics.total_sessions++;
|
|
tunnel->statistics.active_sessions++;
|
|
|
|
/* Status callback */
|
|
if (ipl2tp_v3_state_session_callback(session,
|
|
IPL2TP_INCOMING_ESTABLISHED,
|
|
"Incoming session established") != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
|
|
break;
|
|
|
|
case IPL2TP_MSG_ICCN:
|
|
if (session->state != IPL2TP_SSTATE_WAIT_CONNECT)
|
|
goto errstate;
|
|
|
|
/* Setup the session based on the AVP */
|
|
if (ipl2tp_v3_state_session_setup(session, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
tunnel->statistics.total_sessions++;
|
|
tunnel->statistics.active_sessions++;
|
|
|
|
session->state = IPL2TP_SSTATE_ESTABLISHED;
|
|
ipl2tp_state_establish_session_timeout_init(session, 0);
|
|
|
|
/* Status callback */
|
|
if (ipl2tp_v3_state_session_callback(session,
|
|
IPL2TP_INCOMING_ESTABLISHED,
|
|
"Incoming session established") != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
tunnel->needzlb = 1;
|
|
break;
|
|
|
|
case IPL2TP_MSG_OCRQ:
|
|
if (session->state != IPL2TP_SSTATE_IDLE)
|
|
goto errstate;
|
|
|
|
/* Setup the session based on the AVP */
|
|
if (ipl2tp_v3_state_session_setup(session, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
/* Status callback */
|
|
if (ipl2tp_v3_state_session_callback(session,
|
|
IPL2TP_OUTGOING_REQUEST,
|
|
"Outgoing session request") != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
/* Ready to fly */
|
|
ipl2tp_message_ocrp(session);
|
|
ipl2tp_state_establish_session_timeout_init(session, 1);
|
|
session->state = IPL2TP_SSTATE_WAIT_CS_ANSWER;
|
|
|
|
/* Status callback */
|
|
if (ipl2tp_v3_state_session_callback(session,
|
|
IPL2TP_OUTGOING_REPLY,
|
|
"Outgoing session reply") != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
/* Done */
|
|
break;
|
|
case IPL2TP_MSG_OCRP:
|
|
/* Only valid if we're waiting for the reply */
|
|
if (session->state != IPL2TP_SSTATE_WAIT_REPLY)
|
|
goto errstate;
|
|
/* Setup the session based on the AVP */
|
|
if (ipl2tp_v3_state_session_setup(session, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
/**/
|
|
ipl2tp_state_establish_session_timeout_init(session, 1);
|
|
session->state = IPL2TP_SSTATE_WAIT_CONNECT;
|
|
break;
|
|
|
|
case IPL2TP_MSG_OCCN:
|
|
if (session->state != IPL2TP_SSTATE_WAIT_CONNECT)
|
|
goto errstate;
|
|
|
|
/* Setup the session based on the AVP */
|
|
if (ipl2tp_v3_state_session_setup(session, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
tunnel->statistics.total_sessions++;
|
|
tunnel->statistics.active_sessions++;
|
|
|
|
session->state = IPL2TP_SSTATE_ESTABLISHED;
|
|
ipl2tp_state_establish_session_timeout_init(session, 0);
|
|
|
|
/* Status callback */
|
|
if (ipl2tp_v3_state_session_callback(session,
|
|
IPL2TP_OUTGOING_ESTABLISHED,
|
|
"Outgoing session established") != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
tunnel->needzlb = 1;
|
|
break;
|
|
case IPL2TP_MSG_CDN:
|
|
/* Log */
|
|
IPCOM_LOG7(INFO,
|
|
"%s(%d,%d,%s): Got CDN with result: %d, error: %d, message:\'%s\'",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
(int)avp->result_code.result_code,
|
|
(int)avp->result_code.error_code,
|
|
(avp->result_code.error_message == IP_NULL ?
|
|
"<none>" : avp->result_code.error_message));
|
|
|
|
/* Set status */
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_GOTCDN,
|
|
avp->result_code.result_code,
|
|
avp->result_code.error_code,
|
|
"Got CDN from peer");
|
|
|
|
/* Prepare reply */
|
|
session->remote.key.ident = avp->assigned_session_id.value;
|
|
tunnel->needzlb = 1;
|
|
ipl2tp_state_session_teardown(session);
|
|
break;
|
|
case IPL2TP_MSG_WEN:
|
|
break;
|
|
case IPL2TP_MSG_SLI:
|
|
ipl2tp_v3_state_session_sli(session,avp);
|
|
tunnel->needzlb = 1;
|
|
break;
|
|
}
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
|
|
errstate:
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_STATE,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
0,
|
|
"Session state machine error");
|
|
IPCOM_LOG6(WARNING,
|
|
"%s(%d,%d,%s): Got %s for session in %s state",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_message_name(avp->message_type.value),
|
|
ipl2tp_state_sstate_name(session->state));
|
|
|
|
stopcdn:
|
|
if (session != IP_NULL)
|
|
{
|
|
ipl2tp_message_cdn(session);
|
|
ipl2tp_state_session_teardown(session);
|
|
}
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_machine_tunnel
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v3_state_machine_tunnel(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
|
|
/* Teardown? */
|
|
if (avp->status & (1L << IPL2TP_STATUS_TEARDOWN))
|
|
{
|
|
IPCOM_LOG4(DEBUG,
|
|
"%s(%d,%s): Tearing down when receiving %s",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
goto stopccn;
|
|
}
|
|
|
|
|
|
/* */
|
|
if (tunnel->slave != IP_NULL)
|
|
{
|
|
/* */
|
|
Ipl2tp_tunnel *slave = tunnel->slave;
|
|
|
|
/* */
|
|
slave->slave = IP_NULL;
|
|
tunnel->slave = IP_NULL;
|
|
|
|
/* Notify client */
|
|
IPL2TP_TUNNEL_RESULT_SET(slave,
|
|
IPL2TP_STATUS_NEGOTIATION,
|
|
0,
|
|
0,
|
|
"Redundant tunnel removed");
|
|
|
|
IPL2TP_AVAILABLE();
|
|
IPL2TP_SAFE_ICALLBACK(slave->attr.scallback,
|
|
(slave->attr.user_data,
|
|
&slave->local.key,
|
|
&slave->last_result));
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
|
|
/* Remove the slave tunnel; we're doing V3 */
|
|
ipl2tp_tunnel_delete(slave);
|
|
}
|
|
|
|
|
|
switch (avp->message_type.value)
|
|
{
|
|
case IPL2TP_MSG_ZLB:
|
|
case IPL2TP_MSG_ACK:
|
|
/* ZLB & ACK */
|
|
break;
|
|
|
|
case IPL2TP_MSG_SCCRQ:
|
|
switch (tunnel->state)
|
|
{
|
|
case IPL2TP_TSTATE_WAIT_AUTH_CB:
|
|
case IPL2TP_TSTATE_IDLE:
|
|
case IPL2TP_TSTATE_WAIT_CTL_REPLY:
|
|
/* Remote nonce */
|
|
/* 'tis is OK. We've gotten a SCCRQ and we're in IDLE mode */
|
|
if (ipl2tp_v3_state_tunnel_setup(tunnel, avp) != IPL2TP_STATUS_OK)
|
|
goto stopccn;
|
|
|
|
/* Verify that we aint got a TIE-BREAK situation */
|
|
if (ipl2tp_state_tie_break_win(tunnel, avp) == 0)
|
|
{
|
|
/* Remove new tunnel */
|
|
ipl2tp_state_tunnel_teardown(tunnel);
|
|
break;
|
|
}
|
|
|
|
/* Initialize the tunnel */
|
|
if (ipl2tp_v3_state_tunnel_initialize(tunnel, avp) != IPL2TP_STATUS_OK)
|
|
goto stopccn;
|
|
|
|
/* We're done */
|
|
break;
|
|
|
|
default:
|
|
/* Not allowed to receive SCCRQ in these states */
|
|
goto errstate;
|
|
}
|
|
|
|
break;
|
|
case IPL2TP_MSG_SCCRP:
|
|
/* Only valid in CTL REPLY state */
|
|
if (tunnel->state != IPL2TP_TSTATE_WAIT_CTL_REPLY)
|
|
goto errstate;
|
|
|
|
/* Setup the tunnel */
|
|
if (ipl2tp_v3_state_tunnel_setup(tunnel, avp) != IPL2TP_STATUS_OK)
|
|
goto stopccn;
|
|
|
|
/* Send the SCCCN */
|
|
if (ipl2tp_message_scccn(tunnel, avp) != IPL2TP_STATUS_OK)
|
|
goto stopccn;
|
|
|
|
/* Finalize the tunnel */
|
|
if (ipl2tp_v3_state_tunnel_finalize(tunnel, avp, IPL2TP_INCOMING_ESTABLISHED) != IPL2TP_STATUS_OK)
|
|
goto stopccn;
|
|
|
|
break;
|
|
case IPL2TP_MSG_SCCCN:
|
|
/* May only be done in wait ctl conn */
|
|
if (tunnel->state != IPL2TP_TSTATE_WAIT_CTL_CONN)
|
|
goto errstate;
|
|
|
|
/* Finalize the tunnel */
|
|
if (ipl2tp_v3_state_tunnel_finalize(tunnel, avp, IPL2TP_OUTGOING_ESTABLISHED) != IPL2TP_STATUS_OK)
|
|
goto stopccn;
|
|
|
|
tunnel->needzlb = 1;
|
|
break;
|
|
case IPL2TP_MSG_StopCCN:
|
|
/* StopCCN received; just tear the tunnel down */
|
|
IPCOM_LOG6(INFO,
|
|
"%s(%d,%s): Got StopCCN with result: %d, error: %d, message:\'%s\'",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
(int)avp->result_code.result_code,
|
|
(int)avp->result_code.error_code,
|
|
(avp->result_code.error_message == IP_NULL ?
|
|
"<none>" : avp->result_code.error_message));
|
|
|
|
/* Set status */
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_GOTSTOPCCN,
|
|
avp->result_code.result_code,
|
|
avp->result_code.error_code,
|
|
"Got StopCCN from peer");
|
|
|
|
/* Prepare reply */
|
|
IPL2TP_TUNNEL_ASSIGN_PEER_ID(tunnel, avp);
|
|
tunnel->needzlb = 1;
|
|
ipl2tp_state_tunnel_teardown(tunnel);
|
|
break;
|
|
case IPL2TP_MSG_HELLO:
|
|
if (tunnel->state != IPL2TP_TSTATE_ESTABLISHED)
|
|
goto stopccn;
|
|
/* Do send a ZLB */
|
|
tunnel->needzlb = 1;
|
|
break;
|
|
|
|
default:
|
|
/* Unknown message type */
|
|
goto errstate;
|
|
}
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
|
|
errstate:
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_STATE,
|
|
IPL2TP_RES_StopCCN_STATE_MACHINE,
|
|
0,
|
|
"Tunnel state machine error");
|
|
IPCOM_LOG6(WARNING,
|
|
"%s(%d,%s): Got %s(%u) for tunnel in %s state",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_message_name(avp->message_type.value),
|
|
(int)avp->message_type.value,
|
|
ipl2tp_state_tstate_name(tunnel->state));
|
|
|
|
stopccn:
|
|
ipl2tp_message_stopccn(tunnel);
|
|
ipl2tp_state_tunnel_teardown(tunnel);
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_machine
|
|
*===========================================================================
|
|
* Description: Handle an incoming IPL2TP message according to state.
|
|
* Parameters: tunnel - Tunnel descriptor.
|
|
* avp - Parsed AVPs from the message.
|
|
* Returns: IPL2TP_SUCCESS - Success.
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v3_state_machine(Ipl2tp_v3_header *header,
|
|
Ip_size_t length,
|
|
Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
Ipl2tp_key skey;
|
|
Ipl2tp_session *session = IP_NULL;
|
|
|
|
/* Deal with ignored 'status' */
|
|
if (avp->status & (1L << IPL2TP_STATUS_IGNORE))
|
|
{
|
|
IPCOM_LOG4(DEBUG,
|
|
"%s(%d,%s): Ignoring %s",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
return IPL2TP_STATUS_IGNORE;
|
|
}
|
|
|
|
if (tunnel->attr.authentication == IPL2TP_MIB_AUTH_DIGEST &&
|
|
avp->message_digest.head.ok == IP_FALSE)
|
|
{
|
|
IPCOM_LOG3(DEBUG,
|
|
"%s(%d,%s): Control message lacks authentication",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
|
|
return IPL2TP_STATUS_IGNORE;
|
|
}
|
|
|
|
/* Update in sequence parameters */
|
|
ipl2tp_trpt_sequence_check(tunnel,
|
|
IP_GET_NTOHS(&header->nr),
|
|
IP_GET_NTOHS(&header->ns),
|
|
IPL2TP_V3_ZLB(length, avp->message_type.value),
|
|
IP_TRUE);
|
|
|
|
skey.version = IPL2TP_VERSION_L2TPV3;
|
|
switch (avp->message_type.value)
|
|
{
|
|
case IPL2TP_MSG_ZLB:
|
|
case IPL2TP_MSG_ACK:
|
|
case IPL2TP_MSG_SCCRQ:
|
|
case IPL2TP_MSG_SCCRP:
|
|
case IPL2TP_MSG_SCCCN:
|
|
case IPL2TP_MSG_StopCCN:
|
|
case IPL2TP_MSG_HELLO:
|
|
return ipl2tp_v3_state_machine_tunnel(tunnel, avp);
|
|
|
|
case IPL2TP_MSG_OCRQ:
|
|
case IPL2TP_MSG_OCRP:
|
|
case IPL2TP_MSG_OCCN:
|
|
case IPL2TP_MSG_ICRQ:
|
|
case IPL2TP_MSG_ICRP:
|
|
case IPL2TP_MSG_ICCN:
|
|
case IPL2TP_MSG_CDN:
|
|
case IPL2TP_MSG_WEN:
|
|
case IPL2TP_MSG_SLI:
|
|
skey.ident = avp->remote_session_id.value;
|
|
|
|
/* Get session ID */
|
|
if (skey.ident == 0)
|
|
{
|
|
avp->status |= 1L << ipl2tp_state_session_find(&session,
|
|
avp,
|
|
tunnel,
|
|
avp->local_session_id.value);
|
|
}
|
|
else if ((session = ipl2tp_state_session_get(&skey, IP_NULL)) == IP_NULL &&
|
|
avp->message_type.value != IPL2TP_MSG_ZLB)
|
|
{
|
|
IPCOM_LOG5(WARNING,
|
|
"%s(%d,%s): Got %s with invalid session ID: %d",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_message_name(avp->message_type.value),
|
|
(int) skey.ident);
|
|
avp->status |= 1L << IPL2TP_STATUS_IGNORE;
|
|
}
|
|
|
|
if (session == IP_NULL)
|
|
{
|
|
IPCOM_LOG4(ERR,
|
|
"%s(%d,%s): No session exists when receiving session level call (%s)",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
avp->status |= 1L << IPL2TP_STATUS_IGNORE;
|
|
}
|
|
|
|
/* Deal with ignored 'status' */
|
|
if (avp->status & (1L << IPL2TP_STATUS_IGNORE))
|
|
{
|
|
IPCOM_LOG4(DEBUG,
|
|
"%s(%d,%s): Ignoring %s",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
return IPL2TP_STATUS_IGNORE;
|
|
}
|
|
|
|
/* We've gotten a session level control channel
|
|
* message, and we aint established yet */
|
|
if (tunnel->state != IPL2TP_TSTATE_ESTABLISHED)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_EXISTS,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
IPL2TP_ERR_NO_CONTROL_CONN,
|
|
"No control channel exists when receiving session level call");
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%s): No control channel exists when receiving session level call (%s)",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
|
|
avp->status |= 1L << IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
|
|
return ipl2tp_v3_state_machine_session(tunnel, session, avp);
|
|
default:
|
|
if (avp->message_type.head.mandatory)
|
|
return ipl2tp_v3_state_machine_tunnel(tunnel, avp);
|
|
else
|
|
{
|
|
#if 0
|
|
if (session)
|
|
{
|
|
IPCOM_LOG5(WARNING,
|
|
"%s(%d,%d,%s): Got unknown mandatory control message: %d",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
(int)avp->message_type.value);
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%s): Got unknown mandatory control message: %d",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
(int)avp->message_type.value);
|
|
#if 0
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_machine
|
|
*===========================================================================
|
|
* Description: Handle an incoming IPL2TP message according to state.
|
|
* Parameters: tunnel - Tunnel descriptor.
|
|
* Returns: IPL2TP_SUCCESS - Success.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_status
|
|
ipl2tp_v3_state_machine_sccrq(Ipl2tp_tunnel *tunnel)
|
|
{
|
|
/* Parse the second round */
|
|
tunnel->sccrq.avp->status |= 1L << ipl2tp_avp_parse(tunnel->sccrq.avp,
|
|
tunnel->sccrq.message,
|
|
tunnel->sccrq.message_index,
|
|
tunnel->sccrq.message_length,
|
|
IP_TRUE,
|
|
tunnel,
|
|
&tunnel->remote.addr);
|
|
|
|
/* Last chance to get peer tunnel ID */
|
|
IPL2TP_TUNNEL_ASSIGN_PEER_ID(tunnel, tunnel->sccrq.avp);
|
|
|
|
/* Must be authenticated? */
|
|
if (tunnel->attr.authentication == IPL2TP_MIB_AUTH_DIGEST &&
|
|
tunnel->sccrq.avp->message_digest.head.ok == IP_FALSE)
|
|
{
|
|
IPCOM_LOG3(DEBUG,
|
|
"%s(%d,%s): Control message lacks authentication",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
|
|
tunnel->sccrq.avp->status |= 1L << IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
|
|
/* Handle all accumulated errors */
|
|
if (tunnel->sccrq.avp->status & (1L << IPL2TP_STATUS_IGNORE))
|
|
{
|
|
/* */
|
|
return IPL2TP_STATUS_IGNORE;
|
|
}
|
|
else if (tunnel->sccrq.avp->status & (1L << IPL2TP_STATUS_TEARDOWN))
|
|
{
|
|
/* Get saved error codes and message */
|
|
IPL2TP_TUNNEL_RESULT_RESTORE(tunnel);
|
|
}
|
|
|
|
|
|
/* Do the final stuff */
|
|
return ipl2tp_v3_state_machine_tunnel(tunnel, tunnel->sccrq.avp);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v3_state_control_input
|
|
*===========================================================================
|
|
* Description: Handle an incoming L2TP control packet.
|
|
* Parameters: header - An L2TP packet.
|
|
* length - Length of the packet
|
|
* addr - IP address of sender.
|
|
* transport - Transport
|
|
* Returns: IPL2TP_SUCCESS - Success.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_status
|
|
ipl2tp_v3_state_control_input(Ipl2tp_v3_header *header,
|
|
Ip_u16 length,
|
|
union Ip_sockaddr_union *addr,
|
|
int transport)
|
|
{
|
|
Ipl2tp_tunnel *tunnel;
|
|
Ipl2tp_status status;
|
|
Ipl2tp_avp *avp;
|
|
Ip_size_t mindex = sizeof(*header);
|
|
Ip_size_t message_length = IP_GET_NTOHS(&header->length);
|
|
Ipl2tp_key tkey;
|
|
|
|
/**/
|
|
tkey.version = IPL2TP_VERSION_L2TPV3;
|
|
tkey.ident = IP_GET_NTOHL(&header->tunnel_id);
|
|
|
|
if ((avp = (Ipl2tp_avp *)ipcom_malloc(sizeof(*avp))) == IP_NULL)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"%s(%s): Out of memory when decoding message",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
ipl2tp_util_ntoa(addr));
|
|
return IPL2TP_STATUS_NOMEM;
|
|
}
|
|
|
|
/* Clear result */
|
|
ipcom_memset(avp, 0, sizeof(*avp));
|
|
|
|
avp->version = IPL2TP_VERSION_L2TPV3;
|
|
avp->compulsory = ipl2tp_v3_avp_compulsory;
|
|
|
|
/* Init bitmap */
|
|
BITINI(&avp->map, IPL2TP_AVP_MAX);
|
|
|
|
/* Parse non-hidden AVPs in message */
|
|
avp->status |= 1L << ipl2tp_avp_parse(avp,
|
|
(Ip_u8 *)header,
|
|
mindex,
|
|
message_length,
|
|
IP_FALSE,
|
|
IP_NULL,
|
|
addr);
|
|
|
|
/* Log the packet */
|
|
ipl2tp_v3_dlog_packet(addr, header, "Receiving");
|
|
|
|
/* Get tunnel ID */
|
|
if (tkey.ident == 0)
|
|
{
|
|
avp->status |= 1L << ipl2tp_state_tunnel_find(&tunnel,
|
|
avp,
|
|
addr,
|
|
avp->assigned_control_connection_id.value,
|
|
transport);
|
|
}
|
|
else if ((tunnel = ipl2tp_state_tunnel_get(&tkey)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%s): Got %s with invalid tunnel ID: %d",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
ipl2tp_util_ntoa(addr),
|
|
ipl2tp_message_name(avp->message_type.value),
|
|
(int)tkey.ident);
|
|
|
|
avp->status |= 1L << IPL2TP_STATUS_IGNORE;
|
|
}
|
|
|
|
/* Abort if invalid tunnel */
|
|
if (tunnel == IP_NULL)
|
|
{
|
|
ipl2tp_avp_delete(avp);
|
|
return IPL2TP_STATUS_IGNORE;
|
|
}
|
|
|
|
tunnel->statistics.in_octets += message_length;
|
|
tunnel->statistics.in_packets++;
|
|
|
|
/* Do control channel stuff */
|
|
tunnel->needzlb = 0;
|
|
avp->status |= 1L << ipl2tp_trpt_sequence_check(tunnel,
|
|
IP_GET_NTOHS(&header->nr),
|
|
IP_GET_NTOHS(&header->ns),
|
|
IPL2TP_V3_ZLB(length, avp->message_type.value),
|
|
IP_FALSE);
|
|
|
|
|
|
/* Abort if message is to be ignored */
|
|
if (avp->status & (1L << IPL2TP_STATUS_IGNORE))
|
|
{
|
|
IPCOM_LOG4(DEBUG,
|
|
"%s(%d,%s): Ignoring %s",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
ipl2tp_avp_delete(avp);
|
|
ipl2tp_state_maybe_zlb(tunnel);
|
|
return IPL2TP_STATUS_IGNORE;
|
|
}
|
|
|
|
/*
|
|
* An SCCRQ must trigger a callback at this early stage
|
|
* in order to get the authentication method and possibly
|
|
* the shared secret for this peer. This is required to
|
|
* decode hidden AVPs. Since the lookup may take some time,
|
|
* processing stops here and continues when the application
|
|
* calls ipl2tp_authentication_established().
|
|
*
|
|
*/
|
|
if (avp->message_type.value == IPL2TP_MSG_SCCRQ)
|
|
{
|
|
if (tunnel->state != IPL2TP_TSTATE_IDLE)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_STATE,
|
|
IPL2TP_RES_StopCCN_STATE_MACHINE,
|
|
0,
|
|
"Got SCCRQ for tunnel in non-idle state");
|
|
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%s): Got SCCRQ for tunnel in %s state",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(addr),
|
|
ipl2tp_state_tstate_name(tunnel->state));
|
|
|
|
avp->status |= 1L << IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
else if ((tunnel->sccrq.message = ipl2tp_util_memdup(header, (int)message_length, (int)message_length)) == IP_NULL)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_NOMEM,
|
|
IPL2TP_RES_StopCCN_GENERAL_ERROR,
|
|
IPL2TP_ERR_RESOURCE_LIMIT,
|
|
"Out of memory when decoding message");
|
|
IPCOM_LOG3(ERR,
|
|
"%s(%d,%s): Out of memory when decoding message",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(addr));
|
|
|
|
avp->status |= 1L << IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
else
|
|
{
|
|
int cb;
|
|
|
|
/* Save AVP */
|
|
tunnel->sccrq.avp = avp;
|
|
tunnel->sccrq.message_index = mindex;
|
|
tunnel->sccrq.message_length = message_length;
|
|
|
|
/* Store the remote nonce */
|
|
IPL2TP_SAFE_VEC(avp->authentication_nonce, tunnel->remote.nonce);
|
|
|
|
/* Update in sequence parameters */
|
|
avp->status |= 1L << ipl2tp_trpt_sequence_check(tunnel,
|
|
IP_GET_NTOHS(&header->nr),
|
|
IP_GET_NTOHS(&header->ns),
|
|
IP_FALSE,
|
|
IP_TRUE);
|
|
|
|
tunnel->state = IPL2TP_TSTATE_WAIT_AUTH_CB;
|
|
tunnel->needzlb = 1;
|
|
ipl2tp_state_maybe_zlb(tunnel);
|
|
|
|
/* Save possible error code for later teardown */
|
|
if (avp->status & (1L << IPL2TP_STATUS_TEARDOWN))
|
|
{
|
|
/* Store */
|
|
IPL2TP_TUNNEL_RESULT_SAVE(tunnel);
|
|
}
|
|
|
|
(void)ipl2tp_state_establish_tunnel_timeout_init(tunnel, 1);
|
|
|
|
/* Set the status message */
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_OK,
|
|
IPL2TP_OUTGOING_AUTHENTICATION,
|
|
0,
|
|
"Outgoing tunnel authentication request");
|
|
|
|
|
|
IPL2TP_AVAILABLE();
|
|
cb = IPL2TP_SAFE_ICALLBACK(tunnel->attr.scallback,
|
|
(tunnel->attr.user_data,
|
|
&tunnel->local.key,
|
|
&tunnel->last_result));
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
if (cb != 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_TEARDOWN,
|
|
IPL2TP_RES_StopCCN_GENERAL_ERROR,
|
|
IPL2TP_ERR_VENDOR_ERROR_LAC,
|
|
"Tunnel creation aborted");
|
|
IPCOM_LOG3(WARNING,
|
|
"%s(%d,%s): Tunnel creation aborted",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(addr));
|
|
|
|
avp->status |= 1L << IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* That's all for now folks. We now exit and allow the
|
|
* application to obtain the authentication for this host.
|
|
*/
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
}
|
|
}
|
|
else if (avp->message_type.value == IPL2TP_MSG_SCCRP)
|
|
{
|
|
if (tunnel->state != IPL2TP_TSTATE_WAIT_CTL_REPLY)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_STATE,
|
|
IPL2TP_RES_StopCCN_STATE_MACHINE,
|
|
0,
|
|
"Got SCCRP for tunnel in non wait-ctl_reply state");
|
|
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%s): Got SCCRP for tunnel in %s state",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(addr),
|
|
ipl2tp_state_tstate_name(tunnel->state));
|
|
|
|
avp->status |= 1L << IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
else
|
|
{
|
|
/* Store the remote nonce */
|
|
IPL2TP_SAFE_VEC(avp->authentication_nonce, tunnel->remote.nonce);
|
|
}
|
|
}
|
|
|
|
|
|
/* Parse possible hidden AVPs in message */
|
|
if (avp->hidden != 0)
|
|
{
|
|
avp->status |= 1L << ipl2tp_avp_parse(avp,
|
|
(Ip_u8 *)header,
|
|
mindex,
|
|
message_length,
|
|
IP_TRUE,
|
|
tunnel,
|
|
addr);
|
|
}
|
|
|
|
|
|
IPCOM_LOG4(DEBUG,
|
|
"%s(%d,%s): Feeding %s message to state machine",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
|
|
/* Feed message to the state machine */
|
|
status = ipl2tp_v3_state_machine(header, length, tunnel, avp);
|
|
|
|
ipl2tp_avp_delete(avp);
|
|
ipl2tp_state_maybe_zlb(tunnel);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|