1043 lines
35 KiB
C
1043 lines
35 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipl2tp_api_session.c,v $ $Revision: 1.5.16.3 $
|
|
* $Source: /home/interpeak/CVSRoot/ipl2tp/src/ipl2tp_api_session.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_api_session.h"
|
|
#include "ipl2tp_avp.h"
|
|
#include "ipl2tp_trpt.h"
|
|
#include "ipl2tp_util.h"
|
|
#include "ipl2tp_attr_h.h"
|
|
#include "ipl2tp_state.h"
|
|
#include "ipl2tp_message.h"
|
|
|
|
#include "ipl2tp_v2_pw.h"
|
|
#include "ipl2tp_v3_pw.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_session_attribute_set
|
|
*===========================================================================
|
|
* Description: Set session parameters
|
|
* Parameters: key - Session identifier.
|
|
* attr - Attribute object.
|
|
* Returns: IPL2TP_STATUS_OK if success.
|
|
* IPL2TP_STATUS_BADID if invalid session ID.
|
|
* IPL2TP_STATUS_BADPARAM if bad attribute object.
|
|
*/
|
|
IP_PUBLIC Ipl2tp_status
|
|
ipl2tp_api_session_attribute_set(Ipl2tp_key *key,
|
|
Ipl2tp_attrobj attr)
|
|
{
|
|
Ipl2tp_session *session;
|
|
Ipl2tp_status status;
|
|
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
if (ipl2tp.state != IPL2TP_STATE_OPEN)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: IPL2TP is not opened",
|
|
ipl2tp_versions[0]);
|
|
status = IPL2TP_STATUS_STATE;
|
|
}
|
|
else if (key->ident == 0)
|
|
{
|
|
switch (key->version)
|
|
{
|
|
case IPL2TP_VERSION_L2TPV3:
|
|
status = ipl2tp_attr_session_set(IP_NULL, &ipl2tp.session.v3.attr, attr);
|
|
break;
|
|
case IPL2TP_VERSION_L2TPV2:
|
|
default:
|
|
status = ipl2tp_attr_session_set(IP_NULL, &ipl2tp.session.v2.attr, attr);
|
|
break;
|
|
}
|
|
}
|
|
else if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"%s: Called ipl2tp_session_attribute_set() with invalid index: %d",
|
|
ipl2tp_versions[key->version],
|
|
(int)key->ident);
|
|
status = IPL2TP_STATUS_BADID;
|
|
}
|
|
else
|
|
{
|
|
status = ipl2tp_attr_session_set(session, &session->attr, attr);
|
|
}
|
|
|
|
IPL2TP_AVAILABLE();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_session_attribute_get
|
|
*===========================================================================
|
|
* Description: Get session parameters
|
|
* Parameters: key - Session identifier.
|
|
* attr - Attribute object.
|
|
* replies - Attribute replies.
|
|
* Returns: IPL2TP_STATUS_OK if success.
|
|
* IPL2TP_STATUS_BADID if invalid session ID.
|
|
* IPL2TP_STATUS_BADPARAM if bad attribute object.
|
|
*/
|
|
IP_PUBLIC Ipl2tp_status
|
|
ipl2tp_api_session_attribute_get(Ipl2tp_key *key,
|
|
Ipl2tp_attrobj attr,
|
|
Ipl2tp_attrobj *replies)
|
|
{
|
|
Ipl2tp_session *session;
|
|
Ipl2tp_status status;
|
|
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
if (ipl2tp.state != IPL2TP_STATE_OPEN)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: IPL2TP is not opened",
|
|
ipl2tp_versions[0]);
|
|
status = IPL2TP_STATUS_STATE;
|
|
}
|
|
else if (key->ident == 0)
|
|
{
|
|
switch (key->version)
|
|
{
|
|
case IPL2TP_VERSION_L2TPV3:
|
|
status = ipl2tp_attr_session_get(IP_NULL, &ipl2tp.session.v3.attr, attr, replies);
|
|
break;
|
|
case IPL2TP_VERSION_L2TPV2:
|
|
default:
|
|
status = ipl2tp_attr_session_get(IP_NULL, &ipl2tp.session.v2.attr, attr, replies);
|
|
break;
|
|
}
|
|
}
|
|
else if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"%s: Called ipl2tp_session_attribute_get() with invalid index: %d",
|
|
ipl2tp_versions[key->version],
|
|
(int)key->ident);
|
|
status = IPL2TP_STATUS_BADID;
|
|
}
|
|
else
|
|
{
|
|
status = ipl2tp_attr_session_get(session, &session->attr, attr, replies);
|
|
}
|
|
|
|
IPL2TP_AVAILABLE();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_session_open
|
|
*===========================================================================
|
|
* Description: Open a new session, either in a new tunnel or in an existing one.
|
|
* Parameters: sidp - Session ID pointer.
|
|
* key - Tunnel identifier.
|
|
* addr - IP address.
|
|
* tattr - Tunnel attributes.
|
|
* sattr - Session attributes.
|
|
* incoming - Is this an incoming or outgoing call?
|
|
* Returns: IPL2TP_STATUS_OK if Success.
|
|
* IPL2TP_STATUS_DRAIN if creation disabled.
|
|
* IPL2TP_STATUS_NOMEM if out of memory.
|
|
* IPL2TP_STATUS_BADPARAM if bad attribute object.
|
|
*/
|
|
IP_PUBLIC Ipl2tp_status
|
|
ipl2tp_api_session_open(Ipl2tp_key *sidp,
|
|
Ipl2tp_key *key,
|
|
union Ip_sockaddr_union *addr,
|
|
Ipl2tp_attrobj tattr,
|
|
Ipl2tp_attrobj sattr,
|
|
Ip_bool incoming)
|
|
{
|
|
Ipl2tp_tunnel *tunnel = IP_NULL;
|
|
Ipl2tp_session *session;
|
|
Ipl2tp_status status;
|
|
Ipl2tp_key tkey;
|
|
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
/* Deal with key */
|
|
if (key == IP_NULL)
|
|
{
|
|
key = &tkey;
|
|
key->ident = 0;
|
|
key->version = sidp->version;
|
|
}
|
|
|
|
if (ipl2tp.state != IPL2TP_STATE_OPEN)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: IPL2TP is not opened",
|
|
ipl2tp_versions[key->version]);
|
|
status = IPL2TP_STATUS_STATE;
|
|
goto leave;
|
|
}
|
|
|
|
if (ipl2tp.admin_state == IPL2TP_MIB_DISABLED ||
|
|
ipl2tp.drain_tunnels == IPL2TP_MIB_YES)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: Session creation currently disabled",
|
|
ipl2tp_versions[key->version]);
|
|
status = IPL2TP_STATUS_DRAIN;
|
|
goto leave;
|
|
}
|
|
|
|
sidp->version = key->version;
|
|
/* Check if old tunnel is available */
|
|
if (((tunnel = ipl2tp_state_tunnel_get(key)) != IP_NULL &&
|
|
tunnel->state > IPL2TP_TSTATE_TEARDOWN) ||
|
|
(addr != IP_NULL && (tunnel = ipl2tp_state_tunnel_find_by_addr(addr, sidp->version))) != IP_NULL)
|
|
{
|
|
/* Old tunnel available */
|
|
if (tunnel->drain_tunnel == IPL2TP_MIB_YES)
|
|
{
|
|
IPCOM_LOG3(ERR,
|
|
"%s(%d,%s): Session creation currently disabled",
|
|
ipl2tp_versions[key->version],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(addr));
|
|
status = IPL2TP_STATUS_DRAIN;
|
|
goto leave;
|
|
}
|
|
else if ((session = ipl2tp_session_new(tunnel, IP_NULL, 0)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG3(ERR,
|
|
"%s(%d,%s): Out of memory when creating session",
|
|
ipl2tp_versions[key->version],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(addr));
|
|
status = IPL2TP_STATUS_NOMEM;
|
|
goto leave;
|
|
}
|
|
|
|
/* Enter session properties */
|
|
session->local_open = 1;
|
|
session->outgoing = (Ip_u8)(incoming? 0 : 1);
|
|
|
|
if ((status = ipl2tp_attr_session_set(session, &session->attr,
|
|
sattr)) != IPL2TP_STATUS_OK)
|
|
{
|
|
ipl2tp_session_delete(session);
|
|
goto leave;
|
|
}
|
|
|
|
session->state = IPL2TP_SSTATE_WAIT_TUNNEL;
|
|
|
|
/* Start session establishment if tunnel OK */
|
|
if (tunnel->state == IPL2TP_TSTATE_ESTABLISHED)
|
|
{
|
|
ipl2tp_message_rq(session);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (addr == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: No tunnel address supplied",
|
|
ipl2tp_versions[key->version]);
|
|
|
|
status = IPL2TP_STATUS_ERROR;
|
|
goto leave;
|
|
}
|
|
else if (key->version == IPL2TP_VERSION_L2TPV2 && ipl2tp.enable_v2 == IPL2TP_MIB_DISABLED)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: IPL2TPV2 is not enabled",
|
|
ipl2tp_versions[0]);
|
|
status = IPL2TP_STATUS_STATE;
|
|
goto leave;
|
|
}
|
|
else if (key->version == IPL2TP_VERSION_L2TPV3 && ipl2tp.enable_v3 == IPL2TP_MIB_DISABLED)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: IPL2TPV3 is not enabled",
|
|
ipl2tp_versions[0]);
|
|
status = IPL2TP_STATUS_STATE;
|
|
goto leave;
|
|
}
|
|
|
|
/* No, have to create one */
|
|
if ((tunnel = ipl2tp_tunnel_new(key->version, addr)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: Out of memory when creating tunnel",
|
|
ipl2tp_versions[key->version]);
|
|
|
|
status = IPL2TP_STATUS_NOMEM;
|
|
goto leave;
|
|
}
|
|
|
|
/* Enter tunnel properties */
|
|
tunnel->local_open = 1;
|
|
|
|
if ((status = ipl2tp_attr_tunnel_set(tunnel, &tunnel->attr, tattr)) !=
|
|
IPL2TP_STATUS_OK)
|
|
{
|
|
ipl2tp_tunnel_delete(tunnel);
|
|
goto leave;
|
|
}
|
|
|
|
tunnel->state = IPL2TP_TSTATE_WAIT_CTL_REPLY;
|
|
|
|
/* Create session descriptor */
|
|
if ((session = ipl2tp_session_new(tunnel, IP_NULL, 0)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG3(ERR,
|
|
"%s(%d,%s): Out of memory when creating session",
|
|
ipl2tp_versions[key->version],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(addr));
|
|
ipl2tp_tunnel_delete(tunnel);
|
|
status = IPL2TP_STATUS_NOMEM;
|
|
goto leave;
|
|
}
|
|
|
|
/* Enter session properties */
|
|
session->local_open = 1;
|
|
session->outgoing = (Ip_u8)(incoming? 0 : 1);
|
|
|
|
if ((status = ipl2tp_attr_session_set(session, &session->attr,
|
|
sattr)) != IPL2TP_STATUS_OK)
|
|
{
|
|
ipl2tp_tunnel_delete(tunnel);
|
|
ipl2tp_session_delete(session);
|
|
goto leave;
|
|
}
|
|
|
|
session->state = IPL2TP_SSTATE_WAIT_TUNNEL;
|
|
|
|
/* Start tunnel establishhment */
|
|
ipl2tp_message_sccrq(tunnel);
|
|
(void)ipl2tp_state_establish_tunnel_timeout_init(tunnel, 1);
|
|
}
|
|
|
|
if (key->ident == 0)
|
|
{
|
|
key->ident = tunnel->local.key.ident;
|
|
}
|
|
|
|
sidp->ident = session->local.key.ident;
|
|
|
|
leave:
|
|
IPL2TP_AVAILABLE();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_session_close
|
|
*===========================================================================
|
|
* Description: Close an IPL2TP session. This is performed without affecting the
|
|
* tunnel in which the session resides.
|
|
* Parameters: session_id - The session to close.
|
|
* Returns: IPL2TP_STATUS_OK if success.
|
|
* IPL2TP_STATUS_BADID if invalid session ID.
|
|
*/
|
|
IP_PUBLIC Ipl2tp_status
|
|
ipl2tp_api_session_close(Ipl2tp_key *key)
|
|
{
|
|
Ipl2tp_session *session;
|
|
Ipl2tp_status status = IPL2TP_STATUS_OK;
|
|
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
if (ipl2tp.state != IPL2TP_STATE_OPEN)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: IPL2TP is not opened",
|
|
ipl2tp_versions[key->version]);
|
|
status = IPL2TP_STATUS_STATE;
|
|
}
|
|
else if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"%s: Called ipl2tp_session_close() with invalid session ID: %d",
|
|
ipl2tp_versions[key->version],
|
|
(int)key->ident);
|
|
status = IPL2TP_STATUS_BADID;
|
|
}
|
|
else
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(session->tunnel,
|
|
IPL2TP_STATUS_CLOSE,
|
|
IPL2TP_RES_CDN_ADMINISTRATIVE,
|
|
0,
|
|
"Session closed");
|
|
|
|
/* Send termination message */
|
|
ipl2tp_message_cdn(session);
|
|
ipl2tp_state_session_teardown(session);
|
|
}
|
|
|
|
IPL2TP_AVAILABLE();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_session_is_closed
|
|
*===========================================================================
|
|
* Description: Determine whether the session with the given ID has been closed.
|
|
* Parameters: key - Session identifier
|
|
* Returns: IP_TRUE if session has been closed.
|
|
* IP_FALSE if otherwise.
|
|
*/
|
|
IP_PUBLIC Ip_bool
|
|
ipl2tp_api_session_is_closed(Ipl2tp_key *key)
|
|
{
|
|
if ((ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL)
|
|
return IP_TRUE;
|
|
else
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_session_next
|
|
*===========================================================================
|
|
* Description: Retrieves the tunnel identifier
|
|
* Parameters: tkey - The tunnel identifier
|
|
* last - Last session we retrieved, or IP_NULL if first
|
|
* next - [OUT] next tunnel key.
|
|
* Returns: IPL2TP_STATUS_OK if next has been properly filled in.
|
|
*
|
|
*/
|
|
IP_PUBLIC Ipl2tp_status
|
|
ipl2tp_api_session_next(Ipl2tp_key *tkey,
|
|
Ipl2tp_key *last,
|
|
Ipl2tp_key *next)
|
|
{
|
|
Ipl2tp_session *sbest = IP_NULL;
|
|
Ipl2tp_session *s;
|
|
Ipl2tp_tunnel *tunnel;
|
|
Ipl2tp_status status = IPL2TP_STATUS_ERROR;
|
|
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
/* Find the tunnel */
|
|
if ((tunnel = ipl2tp_state_tunnel_get(tkey)) == IP_NULL)
|
|
{
|
|
status = IPL2TP_STATUS_BADID;
|
|
goto leave;
|
|
}
|
|
|
|
/* Find next good session */
|
|
for (s = IPCOM_LIST_FIRST(&tunnel->session_list);
|
|
s != IP_NULL;
|
|
s = IPCOM_LIST_NEXT(&s->head))
|
|
{
|
|
if ((last == IP_NULL || s->local.key.ident > last->ident) &&
|
|
(sbest == IP_NULL || s->local.key.ident < sbest->local.key.ident))
|
|
{
|
|
/* Save the best candidate so far */
|
|
sbest = s;
|
|
}
|
|
}
|
|
|
|
/* Found one? */
|
|
if (sbest)
|
|
{
|
|
next->ident = sbest->local.key.ident;
|
|
next->version = sbest->local.key.version;
|
|
status = IPL2TP_STATUS_OK;
|
|
goto leave;
|
|
}
|
|
|
|
leave:
|
|
IPL2TP_AVAILABLE();
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_session_attribute_query
|
|
*===========================================================================
|
|
* Description: Get a singular session parameter
|
|
* Parameters: key - The session key.
|
|
* query - The query
|
|
* replies - Where the replies are to be stored.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC void
|
|
ipl2tp_api_session_attribute_query(Ipl2tp_key *key,
|
|
int query,
|
|
Ipl2tp_attrobj *replies)
|
|
{
|
|
Ipl2tp_attrobj attr = IP_NULL;
|
|
|
|
/* Retrieve the type */
|
|
ipl2tp_attr_add_query(&attr,
|
|
query);
|
|
(void)ipl2tp_api_session_attribute_get(key, attr, replies);
|
|
ipl2tp_attr_delete(&attr);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_session_type
|
|
*===========================================================================
|
|
* Description: Human readable description of type of session
|
|
* Parameters: key - The session key
|
|
* Returns: The human readable description.
|
|
*
|
|
*/
|
|
IP_PUBLIC const char *
|
|
ipl2tp_api_session_type(Ipl2tp_key *key)
|
|
{
|
|
Ipl2tp_attr a;
|
|
Ipl2tp_attrobj replies = IP_NULL;
|
|
const char *type = "<unknown>";
|
|
|
|
/* */
|
|
ipl2tp_api_session_attribute_query(key,
|
|
IPL2TP_SATTR_RO_l2tpSessionStatsCallType,
|
|
&replies);
|
|
|
|
if((a = ipl2tp_attr_first(replies)) == IP_NULL)
|
|
{
|
|
ipl2tp_attr_delete(&replies);
|
|
return type;
|
|
}
|
|
|
|
/* Get the first */
|
|
switch (ipl2tp_attr_idata(a))
|
|
{
|
|
case IPL2TP_MIB_LAC_INCOMING:
|
|
type = "locally requested(LAC) incoming";
|
|
break;
|
|
case IPL2TP_MIB_LNS_INCOMING:
|
|
type = "remotely requested(LAC) incoming";
|
|
break;
|
|
case IPL2TP_MIB_LAC_OUTGOING:
|
|
type = "remotely requested(LNS) outgoing";
|
|
break;
|
|
case IPL2TP_MIB_LNS_OUTGOING:
|
|
type = "locally requested(LNS) outgoing";
|
|
break;
|
|
}
|
|
|
|
/* Delete the variables */
|
|
ipl2tp_attr_delete(&replies);
|
|
|
|
return type;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_session_ppp_input
|
|
*===========================================================================
|
|
* Description: Feed an incoming PPP packet to the IPL2TP engine.
|
|
* Parameters: session_id The session which the packet belongs to.
|
|
* buffer - PPP packet.
|
|
* length - Length of PPP packet.
|
|
* offset - Number of bytes before 'buffer' that may be used.
|
|
* align - Alignment requirement for output buffer.
|
|
* is_ip - Is this an IP packet?
|
|
* Returns: IPL2TP_STATUS_OK if success.
|
|
* IPL2TP_STATUS_BADID if invalid session ID.
|
|
*/
|
|
IP_PUBLIC Ipl2tp_status
|
|
ipl2tp_api_session_ppp_input(Ipl2tp_key *key,
|
|
void *buffer,
|
|
int length,
|
|
int offset,
|
|
int align,
|
|
Ip_bool is_ip)
|
|
{
|
|
Ipl2tp_status status;
|
|
Ipl2tp_session *session;
|
|
|
|
IPL2TP_UNUSED(is_ip);
|
|
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
if (ipl2tp.state != IPL2TP_STATE_OPEN)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: IPL2TP is not opened",
|
|
ipl2tp_versions[key->version]);
|
|
status = IPL2TP_STATUS_STATE;
|
|
goto leave;
|
|
}
|
|
|
|
/* Get session descriptor */
|
|
if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL ||
|
|
session->state != IPL2TP_SSTATE_ESTABLISHED)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"%s: Called ipl2tp_ppp_input() with invalid session ID: %d",
|
|
ipl2tp_versions[key->version],
|
|
(int)key->ident);
|
|
status = IPL2TP_STATUS_BADID;
|
|
goto leave;
|
|
}
|
|
|
|
IPCOM_LOG4(DEBUG,
|
|
"%s(%d,%d,%s): Receiving PPP packet",
|
|
ipl2tp_versions[key->version],
|
|
(int)session->tunnel->local.key.ident,
|
|
(int)key->ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
|
|
|
|
/* */
|
|
if (session->attr.pw_type != IPL2TP_ATTR_PW_TYPE_PPP)
|
|
{
|
|
IPCOM_LOG4(DEBUG,
|
|
"%s(%d,%d,%s): Session does not have the PPP pseudowire type",
|
|
ipl2tp_versions[key->version],
|
|
(int)session->tunnel->local.key.ident,
|
|
(int)key->ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
|
|
status = IPL2TP_STATUS_BADPW;
|
|
goto leave;
|
|
}
|
|
|
|
/* */
|
|
if (session->local.key.version == IPL2TP_VERSION_L2TPV2)
|
|
status = ipl2tp_v2_pw_ppp_input(session,buffer,length,offset,align);
|
|
else
|
|
{
|
|
IPCOM_LOG4(DEBUG,
|
|
"%s(%d,%d,%s): Version does not support the PPP pseudowire type",
|
|
ipl2tp_versions[key->version],
|
|
(int)session->tunnel->local.key.ident,
|
|
(int)key->ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
|
|
status = IPL2TP_STATUS_BADPW;
|
|
}
|
|
|
|
leave:
|
|
IPL2TP_AVAILABLE();
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_ethernet_input
|
|
*===========================================================================
|
|
* Description: Feed an incoming Ethernet packet to the IPL2TP engine.
|
|
* Parameters: key - The session which the packet belongs to.
|
|
* buffer - The ethernet frame
|
|
* length - Length of ethernet frame.
|
|
* offset - Number of bytes before 'buffer' that may be used.
|
|
* align - Alignment requirement for output buffer.
|
|
* is_ip - Is this an IP packet?
|
|
* Returns: IPL2TP_STATUS_OK if success.
|
|
* IPL2TP_STATUS_BADID if invalid session ID.
|
|
*/
|
|
IP_PUBLIC Ipl2tp_status
|
|
ipl2tp_api_session_ethernet_input(Ipl2tp_key *key,
|
|
void *buffer,
|
|
int length,
|
|
int offset,
|
|
int align,
|
|
Ip_bool is_ip)
|
|
{
|
|
Ipl2tp_status status;
|
|
Ipl2tp_session *session;
|
|
|
|
IPL2TP_UNUSED(is_ip);
|
|
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
if (ipl2tp.state != IPL2TP_STATE_OPEN)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: IPL2TP is not opened",
|
|
ipl2tp_versions[key->version]);
|
|
status = IPL2TP_STATUS_STATE;
|
|
goto leave;
|
|
}
|
|
|
|
/* Get session descriptor */
|
|
if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL ||
|
|
session->state != IPL2TP_SSTATE_ESTABLISHED)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"%s: Called ipl2tp_api_session_ethernet_input() with invalid session ID: %d",
|
|
ipl2tp_versions[key->version],
|
|
(int)key->ident);
|
|
status = IPL2TP_STATUS_BADID;
|
|
goto leave;
|
|
}
|
|
|
|
IPCOM_LOG4(DEBUG,
|
|
"%s(%d,%d,%s): Receiving Ethernet frame",
|
|
ipl2tp_versions[key->version],
|
|
(int)session->tunnel->local.key.ident,
|
|
(int)key->ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
|
|
|
|
/* */
|
|
if (session->attr.pw_type != IPL2TP_ATTR_PW_TYPE_ETHERNET &&
|
|
session->attr.pw_type != IPL2TP_ATTR_PW_TYPE_ETHERNET_VLAN)
|
|
{
|
|
IPCOM_LOG4(DEBUG,
|
|
"%s(%d,%d,%s): Session does not have the Ethernet or VLAN pseudowire type",
|
|
ipl2tp_versions[key->version],
|
|
(int)session->tunnel->local.key.ident,
|
|
(int)key->ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
|
|
status = IPL2TP_STATUS_BADPW;
|
|
goto leave;
|
|
}
|
|
|
|
/* */
|
|
if (session->local.key.version == IPL2TP_VERSION_L2TPV3)
|
|
{
|
|
if (session->attr.circuit_status != IPL2TP_MIB_UP ||
|
|
session->v.v3.circuit_status != IPL2TP_MIB_UP)
|
|
{
|
|
IPCOM_LOG4(INFO,
|
|
"%s(%d,%d,%s): Session circuit is not currently up, frame discarded",
|
|
ipl2tp_versions[key->version],
|
|
(int)session->tunnel->local.key.ident,
|
|
(int)key->ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
|
|
status = IPL2TP_STATUS_CIRCUIT_DOWN;
|
|
goto leave;
|
|
}
|
|
status = ipl2tp_v3_pw_ethernet_input(session,buffer,length,offset,align,is_ip);
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG4(DEBUG,
|
|
"%s(%d,%d,%s): Version does not support the Ethernet or VLAN pseudowire type",
|
|
ipl2tp_versions[key->version],
|
|
(int)session->tunnel->local.key.ident,
|
|
(int)key->ident,
|
|
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
|
|
status = IPL2TP_STATUS_BADPW;
|
|
}
|
|
|
|
leave:
|
|
IPL2TP_AVAILABLE();
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_session_outgoing_established
|
|
*===========================================================================
|
|
* Description: Inform IPL2TP about the establishment status of an outgoing
|
|
* session.
|
|
* Parameters: session_id - Session ID.
|
|
* version - Version.
|
|
* result_code - Result code as defined in RFC2661.
|
|
* error_code - Error code as defined in RFC2661.
|
|
* error_message - Error message for vendor-specific errors (code 6).
|
|
* Returns: IPL2TP_STATUS_STATE if IPL2TP is not open.
|
|
* IPL2TP_STATUS_BADID if bad session ID.
|
|
*/
|
|
IP_PUBLIC Ipl2tp_status
|
|
ipl2tp_api_session_outgoing_established(Ipl2tp_key *key,
|
|
Ip_u16 result_code,
|
|
Ip_u16 error_code,
|
|
CONST char *error_message)
|
|
{
|
|
Ipl2tp_session *session;
|
|
Ipl2tp_status status = IPL2TP_STATUS_OK;
|
|
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
if (ipl2tp.state != IPL2TP_STATE_OPEN)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: IPL2TP is not opened",
|
|
ipl2tp_versions[0]);
|
|
status = IPL2TP_STATUS_STATE;
|
|
}
|
|
else if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"%s: Called ipl2tp_api_session_outgoing_established() with invalid session ID: %d",
|
|
ipl2tp_versions[key->version],
|
|
(int)key->ident);
|
|
status = IPL2TP_STATUS_BADID;
|
|
}
|
|
else do
|
|
{
|
|
Ipl2tp_tunnel *tunnel = session->tunnel;
|
|
|
|
/* Increment session count here since a teardown will decrement */
|
|
tunnel->statistics.active_sessions++;
|
|
|
|
if (session->state != IPL2TP_SSTATE_WAIT_CS_ANSWER)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_STATE,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
IPL2TP_ERR_VENDOR_ERROR_LAC,
|
|
"Session established attempted for session in non SSTATE_WAIT_CS_ANSWER state");
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%s): Called ipl2tp_api_session_outgoing_established() for session in %s state",
|
|
ipl2tp_versions[key->version],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_state_sstate_name(session->state));
|
|
status = IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
else if (result_code != 0)
|
|
{
|
|
/* Failed attempt, set result codes */
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_CLOSE,
|
|
result_code,
|
|
error_code,
|
|
error_message);
|
|
}
|
|
else
|
|
{
|
|
int cb;
|
|
|
|
/* Ready to fly */
|
|
ipl2tp_message_occn(session);
|
|
ipl2tp_state_establish_session_timeout_init(session, 0);
|
|
session->state = IPL2TP_SSTATE_ESTABLISHED;
|
|
|
|
tunnel->statistics.total_sessions++;
|
|
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_OK,
|
|
IPL2TP_OUTGOING_ESTABLISHED,
|
|
0,
|
|
"Outgoing session established");
|
|
|
|
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_STATE,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
IPL2TP_ERR_VENDOR_ERROR_LAC,
|
|
"Session creation aborted");
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%d,%s): Session creation aborted",
|
|
ipl2tp_versions[key->version],
|
|
(int)tunnel->local.key.ident,
|
|
(int)session->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG5(INFO,
|
|
"%s(%d,%d,%s): Outgoing session established, remote id is %d",
|
|
ipl2tp_versions[key->version],
|
|
(int)tunnel->local.key.ident,
|
|
(int)session->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
(int)session->remote.key.ident);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ipl2tp_message_cdn(session);
|
|
ipl2tp_state_session_teardown(session);
|
|
} while (0);
|
|
|
|
IPL2TP_AVAILABLE();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_api_session_incoming_established
|
|
*===========================================================================
|
|
* Description: Inform IPL2TP about the establishment status of an incoming
|
|
* session.
|
|
* Parameters: session_id - Session ID.
|
|
* version - Version.
|
|
* result_code - Result code as defined in RFC2661.
|
|
* error_code - Error code as defined in RFC2661.
|
|
* error_message - Error message for vendor-specific errors (code 6).
|
|
* Returns: IPL2TP_STATUS_STATE if IPL2TP is not open.
|
|
* IPL2TP_STATUS_BADID if bad session ID.
|
|
*/
|
|
IP_PUBLIC Ipl2tp_status
|
|
ipl2tp_api_session_incoming_established(Ipl2tp_key *key,
|
|
Ip_u16 result_code,
|
|
Ip_u16 error_code,
|
|
CONST char *error_message)
|
|
{
|
|
Ipl2tp_session *session;
|
|
Ipl2tp_status status = IPL2TP_STATUS_OK;
|
|
|
|
IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED);
|
|
|
|
if (ipl2tp.state != IPL2TP_STATE_OPEN)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: IPL2TP is not opened",
|
|
ipl2tp_versions[0]);
|
|
status = IPL2TP_STATUS_STATE;
|
|
}
|
|
else if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"%s: Called ipl2tp_api_session_incoming_established() with invalid session ID: %d",
|
|
ipl2tp_versions[key->version],
|
|
(int)key->ident);
|
|
status = IPL2TP_STATUS_BADID;
|
|
}
|
|
else do
|
|
{
|
|
Ipl2tp_tunnel *tunnel = session->tunnel;
|
|
|
|
if (session->state != IPL2TP_SSTATE_WAIT_CS_ANSWER)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_STATE,
|
|
IPL2TP_RES_CDN_GENERAL_ERROR,
|
|
IPL2TP_ERR_VENDOR_ERROR_LAC,
|
|
"Session established attempted for session in non SSTATE_WAIT_CS_ANSWER state");
|
|
IPCOM_LOG4(WARNING,
|
|
"%s(%d,%s): Called ipl2tp_api_session_incoming_established() for session in %s state",
|
|
ipl2tp_versions[key->version],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
ipl2tp_state_sstate_name(session->state));
|
|
status = IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
else if (result_code != 0)
|
|
{
|
|
/* Failed attempt, set result codes */
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_CLOSE,
|
|
result_code,
|
|
error_code,
|
|
error_message);
|
|
}
|
|
else
|
|
{
|
|
/* Ready to fly */
|
|
session->state = IPL2TP_SSTATE_WAIT_CONNECT;
|
|
ipl2tp_state_establish_session_timeout_init(session, 1);
|
|
ipl2tp_message_icrp(session);
|
|
break;
|
|
}
|
|
|
|
ipl2tp_message_cdn(session);
|
|
ipl2tp_state_session_teardown(session);
|
|
} while (0);
|
|
|
|
IPL2TP_AVAILABLE();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|