Files
m241Neelima/components/ip_net2-6.9/ipl2tp/src/ipl2tp_api_session.c
T
2026-07-30 11:19:44 +05:30

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
****************************************************************************
*/