1740 lines
61 KiB
C
1740 lines
61 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipl2tp_v2_state.c,v $ $Revision: 1.10.12.1 $
|
|
* $Source: /home/interpeak/CVSRoot/ipl2tp/src/ipl2tp_v2_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_v2.h"
|
|
#include "ipl2tp_v2_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_v2_compulsory_avp_void[] =
|
|
{
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_sccrq[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_PROTOCOL_VERSION,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_HOST_NAME,
|
|
IPL2TP_AVP_FRAMING_CAPABILITIES,
|
|
IPL2TP_AVP_ASSIGNED_TUNNEL_ID,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_sccrp[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_PROTOCOL_VERSION,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_HOST_NAME,
|
|
IPL2TP_AVP_FRAMING_CAPABILITIES,
|
|
IPL2TP_AVP_ASSIGNED_TUNNEL_ID,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_scccn[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_stopccn[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_ASSIGNED_TUNNEL_ID,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_RESULT_CODE,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_hello[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_icrq[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_ASSIGNED_SESSION_ID,
|
|
IPL2TP_AVP_CALL_SERIAL_NUMBER,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_icrp[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_ASSIGNED_SESSION_ID,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_iccn[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_TX_CONNECT_SPEED,
|
|
IPL2TP_AVP_FRAMING_TYPE,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_ocrq[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_ASSIGNED_SESSION_ID,
|
|
IPL2TP_AVP_CALL_SERIAL_NUMBER,
|
|
IPL2TP_AVP_MINIMUM_BPS,
|
|
IPL2TP_AVP_MAXIMUM_BPS,
|
|
IPL2TP_AVP_BEARER_TYPE,
|
|
IPL2TP_AVP_FRAMING_TYPE,
|
|
IPL2TP_AVP_CALLED_NUMBER,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_ocrp[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_ASSIGNED_SESSION_ID,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_occn[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_TX_CONNECT_SPEED,
|
|
IPL2TP_AVP_FRAMING_TYPE,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_cdn[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_ASSIGNED_SESSION_ID,
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_RESULT_CODE,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_wen[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_CALL_ERRORS,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
IP_STATIC CONST Ip_u8 ipl2tp_v2_compulsory_avp_sli[] =
|
|
{
|
|
IPL2TP_AVP_VISIBLE | IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_ACCM,
|
|
IPL2TP_AVP_END
|
|
};
|
|
|
|
|
|
IP_STATIC CONST Ip_u8 *ipl2tp_v2_avp_compulsory[] =
|
|
{
|
|
ipl2tp_v2_compulsory_avp_void, /* (0) reserved */
|
|
ipl2tp_v2_compulsory_avp_sccrq, /* (1) sccrq */
|
|
ipl2tp_v2_compulsory_avp_sccrp, /* (2) sccrp */
|
|
ipl2tp_v2_compulsory_avp_scccn, /* (3) scccn */
|
|
ipl2tp_v2_compulsory_avp_stopccn, /* (4) stopccn */
|
|
ipl2tp_v2_compulsory_avp_void, /* (5) reserved */
|
|
ipl2tp_v2_compulsory_avp_hello, /* (6) hello */
|
|
ipl2tp_v2_compulsory_avp_ocrq, /* (7) ocrq */
|
|
ipl2tp_v2_compulsory_avp_ocrp, /* (8) ocrp */
|
|
ipl2tp_v2_compulsory_avp_occn, /* (9) occn */
|
|
ipl2tp_v2_compulsory_avp_icrq, /* (10) icrq */
|
|
ipl2tp_v2_compulsory_avp_icrp, /* (11) icrp */
|
|
ipl2tp_v2_compulsory_avp_iccn, /* (12) iccn */
|
|
ipl2tp_v2_compulsory_avp_void, /* (13) reserved */
|
|
ipl2tp_v2_compulsory_avp_cdn, /* (14) cdn */
|
|
ipl2tp_v2_compulsory_avp_wen, /* (15) wen */
|
|
ipl2tp_v2_compulsory_avp_sli, /* (16) sli */
|
|
ipl2tp_v2_compulsory_avp_void, /* (17) unimplemented */
|
|
ipl2tp_v2_compulsory_avp_void, /* (18) unimplemented */
|
|
ipl2tp_v2_compulsory_avp_void, /* (19) unimplemented */
|
|
ipl2tp_v2_compulsory_avp_void, /* (20) unimplemented */
|
|
IP_NULL
|
|
};
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v2_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_v2_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.
|
|
*/
|
|
|
|
/* Protocol version */
|
|
if (avp->protocol_version.ver > IPL2TP_PROTOCOL_VER)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_PROTVERSION,
|
|
IPL2TP_RES_StopCCN_PROTOCOL_VERSION,
|
|
IPL2TP_PROTOCOL_VER,
|
|
"Invalid protocol version");
|
|
IPCOM_LOG5(WARNING,
|
|
"%s(%d,%s): Protocol version %d.%d is not supported, only "
|
|
IPL2TP_NUM2STR(IPL2TP_PROTOCOL_VER) ".x",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
(int)avp->protocol_version.ver,
|
|
(int)avp->protocol_version.rev);
|
|
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
|
|
/* Host name */
|
|
IPL2TP_SAFE_SWAP(avp->host_name, tunnel->common.host_name);
|
|
IPL2TP_SAFE_SWAP(avp->vendor_name, tunnel->common.vendor_name);
|
|
|
|
/* Firmware revision */
|
|
tunnel->v.v2.firmware_revision = IP_GET_NTOHS(&avp->firmware_revision.value);
|
|
|
|
/* Protocol version */
|
|
tunnel->v.v2.protocol_version[0] = avp->protocol_version.ver;
|
|
tunnel->v.v2.protocol_version[1] = avp->protocol_version.rev;
|
|
|
|
/* Assigned tunnel ID */
|
|
if (avp->assigned_tunnel_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_L2TPV2],
|
|
(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);
|
|
|
|
/* Framing capabilities */
|
|
tunnel->v.v2.framing_capabilities = (Ip_u8)avp->framing_capabilities.value;
|
|
|
|
/* Bearer capabilities */
|
|
tunnel->v.v2.bearer_capabilities = (Ip_u8)avp->bearer_capabilities.value;
|
|
|
|
/* 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_L2TPV2],
|
|
(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_L2TPV2],
|
|
(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_L2TPV2],
|
|
(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_L2TPV2],
|
|
(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_v2_state_bearer_verify
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipl2tp_v2_state_bearer_verify(Ipl2tp_session *session,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
/* Check if allowed bearer */
|
|
if (avp->bearer_type.head.ok)
|
|
{
|
|
if (avp->bearer_type.value > IPL2TP_MIB_BEARER_NONE &&
|
|
(ipl2tp_pw_bearer2bits(avp->bearer_type.value) &
|
|
ipl2tp_pw_bearer2bits(session->tunnel->v.v2.bearer_capabilities)) == 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(session->tunnel,
|
|
IPL2TP_STATUS_BADBEARER,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
IPL2TP_ERR_OUT_OF_RANGE,
|
|
"Invalid bearer type for tunnel");
|
|
|
|
IPCOM_LOG5(WARNING,
|
|
"%s(%d,%d,%s): Invalid bearer type for tunnel: %d",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int) session->tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr),
|
|
(int) avp->bearer_type.value);
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
session->attr.bearer_type = (Ip_u8)avp->bearer_type.value;
|
|
}
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v2_state_framing_verify
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipl2tp_v2_state_framing_verify(Ipl2tp_session *session,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
/* Check if allowed framing */
|
|
if (avp->framing_type.value > IPL2TP_MIB_FRAMING_NONE &&
|
|
(ipl2tp_pw_framing2bits(avp->framing_type.value) &
|
|
ipl2tp_pw_framing2bits(session->tunnel->v.v2.framing_capabilities)) == 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(session->tunnel,
|
|
IPL2TP_STATUS_BADFRAMING,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
IPL2TP_ERR_OUT_OF_RANGE,
|
|
"Invalid framing type for tunnel");
|
|
|
|
IPCOM_LOG5(WARNING,
|
|
"%s(%d,%d,%s): Invalid framing type for tunnel: %d",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int) session->tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr),
|
|
(int) avp->framing_type.value);
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
session->attr.framing_type = (Ip_u8)avp->framing_type.value;
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v2_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_v2_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 (avp->message_type.value == IPL2TP_MSG_OCRQ ||
|
|
avp->message_type.value == IPL2TP_MSG_ICRQ ||
|
|
avp->message_type.value == IPL2TP_MSG_OCRP ||
|
|
avp->message_type.value == IPL2TP_MSG_ICRP)
|
|
{
|
|
if ((session->remote.key.ident = avp->assigned_session_id.value) == 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_IDZERO,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
IPL2TP_ERR_OUT_OF_RANGE,
|
|
"Assigned session ID is 0");
|
|
IPCOM_LOG5(WARNING,
|
|
"%s(%d,%d,%s): Assigned session ID is 0 in %s",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(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)
|
|
{
|
|
/* Check if allowed bearer */
|
|
if (ipl2tp_v2_state_bearer_verify(session, avp) == IP_FALSE)
|
|
return IPL2TP_STATUS_ERROR;
|
|
|
|
/* Check framing */
|
|
if (ipl2tp_v2_state_framing_verify(session, avp) == IP_FALSE)
|
|
return IPL2TP_STATUS_ERROR;
|
|
|
|
|
|
/* Enter rest of OCRQ */
|
|
session->attr.minimum_bps = avp->minimum_bps.value;
|
|
session->attr.maximum_bps = avp->maximum_bps.value;
|
|
|
|
IPL2TP_SAFE_SWAP(avp->called_number, session->attr.called_number);
|
|
IPL2TP_SAFE_SWAP(avp->sub_address, session->attr.sub_address);
|
|
|
|
session->common.call_serial_number = avp->call_serial_number.value;
|
|
}
|
|
else if (avp->message_type.value == IPL2TP_MSG_ICRQ)
|
|
{
|
|
session->common.call_serial_number = avp->call_serial_number.value;
|
|
|
|
/* Physical channel ID may be provided */
|
|
IPL2TP_SAFE_ASSIGN(avp->physical_channel_id, session->attr.phys_chan_id);
|
|
|
|
/* Calling number may be provided. */
|
|
IPL2TP_SAFE_SWAP(avp->calling_number, session->attr.calling_number);
|
|
IPL2TP_SAFE_SWAP(avp->called_number, session->attr.called_number);
|
|
IPL2TP_SAFE_SWAP(avp->sub_address, session->attr.sub_address);
|
|
|
|
}
|
|
else if (avp->message_type.value == IPL2TP_MSG_OCRP)
|
|
{
|
|
/* Physical channel ID may be provided */
|
|
IPL2TP_SAFE_ASSIGN(avp->physical_channel_id, session->attr.phys_chan_id);
|
|
}
|
|
else if (avp->message_type.value == IPL2TP_MSG_ICRP)
|
|
{
|
|
/* Not much to do */
|
|
}
|
|
else if (avp->message_type.value == IPL2TP_MSG_OCCN)
|
|
{
|
|
if (ipl2tp_v2_state_framing_verify(session, avp) != IP_TRUE)
|
|
return IPL2TP_STATUS_ERROR;
|
|
|
|
IPL2TP_SAFE_ASSIGN(avp->tx_connect_speed, session->attr.tx_connect_speed);
|
|
IPL2TP_SAFE_ASSIGN(avp->rx_connect_speed, session->attr.rx_connect_speed);
|
|
|
|
if (avp->sequencing_required.head.ok)
|
|
session->v.v2.sequencing = 1;
|
|
}
|
|
else if (avp->message_type.value == IPL2TP_MSG_ICCN)
|
|
{
|
|
if (ipl2tp_v2_state_framing_verify(session, avp) != IP_TRUE)
|
|
return IPL2TP_STATUS_ERROR;
|
|
|
|
/* Do the AVP's */
|
|
IPL2TP_SAFE_ASSIGN(avp->tx_connect_speed, session->attr.tx_connect_speed);
|
|
|
|
IPL2TP_SAFE_VEC(avp->initial_received_lcp_confreq, session->attr.first_received_confreq);
|
|
IPL2TP_SAFE_VEC(avp->last_sent_lcp_confreq, session->attr.last_sent_confreq);
|
|
IPL2TP_SAFE_VEC(avp->last_received_lcp_confreq, session->attr.last_received_confreq);
|
|
|
|
IPL2TP_SAFE_ASSIGN(avp->proxy_authen_type, session->attr.auth_method);
|
|
IPL2TP_SAFE_SWAP(avp->proxy_authen_name, session->attr.proxy_authen_name);
|
|
IPL2TP_SAFE_VEC(avp->proxy_authen_challenge, session->attr.proxy_authen_challenge);
|
|
IPL2TP_SAFE_ASSIGN(avp->proxy_authen_id, session->attr.proxy_authen_id);
|
|
IPL2TP_SAFE_VEC(avp->proxy_authen_response, session->attr.proxy_authen_response);
|
|
|
|
IPL2TP_SAFE_SWAP(avp->private_group_id, session->attr.private_group_id);
|
|
IPL2TP_SAFE_ASSIGN(avp->rx_connect_speed, session->attr.rx_connect_speed);
|
|
|
|
if (avp->sequencing_required.head.ok)
|
|
session->v.v2.sequencing = 1;
|
|
}
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v2_state_response_check
|
|
*===========================================================================
|
|
* Description: Check if challenge response OK.
|
|
* Parameters: tunnel - Tunnel descriptor.
|
|
* avp - Parsed AVPs.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v2_state_response_check(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
/* A response may only be present when requested */
|
|
if (tunnel->attr.authentication == IPL2TP_MIB_AUTH_CHALLENGE)
|
|
{
|
|
if (avp->challenge_response.head.ok == 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_BADAUTH,
|
|
IPL2TP_RES_StopCCN_NOT_AUTHORIZED,
|
|
0,
|
|
"Missing challenge response from peer");
|
|
IPCOM_LOG3(WARNING,
|
|
"%s(%d,%s) Missing challenge response from peer",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
}
|
|
else if (tunnel->attr.secret.size == 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_BADAUTH,
|
|
IPL2TP_RES_StopCCN_NOT_AUTHORIZED,
|
|
0,
|
|
"No authentication secret configured");
|
|
IPCOM_LOG3(WARNING,
|
|
"%s(%d,%s) No authentication secret configured",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
}
|
|
else if (ipl2tp_avp_challenge_verify(avp, tunnel) != IP_TRUE)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_BADAUTH,
|
|
IPL2TP_RES_StopCCN_NOT_AUTHORIZED,
|
|
0,
|
|
"Challenge authentication failure");
|
|
IPCOM_LOG3(WARNING,
|
|
"%s(%d,%s) Challenge authentication failure",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG3(DEBUG,
|
|
"%s(%d,%s) Challenge authentication OK",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (avp->challenge_response.head.ok != 0)
|
|
{
|
|
IPCOM_LOG3(WARNING,
|
|
"%s(%d,%s) Unsolicited challenge response from peer",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
}
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v2_state_session_callback
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v2_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_L2TPV2],
|
|
(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_L2TPV2],
|
|
(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_v2_state_tunnel_initialize
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v2_state_tunnel_initialize(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
int cb;
|
|
|
|
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_L2TPV2],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
|
|
if (ipl2tp_message_sccrp(tunnel, avp) != IPL2TP_STATUS_OK)
|
|
return IPL2TP_STATUS_ERROR;
|
|
|
|
IPCOM_LOG3(INFO,
|
|
"%s(%d,%s): Received good SCCRQ, sent SCCRP",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(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_v2_state_tunnel_initialize
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v2_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_L2TPV2],
|
|
(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_L2TPV2],
|
|
(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_v2_state_machine_session
|
|
*===========================================================================
|
|
* Description: Handle an incoming IPL2TP message according to state.
|
|
* Parameters: tunnel - Tunnel descriptor.
|
|
* session - Session descriptor.
|
|
* avp - Parsed AVPs from the message.
|
|
* Returns: IPL2TP_SUCCESS - Success.
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v2_state_machine_session(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_session *session,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
|
|
if (session == IP_NULL)
|
|
return (IPL2TP_STATUS_ERROR);
|
|
|
|
/* State machine */
|
|
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;
|
|
|
|
if (ipl2tp_v2_state_session_setup(session, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
session->state = IPL2TP_SSTATE_WAIT_CS_ANSWER;
|
|
ipl2tp_state_establish_session_timeout_init(session, 1);
|
|
|
|
/* Status callback */
|
|
if (ipl2tp_v2_state_session_callback(session,
|
|
IPL2TP_INCOMING_REQUEST,
|
|
"Incoming session request") != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
tunnel->needzlb = 1;
|
|
break;
|
|
case IPL2TP_MSG_ICRP:
|
|
/* Increment session count here since a teardown will decrement */
|
|
tunnel->statistics.active_sessions++;
|
|
|
|
if (session->state != IPL2TP_SSTATE_WAIT_REPLY)
|
|
goto errstate;
|
|
|
|
if (ipl2tp_v2_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++;
|
|
|
|
if (ipl2tp_v2_state_session_callback(session,
|
|
IPL2TP_INCOMING_ESTABLISHED,
|
|
"Incoming tunnel established") != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
break;
|
|
|
|
case IPL2TP_MSG_ICCN:
|
|
if (session->state != IPL2TP_SSTATE_WAIT_CONNECT)
|
|
goto errstate;
|
|
|
|
if (ipl2tp_v2_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_v2_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;
|
|
|
|
if (ipl2tp_v2_state_session_setup(session, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
/* Notify user */
|
|
if (ipl2tp_v2_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;
|
|
|
|
IPCOM_LOG4(INFO,
|
|
"%s(%d,%d,%s): Received good OCRQ, sent OCRP",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int) tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
|
|
/* All done? */
|
|
if (ipl2tp_v2_state_session_callback(session,
|
|
IPL2TP_OUTGOING_REPLY,
|
|
"Outgoing session reply") != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
break;
|
|
case IPL2TP_MSG_OCRP:
|
|
/* Only valid if we're waiting for the reply */
|
|
if (session->state != IPL2TP_SSTATE_WAIT_REPLY)
|
|
goto errstate;
|
|
|
|
if (ipl2tp_v2_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;
|
|
|
|
if (ipl2tp_v2_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_v2_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_L2TPV2],
|
|
(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_SLI:
|
|
IPL2TP_AVAILABLE();
|
|
IPL2TP_SAFE_CALLBACK(session->attr.slicallback,
|
|
(session->attr.user_data,
|
|
&session->local.key,
|
|
avp->accm.send_accm,
|
|
avp->accm.receive_accm));
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
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_L2TPV2],
|
|
(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_v2_state_machine_tunnel
|
|
*===========================================================================
|
|
* 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_v2_state_machine_tunnel(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
/* */
|
|
if (tunnel->slave != IP_NULL)
|
|
{
|
|
/* */
|
|
Ipl2tp_tunnel *slave = tunnel->slave;
|
|
|
|
/* */
|
|
slave->slave = IP_NULL;
|
|
tunnel->slave = IP_NULL;
|
|
|
|
/* Need to notify regarding key change */
|
|
/* 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 V2 */
|
|
ipl2tp_tunnel_delete(slave);
|
|
}
|
|
|
|
|
|
/* State machine */
|
|
switch (avp->message_type.value)
|
|
{
|
|
case IPL2TP_MSG_SCCRQ:
|
|
if (ipl2tp_v2_state_tunnel_setup(tunnel, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
if (ipl2tp_state_tie_break_win(tunnel, avp) == 0)
|
|
{
|
|
/* Remove new tunnel */
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_EXISTS,
|
|
IPL2TP_RES_StopCCN_CHANNEL_EXISTS,
|
|
0,
|
|
"Tunnel already exists");
|
|
ipl2tp_state_tunnel_teardown(tunnel);
|
|
break;
|
|
}
|
|
|
|
/* Initialize the tunnel */
|
|
if (ipl2tp_v2_state_tunnel_initialize(tunnel, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
break;
|
|
|
|
case IPL2TP_MSG_SCCRP:
|
|
if (tunnel->state != IPL2TP_TSTATE_WAIT_CTL_REPLY)
|
|
goto errstate;
|
|
|
|
if (ipl2tp_v2_state_tunnel_setup(tunnel, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
if (ipl2tp_v2_state_response_check(tunnel, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
if (ipl2tp_message_scccn(tunnel, avp) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
|
|
if (ipl2tp_v2_state_tunnel_finalize(tunnel, avp, IPL2TP_INCOMING_ESTABLISHED) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
break;
|
|
|
|
case IPL2TP_MSG_SCCCN:
|
|
if (tunnel->state != IPL2TP_TSTATE_WAIT_CTL_CONN)
|
|
goto errstate;
|
|
|
|
if (ipl2tp_v2_state_tunnel_finalize(tunnel, avp, IPL2TP_OUTGOING_ESTABLISHED) != IPL2TP_STATUS_OK)
|
|
goto stopcdn;
|
|
tunnel->needzlb = 1;
|
|
break;
|
|
|
|
case IPL2TP_MSG_StopCCN:
|
|
/* Log */
|
|
IPCOM_LOG6(INFO,
|
|
"%s(%d,%s): Got StopCCN with result: %d, error: %d, message:\'%s\'",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(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 errstate;
|
|
|
|
/* Reply */
|
|
tunnel->needzlb = 1;
|
|
break;
|
|
|
|
default:
|
|
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_L2TPV2],
|
|
(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));
|
|
|
|
stopcdn:
|
|
ipl2tp_message_stopccn(tunnel);
|
|
ipl2tp_state_tunnel_teardown(tunnel);
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v2_state_machine
|
|
*===========================================================================
|
|
* Description: Handle an incoming IPL2TP message according to state.
|
|
* Parameters: tunnel - Tunnel descriptor.
|
|
* session - Session descriptor.
|
|
* avp - Parsed AVPs from the message.
|
|
* Returns: IPL2TP_SUCCESS - Success.
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_v2_state_machine(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_session *session,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
/* State machine */
|
|
switch (avp->message_type.value)
|
|
{
|
|
case IPL2TP_MSG_SCCRQ:
|
|
case IPL2TP_MSG_SCCRP:
|
|
case IPL2TP_MSG_SCCCN:
|
|
case IPL2TP_MSG_StopCCN:
|
|
case IPL2TP_MSG_HELLO:
|
|
return ipl2tp_v2_state_machine_tunnel(tunnel, avp);
|
|
|
|
case IPL2TP_MSG_ICRQ:
|
|
case IPL2TP_MSG_ICRP:
|
|
case IPL2TP_MSG_ICCN:
|
|
case IPL2TP_MSG_OCRQ:
|
|
case IPL2TP_MSG_OCRP:
|
|
case IPL2TP_MSG_OCCN:
|
|
case IPL2TP_MSG_CDN:
|
|
case IPL2TP_MSG_SLI:
|
|
return ipl2tp_v2_state_machine_session(tunnel,session,avp);
|
|
|
|
default:
|
|
if (avp->message_type.head.mandatory)
|
|
return ipl2tp_v2_state_machine_tunnel(tunnel,avp);
|
|
else
|
|
{
|
|
if (session)
|
|
{
|
|
IPCOM_LOG5(WARNING,
|
|
"%s(%d,%d,%s): Got unknown mandatory control message: %d",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int) tunnel->local.key.ident,
|
|
(int) session->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
(int)avp->message_type.value);
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%s): Got unknown mandatory control message: %d",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int) tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
(int)avp->message_type.value);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v2_state_machine_sccrq
|
|
*===========================================================================
|
|
* Description: Handle an incoming IPL2TP SCCRQ according to state.
|
|
* Parameters: tunnel - Tunnel descriptor.
|
|
* Returns: IPL2TP_SUCCESS - Success.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_status
|
|
ipl2tp_v2_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);
|
|
|
|
/* 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 AVP */
|
|
return ipl2tp_v2_state_machine_tunnel(tunnel, tunnel->sccrq.avp);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_v2_state_control_input
|
|
*===========================================================================
|
|
* Description: Handle an incoming L2TP control packet.
|
|
* Parameters: packet - An L2TP packet.
|
|
* ipaddr - IP address of sender.
|
|
* Returns: IPL2TP_SUCCESS - Success.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_status
|
|
ipl2tp_v2_state_control_input(Ipl2tp_v2_header *message,
|
|
Ip_u16 length,
|
|
union Ip_sockaddr_union *addr)
|
|
{
|
|
|
|
Ipl2tp_tunnel *tunnel = IP_NULL;
|
|
Ipl2tp_session *session = IP_NULL;
|
|
Ipl2tp_status status;
|
|
Ipl2tp_avp *avp;
|
|
Ip_size_t mindex = sizeof(*message);
|
|
Ip_size_t message_length = IP_GET_NTOHS(&message->length);
|
|
Ip_u16 flags = IP_GET_NTOHS(&message->flv);
|
|
Ipl2tp_key tkey;
|
|
Ipl2tp_key skey;
|
|
|
|
IPL2TP_UNUSED(length);
|
|
|
|
tkey.version = IPL2TP_VERSION_L2TPV2;
|
|
skey.version = IPL2TP_VERSION_L2TPV2;
|
|
tkey.ident = IP_GET_NTOHS(&message->tunnel_id);
|
|
skey.ident = IP_GET_NTOHS(&message->session_id);
|
|
|
|
/* Do we have the offset field? */
|
|
if (IP_BIT_ISSET(flags, IPL2TP_HEADER_FLAG_OFFSET))
|
|
{
|
|
Ipl2tp_v2_umessage *umessage = (Ipl2tp_v2_umessage *) message;
|
|
|
|
/* Move past the offset */
|
|
mindex += 2;
|
|
|
|
/* And the rest of the offset */
|
|
mindex += IP_GET_NTOHS(&umessage->len_seq_off.offset);
|
|
}
|
|
|
|
/* Log the reception */
|
|
ipl2tp_v2_dlog_packet(addr, message, "Receiving");
|
|
|
|
/* Allocate an AVP structure */
|
|
if ((avp = (Ipl2tp_avp *)ipcom_malloc(sizeof(*avp))) == IP_NULL)
|
|
{
|
|
IPCOM_LOG4(ERR,
|
|
"%s(%d,%d,%s): Out of memory when decoding message",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int)tkey.ident,
|
|
(int)skey.ident,
|
|
ipl2tp_util_ntoa(addr));
|
|
return IPL2TP_STATUS_NOMEM;
|
|
}
|
|
|
|
/* Clear result */
|
|
ipcom_memset(avp, 0, sizeof(*avp));
|
|
|
|
avp->version = IPL2TP_VERSION_L2TPV2;
|
|
avp->compulsory = ipl2tp_v2_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 *)message,
|
|
mindex,
|
|
message_length,
|
|
IP_FALSE,
|
|
IP_NULL,
|
|
addr);
|
|
|
|
/* An SCCRQ message */
|
|
if (avp->message_type.value == IPL2TP_MSG_SCCRQ &&
|
|
ipl2tp.enable_v3 == IPL2TP_MIB_ENABLED)
|
|
{
|
|
/* See if we've seen the required V3 AVP's? */
|
|
if (avp->v3_seen)
|
|
{
|
|
/* This is a v3 handshake attempt */
|
|
ipl2tp_avp_delete(avp);
|
|
return IPL2TP_STATUS_NEGOTIATION;
|
|
}
|
|
}
|
|
|
|
/* Get tunnel ID */
|
|
if (tkey.ident == 0)
|
|
{
|
|
avp->status |= 1L << ipl2tp_state_tunnel_find(&tunnel,
|
|
avp,
|
|
addr,
|
|
avp->assigned_tunnel_id.value,
|
|
IPL2TP_ATTR_TRANSPORT_UDP);
|
|
}
|
|
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_L2TPV2],
|
|
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;
|
|
}
|
|
|
|
/* Do control channel stuff */
|
|
tunnel->needzlb = 0;
|
|
avp->status |= 1L << ipl2tp_trpt_sequence_check(tunnel,
|
|
IP_GET_NTOHS(&message->nr),
|
|
IP_GET_NTOHS(&message->ns),
|
|
IPL2TP_V2_ZLB(message_length),
|
|
IP_TRUE);
|
|
|
|
/* Get session ID */
|
|
if (skey.ident == 0)
|
|
{
|
|
if (avp->message_type.value >= IPL2TP_MSG_OCRQ)
|
|
{
|
|
avp->status |= 1L << ipl2tp_state_session_find(&session,
|
|
avp,
|
|
tunnel,
|
|
avp->assigned_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_L2TPV2],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(addr),
|
|
ipl2tp_message_name(avp->message_type.value),
|
|
(int)skey.ident);
|
|
|
|
avp->status |= 1L << IPL2TP_STATUS_IGNORE;
|
|
}
|
|
|
|
/* Abort if message is to be ignored */
|
|
if (avp->status & (1L << IPL2TP_STATUS_IGNORE))
|
|
{
|
|
IPCOM_LOG5(DEBUG,
|
|
"%s(%d,%d,%s): Ignoring %s",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int)tunnel->local.key.ident,
|
|
(int)skey.ident,
|
|
ipl2tp_util_ntoa(addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
if(tunnel->sccrq.avp == avp)
|
|
{
|
|
tunnel->sccrq.avp = IP_NULL;
|
|
}
|
|
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_LOG5(WARNING,
|
|
"%s(%d,%d,%s): Got SCCRQ for tunnel in %s state",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int)tunnel->local.key.ident,
|
|
(int)skey.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(message, (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_LOG4(ERR,
|
|
"%s(%d,%d,%s): Out of memory when decoding message",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int)tunnel->local.key.ident,
|
|
(int)skey.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;
|
|
|
|
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_LOG4(WARNING,
|
|
"%s(%d,%d,%s): Tunnel creation aborted",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int)tunnel->local.key.ident,
|
|
(int)skey.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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Parse possible hidden AVPs in message */
|
|
if (avp->hidden != 0)
|
|
{
|
|
avp->status |= 1L << ipl2tp_avp_parse(avp,
|
|
(Ip_u8 *)message,
|
|
mindex,
|
|
message_length,
|
|
IP_TRUE,
|
|
tunnel,
|
|
addr);
|
|
}
|
|
|
|
/* Finally handle all accumulated errors */
|
|
if (avp->status & (1L << IPL2TP_STATUS_IGNORE))
|
|
{
|
|
IPCOM_LOG5(DEBUG,
|
|
"%s(%d,%d,%s): Ignoring %s",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int)tunnel->local.key.ident,
|
|
(int)skey.ident,
|
|
ipl2tp_util_ntoa(addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
if(tunnel->sccrq.avp == avp)
|
|
{
|
|
tunnel->sccrq.avp = IP_NULL;
|
|
}
|
|
|
|
ipl2tp_avp_delete(avp);
|
|
ipl2tp_state_maybe_zlb(tunnel);
|
|
return IPL2TP_STATUS_IGNORE;
|
|
}
|
|
else if (avp->status & (1L << IPL2TP_STATUS_TEARDOWN))
|
|
{
|
|
IPCOM_LOG5(DEBUG,
|
|
"%s(%d,%d,%s): Teardown requested when receiving %s",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int)tunnel->local.key.ident,
|
|
(int)skey.ident,
|
|
ipl2tp_util_ntoa(addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
if(tunnel->sccrq.avp == avp)
|
|
{
|
|
tunnel->sccrq.avp = IP_NULL;
|
|
}
|
|
|
|
ipl2tp_avp_delete(avp);
|
|
|
|
if (session != IP_NULL)
|
|
{
|
|
if (session->remote.key.ident != 0)
|
|
{
|
|
ipl2tp_message_cdn(session);
|
|
}
|
|
ipl2tp_state_session_teardown(session);
|
|
}
|
|
else if (tunnel != IP_NULL)
|
|
{
|
|
if (tunnel->remote.key.ident != 0)
|
|
{
|
|
ipl2tp_message_stopccn(tunnel);
|
|
}
|
|
ipl2tp_state_tunnel_teardown(tunnel);
|
|
}
|
|
|
|
ipl2tp_state_maybe_zlb(tunnel);
|
|
return IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
|
|
IPCOM_LOG5(DEBUG,
|
|
"%s(%d,%d,%s): Feeding %s to state machine",
|
|
ipl2tp_versions[IPL2TP_VERSION_L2TPV2],
|
|
(int)tunnel->local.key.ident,
|
|
(int)skey.ident,
|
|
ipl2tp_util_ntoa(addr),
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
|
|
/* Feed message to the state machine */
|
|
status = ipl2tp_v2_state_machine(tunnel, session, avp);
|
|
|
|
if(tunnel->sccrq.avp == avp)
|
|
{
|
|
tunnel->sccrq.avp = IP_NULL;
|
|
}
|
|
|
|
ipl2tp_avp_delete(avp);
|
|
ipl2tp_state_maybe_zlb(tunnel);
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|