984 lines
30 KiB
C
984 lines
30 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipl2tp_data.c,v $ $Revision: 1.7.14.1 $
|
|
* $Source: /home/interpeak/CVSRoot/ipl2tp/src/ipl2tp_data.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_avp.h"
|
|
#include "ipl2tp_data.h"
|
|
#include "ipl2tp_state.h"
|
|
#include "ipl2tp_attr.h"
|
|
#include "ipl2tp_attr_h.h"
|
|
#include "ipl2tp_message.h"
|
|
|
|
#include "ipl2tp_v2.h"
|
|
#include "ipl2tp_v3.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_PUBLIC Ipl2tp_context ipl2tp;
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_key_hash
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipl2tp_data_key_hash(Ipl2tp_key *key)
|
|
{
|
|
/* Hash the session ID */
|
|
return ipcom_hash_update(key,
|
|
sizeof(*key),
|
|
0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_obj_hash_session
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipl2tp_data_obj_hash_session(Ipl2tp_session *session)
|
|
{
|
|
/* Hash the version & session ID */
|
|
return ipcom_hash_update(&session->local.key,
|
|
sizeof(session->local.key),
|
|
0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_cmp_session
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipl2tp_data_cmp_session(Ipl2tp_session *session,
|
|
Ipl2tp_key *key)
|
|
{
|
|
/* Version & ID must match */
|
|
if (session->local.key.version == key->version &&
|
|
session->local.key.ident == key->ident)
|
|
return IP_TRUE;
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_obj_hash_tunnel
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipl2tp_data_obj_hash_tunnel(Ipl2tp_tunnel *tunnel)
|
|
{
|
|
/* Hash the tunnel ID */
|
|
return ipcom_hash_update(&tunnel->local.key,
|
|
sizeof(tunnel->local.key),
|
|
0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_cmp_tunnel
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipl2tp_data_cmp_tunnel(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_key *key)
|
|
{
|
|
/* Version & ID must match */
|
|
if (tunnel->local.key.version == key->version &&
|
|
tunnel->local.key.ident == key->ident)
|
|
return IP_TRUE;
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_obj_hash_addr
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipl2tp_data_obj_hash_addr(Ipl2tp_tunnel *tunnel)
|
|
{
|
|
/* Hash the version first */
|
|
unsigned val = ipcom_hash_update(&tunnel->local.key.version,
|
|
sizeof(tunnel->local.key.version),
|
|
0);
|
|
|
|
/* Hash the tunnel ID */
|
|
return ipcom_hash_update(&tunnel->remote.addr,
|
|
tunnel->remote.addr.sa.sa_len,
|
|
val);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_key_hash_addr
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipl2tp_data_key_hash_addr(Ipl2tp_addr *key)
|
|
{
|
|
/* Hash the version first */
|
|
unsigned val = ipcom_hash_update(&key->key.version,
|
|
sizeof(key->key.version),
|
|
0);
|
|
|
|
/* Hash the address */
|
|
return ipcom_hash_update(key->addr,
|
|
key->addr->sa.sa_len,
|
|
val);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_cmp_addr
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipl2tp_data_cmp_addr(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_addr *key)
|
|
{
|
|
/* Version & addr must match; Tunnel must not be teardown. */
|
|
if (tunnel->local.key.version == key->key.version &&
|
|
IPL2TP_SOCKADDR_EQUAL(&tunnel->remote.addr.sa, &key->addr->sa) &&
|
|
tunnel->state > IPL2TP_TSTATE_TEARDOWN)
|
|
return IP_TRUE;
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_obj_hash_tunnel_assigned
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipl2tp_data_obj_hash_tunnel_assigned(Ipl2tp_tunnel *tunnel)
|
|
{
|
|
/* Hash the addr & version first */
|
|
unsigned val = ipl2tp_data_obj_hash_addr(tunnel);
|
|
|
|
/* Hash the tunnel ID */
|
|
return ipcom_hash_update(&tunnel->remote.key.ident,
|
|
sizeof(tunnel->remote.key.ident),
|
|
val);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_key_hash_tunnel_assigned
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipl2tp_data_key_hash_tunnel_assigned(Ipl2tp_addr *key)
|
|
{
|
|
/* Hash the addr & version first */
|
|
unsigned val = ipl2tp_data_key_hash_addr(key);
|
|
|
|
/* Hash the session ID */
|
|
return ipcom_hash_update(&key->key.ident,
|
|
sizeof(key->key.ident),
|
|
val);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_cmp_tunnel_assigned
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipl2tp_data_cmp_tunnel_assigned(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_addr *key)
|
|
{
|
|
/* Addr, Version & ID must match */
|
|
if (ipl2tp_data_cmp_addr(tunnel, key) &&
|
|
tunnel->remote.key.ident == key->key.ident)
|
|
return IP_TRUE;
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_obj_hash_tunnel_ifindex
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipl2tp_data_obj_hash_tunnel_ifindex(Ipl2tp_tunnel *tunnel)
|
|
{
|
|
/* Hash the tunnel ifindex ID */
|
|
return ipcom_hash_update(&tunnel->attr.ifindex,
|
|
sizeof(tunnel->attr.ifindex),
|
|
0);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_key_hash_tunnel_assigned
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipl2tp_data_key_hash_tunnel_ifindex(Ip_u32 *ifindex)
|
|
{
|
|
/* Hash the tunnel ifindex ID */
|
|
return ipcom_hash_update(ifindex,
|
|
sizeof(*ifindex),
|
|
0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_tunnel_close
|
|
*===========================================================================
|
|
* Description: Close down a tunnel.
|
|
* Parameters: tunnel - The tunnel.
|
|
* data - Opaque data (UNUSED)
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipl2tp_data_tunnel_close(Ipl2tp_tunnel *tunnel,
|
|
void *data)
|
|
{
|
|
IPL2TP_UNUSED(data);
|
|
|
|
/* Do teardown */
|
|
ipl2tp_state_tunnel_teardown(tunnel);
|
|
ipl2tp_tunnel_delete(tunnel);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_cmp_tunnel_assigned
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipl2tp_data_cmp_tunnel_ifindex(Ipl2tp_tunnel *tunnel,
|
|
Ip_u32 *ifindex)
|
|
{
|
|
/* The same? */
|
|
return tunnel->attr.ifindex == *ifindex;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_init
|
|
*===========================================================================
|
|
* Description: Init the global data object
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_status
|
|
ipl2tp_data_init(void)
|
|
{
|
|
int i;
|
|
|
|
ipcom_memset(&ipl2tp, 0, sizeof(ipl2tp));
|
|
|
|
#ifdef IPL2TP_USE_MUTEX
|
|
/* Create synchronization mutex */
|
|
(void)ipcom_mutex_create(&ipl2tp.mutex);
|
|
#endif
|
|
|
|
/* Init other lists */
|
|
ipcom_list_init(&ipl2tp.tunnel.v2.tunnels);
|
|
ipcom_list_init(&ipl2tp.tunnel.v3.tunnels);
|
|
ipcom_list_init(&ipl2tp.tunnel.free_list);
|
|
ipcom_list_init(&ipl2tp.session.free_list);
|
|
|
|
/* The basic id tunnel hash */
|
|
ipl2tp.tunnel.hash_id = ipcom_hash_new((Ipcom_hash_obj_func)ipl2tp_data_obj_hash_tunnel,
|
|
(Ipcom_hash_key_func)ipl2tp_data_key_hash,
|
|
(Ipcom_hash_cmp_func)ipl2tp_data_cmp_tunnel);
|
|
|
|
/* The basic remote id tunnel hash */
|
|
ipl2tp.tunnel.hash_remote_id = ipcom_hash_new((Ipcom_hash_obj_func)ipl2tp_data_obj_hash_tunnel_assigned,
|
|
(Ipcom_hash_key_func)ipl2tp_data_key_hash_tunnel_assigned,
|
|
(Ipcom_hash_cmp_func)ipl2tp_data_cmp_tunnel_assigned);
|
|
|
|
/* The basic remote id tunnel hash */
|
|
ipl2tp.tunnel.hash_ifindex = ipcom_hash_new((Ipcom_hash_obj_func)ipl2tp_data_obj_hash_tunnel_ifindex,
|
|
(Ipcom_hash_key_func)ipl2tp_data_key_hash_tunnel_ifindex,
|
|
(Ipcom_hash_cmp_func)ipl2tp_data_cmp_tunnel_ifindex);
|
|
|
|
/* The address tunnel hash */
|
|
ipl2tp.tunnel.hash_remote_addr = ipcom_hash_new((Ipcom_hash_obj_func)ipl2tp_data_obj_hash_addr,
|
|
(Ipcom_hash_key_func)ipl2tp_data_key_hash_addr,
|
|
(Ipcom_hash_cmp_func)ipl2tp_data_cmp_addr);
|
|
|
|
/* The session hash */
|
|
ipl2tp.session.hash_id = ipcom_hash_new((Ipcom_hash_obj_func)ipl2tp_data_obj_hash_session,
|
|
(Ipcom_hash_key_func)ipl2tp_data_key_hash,
|
|
(Ipcom_hash_cmp_func)ipl2tp_data_cmp_session);
|
|
|
|
/* Did they succeed? */
|
|
if (ipl2tp.tunnel.hash_id == IP_NULL || ipl2tp.tunnel.hash_remote_addr == IP_NULL ||
|
|
ipl2tp.tunnel.hash_remote_addr == IP_NULL || ipl2tp.tunnel.hash_ifindex == IP_NULL ||
|
|
ipl2tp.session.hash_id == IP_NULL)
|
|
{
|
|
ipl2tp_data_exit();
|
|
return IPL2TP_STATUS_NOMEM;
|
|
}
|
|
|
|
/* Tunnel and session IDs start at 1 */
|
|
ipl2tp.tunnel.v2.ident = 1;
|
|
ipl2tp.tunnel.v3.ident = 1;
|
|
ipl2tp.session.v2.ident = 1;
|
|
ipl2tp.session.v3.ident = 1;
|
|
|
|
for (i = 1; i <= IPL2TP_PREALLOCATED_TUNNEL_NO; i++)
|
|
{
|
|
Ipl2tp_tunnel *tunnel;
|
|
if ((tunnel = ipl2tp_tunnel_malloc()) == IP_NULL)
|
|
{
|
|
ipl2tp_data_exit();
|
|
return IPL2TP_STATUS_NOMEM;
|
|
}
|
|
|
|
ipcom_list_insert_first(&ipl2tp.tunnel.free_list,
|
|
&tunnel->head);
|
|
}
|
|
|
|
for (i = 1; i <= IPL2TP_PREALLOCATED_SESSION_NO; i++)
|
|
{
|
|
Ipl2tp_session *session;
|
|
if ((session = ipl2tp_session_malloc()) == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: Out of memory for session descriptors",
|
|
ipl2tp_versions[0]);
|
|
ipl2tp_data_exit();
|
|
return IPL2TP_STATUS_NOMEM;
|
|
}
|
|
|
|
ipcom_list_insert_first(&ipl2tp.session.free_list,
|
|
&session->head);
|
|
}
|
|
|
|
|
|
/* Serial number starts at 1 */
|
|
ipl2tp.call_serial_number = 1;
|
|
|
|
/* Set default attributes */
|
|
ipcom_strncpy(ipl2tp.host_name, IPL2TP_HOST_NAME, IPL2TP_MAX_HOST_NAME_SIZE);
|
|
ipl2tp.first_retransmit_sec = IPL2TP_FIRST_RETRANSMIT_SEC;
|
|
ipl2tp.tunnel_zombie_sec = IPL2TP_TUNNEL_ZOMBIE_SEC;
|
|
ipl2tp.hello_tick_sec = IPL2TP_HELLO_TICK_SEC;
|
|
ipl2tp.establish_timeout_sec = IPL2TP_ESTABLISH_TIMEOUT_SEC;
|
|
ipl2tp.open_exclusive = IPL2TP_OPEN_EXCLUSIVE;
|
|
ipl2tp.admin_state = IPL2TP_MIB_ENABLED;
|
|
ipl2tp.drain_tunnels = IPL2TP_MIB_NO;
|
|
ipl2tp.enable_outgoing = IPL2TP_MIB_DISABLED;
|
|
|
|
ipl2tp.enable_v3 = IPL2TP_MIB_DISABLED;
|
|
ipl2tp.enable_v2 = IPL2TP_MIB_DISABLED;
|
|
ipl2tp.close_unused_tunnels = IPL2TP_MIB_YES;
|
|
|
|
/* Set default tunnel attributes */
|
|
ipl2tp.tunnel.v2.attr.hello_interval_sec = IPL2TP_HELLO_INTERVAL_SEC;
|
|
ipl2tp.tunnel.v2.attr.max_retransmit = IPL2TP_MAX_RETRANSMIT;
|
|
ipl2tp.tunnel.v2.attr.max_backoff_sec = IPL2TP_MAX_BACKOFF_SEC;
|
|
ipl2tp.tunnel.v2.attr.receive_window_size = IPL2TP_RECEIVE_WINDOW_SIZE;
|
|
ipl2tp.tunnel.v2.attr.framing_capabilities = IPL2TP_MIB_FRAMING_NONE;
|
|
ipl2tp.tunnel.v2.attr.authentication = IPL2TP_MIB_AUTH_NONE;
|
|
ipl2tp.tunnel.v2.attr.sequencing = IPL2TP_MIB_NEVER;
|
|
ipl2tp.tunnel.v2.attr.hide_avp = IPL2TP_MIB_NO;
|
|
|
|
ipl2tp.tunnel.v3.attr.hello_interval_sec = IPL2TP_HELLO_INTERVAL_SEC;
|
|
ipl2tp.tunnel.v3.attr.max_retransmit = IPL2TP_MAX_RETRANSMIT;
|
|
ipl2tp.tunnel.v3.attr.max_backoff_sec = IPL2TP_MAX_BACKOFF_SEC;
|
|
ipl2tp.tunnel.v3.attr.receive_window_size = IPL2TP_RECEIVE_WINDOW_SIZE;
|
|
ipl2tp.tunnel.v3.attr.framing_capabilities = IPL2TP_MIB_FRAMING_NONE;
|
|
ipl2tp.tunnel.v3.attr.authentication = IPL2TP_MIB_AUTH_NONE;
|
|
ipl2tp.tunnel.v3.attr.sequencing = IPL2TP_MIB_NEVER;
|
|
ipl2tp.tunnel.v3.attr.hide_avp = IPL2TP_MIB_NO;
|
|
|
|
/* Set default session attributes */
|
|
ipl2tp.session.v2.attr.framing_type = IPL2TP_MIB_FRAMING_NONE;
|
|
|
|
ipl2tp.session.v3.attr.circuit_status = IPL2TP_MIB_DOWN;
|
|
ipl2tp.session.v3.attr.l2_out_of_order_reset = IPL2TP_L2_OUT_OF_ORDER_RESET;
|
|
|
|
/* Mark as initialized */
|
|
ipl2tp.magic = IPL2TP_MAGIC;
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_data_exit
|
|
*===========================================================================
|
|
* Description: Free any resources allocated by ipl2tp_data_init.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_data_exit(void)
|
|
{
|
|
Ipl2tp_tunnel *tunnel;
|
|
Ipl2tp_session *session;
|
|
|
|
#ifdef IPL2TP_USE_MUTEX
|
|
ipcom_mutex_delete(&ipl2tp.mutex);
|
|
#endif
|
|
|
|
/* Close down the tunnels & sessions */
|
|
ipcom_hash_for_each(ipl2tp.tunnel.hash_id,
|
|
(Ipcom_hash_foreach_cb_func)ipl2tp_data_tunnel_close,
|
|
IP_NULL);
|
|
|
|
/* Grab the first session */
|
|
while ((session = IPCOM_LIST_FIRST(&ipl2tp.session.free_list)) != IP_NULL)
|
|
{
|
|
/* Remove it from the queue */
|
|
ipcom_list_remove(&session->head);
|
|
ipcom_free(session);
|
|
}
|
|
|
|
/* Grab the first session */
|
|
while ((tunnel = IPCOM_LIST_FIRST(&ipl2tp.tunnel.free_list)) != IP_NULL)
|
|
{
|
|
/* Remove it from the queue */
|
|
ipcom_list_remove(&tunnel->head);
|
|
ipcom_free(tunnel);
|
|
}
|
|
|
|
/* Delete the hashes */
|
|
if (ipl2tp.tunnel.hash_remote_addr)
|
|
ipcom_hash_delete(ipl2tp.tunnel.hash_remote_addr);
|
|
if (ipl2tp.tunnel.hash_remote_id)
|
|
ipcom_hash_delete(ipl2tp.tunnel.hash_remote_id);
|
|
if (ipl2tp.tunnel.hash_id)
|
|
ipcom_hash_delete(ipl2tp.tunnel.hash_id);
|
|
if (ipl2tp.tunnel.hash_ifindex)
|
|
ipcom_hash_delete(ipl2tp.tunnel.hash_ifindex);
|
|
if (ipl2tp.session.hash_id)
|
|
ipcom_hash_delete(ipl2tp.session.hash_id);
|
|
|
|
ipcom_memset(&ipl2tp, 0, sizeof(ipl2tp));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_tunnel_new
|
|
*===========================================================================
|
|
* Description: Retrieve a tunnel descriptor.
|
|
* Parameters: version - Version of the tunnel.
|
|
* addr - The address of the peer.
|
|
* Returns: A new tunnel.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_tunnel *
|
|
ipl2tp_tunnel_new(Ipl2tp_version version,
|
|
union Ip_sockaddr_union *addr)
|
|
{
|
|
Ipl2tp_tunnel *t;
|
|
|
|
/* Try to recycle an old descriptor */
|
|
if ((t = IPCOM_LIST_FIRST(&ipl2tp.tunnel.free_list)) != IP_NULL)
|
|
{
|
|
ipcom_list_remove(&t->head);
|
|
}
|
|
else
|
|
{
|
|
t = ipl2tp_tunnel_malloc();
|
|
}
|
|
|
|
/* Initialize */
|
|
if (t != IP_NULL)
|
|
{
|
|
/*lint -e419*/
|
|
ipcom_memset(t, 0, sizeof(*t));
|
|
ipcom_list_init(&t->session_list);
|
|
ipcom_list_init(&t->message_list);
|
|
IPCOM_TMO_INIT(&t->timer);
|
|
|
|
t->state = IPL2TP_TSTATE_IDLE;
|
|
t->cwnd = 1;
|
|
t->drain_tunnel = IPL2TP_MIB_NO;
|
|
|
|
ipl2tp.open_tunnels++;
|
|
|
|
/* Copy the address */
|
|
ipcom_memset(&t->remote.addr, 0, sizeof(t->remote.addr));
|
|
ipcom_memcpy(&t->remote.addr, addr, addr->sa.sa_len);
|
|
|
|
t->common.receive_window_size = IPL2TP_RECEIVE_WINDOW_SIZE;
|
|
t->ssthresh = t->common.receive_window_size;
|
|
|
|
/* Create logheader and setup callback table*/
|
|
switch (version)
|
|
{
|
|
case IPL2TP_VERSION_L2TPV2:
|
|
ipl2tp_v2_tunnel_init(t);
|
|
break;
|
|
case IPL2TP_VERSION_L2TPV3:
|
|
ipl2tp_v3_tunnel_init(t);
|
|
break;
|
|
}
|
|
|
|
/* Add it to the ID and ADDR table */
|
|
if ((ipcom_hash_add(ipl2tp.tunnel.hash_id, t) != IPCOM_SUCCESS) ||
|
|
(ipcom_hash_add(ipl2tp.tunnel.hash_remote_addr, t) != IPCOM_SUCCESS))
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: Unable to add a new tunnel",
|
|
ipl2tp_versions[0]);
|
|
ipcom_free (t);
|
|
return IP_NULL;
|
|
}
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_session_new
|
|
*===========================================================================
|
|
* Description: Retrieve a session descriptor
|
|
* Parameters: tunnel - The tunnel this session belongs to.
|
|
* cookie - Cookie for identification of the session.
|
|
* cookie_size - Size of the cookie [max 8].
|
|
* Returns: The session
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_session *
|
|
ipl2tp_session_new(Ipl2tp_tunnel *tunnel,
|
|
void *cookie,
|
|
Ip_u8 cookie_size)
|
|
{
|
|
Ipl2tp_session *s;
|
|
|
|
/* Try to recycle an old descriptor */
|
|
if ((s = IPCOM_LIST_FIRST(&ipl2tp.session.free_list)) != IP_NULL)
|
|
{
|
|
ipcom_list_remove(&s->head);
|
|
}
|
|
else
|
|
{
|
|
s = ipl2tp_session_malloc();
|
|
}
|
|
|
|
/* Initialize */
|
|
if (s != IP_NULL)
|
|
{
|
|
ipcom_memset(s, 0, sizeof(*s));
|
|
IPCOM_TMO_INIT(&s->timer);
|
|
|
|
/* */
|
|
s->state = IPL2TP_SSTATE_IDLE;
|
|
s->common.call_serial_number = ipl2tp.call_serial_number++;
|
|
|
|
/* Grab next session ID based on version */
|
|
|
|
if (cookie_size)
|
|
{
|
|
ipl2tp_util_vector_create(&s->local.cookie,
|
|
cookie,
|
|
cookie_size);
|
|
}
|
|
|
|
s->tunnel = tunnel;
|
|
|
|
/* Initialize the tunnel */
|
|
IPL2TP_TUNNEL_SESSION_INIT(s);
|
|
|
|
/* Set the tunnel ownership */
|
|
ipcom_list_insert_last(&tunnel->session_list, &s->head);
|
|
if (ipcom_hash_add(ipl2tp.session.hash_id, s) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: Unable to add a new session",
|
|
ipl2tp_versions[0]);
|
|
ipcom_free(s);
|
|
return IP_NULL;
|
|
}
|
|
|
|
ipl2tp.open_sessions++;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_tunnel_malloc
|
|
*===========================================================================
|
|
* Description: Allocate a new tunnel descriptor.
|
|
* Parameters:
|
|
* Returns: The tunnel.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_tunnel *
|
|
ipl2tp_tunnel_malloc(void)
|
|
{
|
|
Ipl2tp_tunnel *t;
|
|
|
|
/* Limit the amount of tunnels */
|
|
if (ipl2tp.tunnel.total > IPL2TP_TUNNEL_MAX)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: Max no of tunnels created",
|
|
ipl2tp_versions[0]);
|
|
return IP_NULL;
|
|
}
|
|
|
|
/* Try to get new memory */
|
|
if ((t = ipcom_malloc(sizeof(*t))) == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: Out of memory for tunnel descriptor",
|
|
ipl2tp_versions[0]);
|
|
return IP_NULL;
|
|
}
|
|
|
|
/* Increase the number of tunnels */
|
|
ipl2tp.tunnel.total++;
|
|
|
|
/* Initialize state and ID */
|
|
t->state = IPL2TP_TSTATE_VOID;
|
|
|
|
return t;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_session_malloc
|
|
*===========================================================================
|
|
* Description: Allocate a new session descriptor.
|
|
* Parameters:
|
|
* Returns: The session.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_session *
|
|
ipl2tp_session_malloc(void)
|
|
{
|
|
Ipl2tp_session *s;
|
|
|
|
/* Limit the amount of sessions */
|
|
if (ipl2tp.session.total > IPL2TP_SESSION_MAX)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: Max no of sessions created",
|
|
ipl2tp_versions[0]);
|
|
return IP_NULL;
|
|
}
|
|
|
|
/* Try to get new memory */
|
|
if ((s = ipcom_malloc(sizeof(*s))) == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s: Out of memory for sesssion descriptor",
|
|
ipl2tp_versions[0]);
|
|
return IP_NULL;
|
|
}
|
|
|
|
/* One more session */
|
|
ipl2tp.session.total++;
|
|
|
|
/* Initialize state and ID */
|
|
s->state = IPL2TP_SSTATE_VOID;
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_tunnel_delete
|
|
*===========================================================================
|
|
* Description: Delete a tunnel
|
|
* Parameters: tunnel - The tunnel descriptor.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_tunnel_delete(Ipl2tp_tunnel *tunnel)
|
|
{
|
|
/* */
|
|
if (tunnel->slave != IP_NULL)
|
|
{
|
|
Ipl2tp_tunnel *slave = tunnel->slave;
|
|
/* Clear all pointers */
|
|
tunnel->slave = IP_NULL;
|
|
slave->slave = IP_NULL;
|
|
|
|
/* Tear the slave down */
|
|
ipl2tp_tunnel_delete(slave);
|
|
}
|
|
|
|
/* Cancel any outstanding timer */
|
|
ipcom_tmo_cancel(&tunnel->timer);
|
|
|
|
/* Remove it from the remote tunnel hash */
|
|
ipcom_hash_remove(ipl2tp.tunnel.hash_remote_id, tunnel);
|
|
/* Remove it from the tunnel hash */
|
|
ipcom_hash_remove(ipl2tp.tunnel.hash_id, tunnel);
|
|
/* Remove it from the remote address hash */
|
|
ipcom_hash_remove(ipl2tp.tunnel.hash_remote_addr, tunnel);
|
|
/* Remove it from the ifindex hash */
|
|
ipcom_hash_remove(ipl2tp.tunnel.hash_ifindex, tunnel);
|
|
|
|
/* Flush any outstanding messages */
|
|
ipl2tp_state_tunnel_flush(tunnel);
|
|
|
|
IPL2TP_SAFE_FREE(tunnel->sccrq.message);
|
|
ipl2tp_avp_delete(tunnel->sccrq.avp);
|
|
tunnel->sccrq.avp = IP_NULL;
|
|
tunnel->sccrq.message = IP_NULL;
|
|
|
|
ipl2tp_attr_tunnel_attribute_free(&tunnel->attr);
|
|
IPL2TP_SAFE_FREE(tunnel->last_result.error_message);
|
|
IPL2TP_SAFE_FREE(tunnel->last_error.error_message);
|
|
IPL2TP_SAFE_FREE(tunnel->expected_response.array);
|
|
|
|
IPL2TP_SAFE_FREE(tunnel->common.host_name);
|
|
IPL2TP_SAFE_FREE(tunnel->common.vendor_name);
|
|
IPL2TP_SAFE_FREE(tunnel->common.tie_breaker.array);
|
|
|
|
tunnel->state = IPL2TP_TSTATE_VOID;
|
|
|
|
IPL2TP_TUNNEL_DONE(tunnel);
|
|
|
|
ipcom_list_insert_last(&ipl2tp.tunnel.free_list, &tunnel->head);
|
|
if (--ipl2tp.open_tunnels == 0 && ipl2tp.drain_tunnels == IPL2TP_MIB_YES)
|
|
{
|
|
ipl2tp.admin_state = IPL2TP_MIB_DISABLED;
|
|
ipl2tp.drain_tunnels = IPL2TP_MIB_NO;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_session_delete
|
|
*===========================================================================
|
|
* Description: Delete a session
|
|
* Parameters: session - The session descriptor.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_session_delete(Ipl2tp_session *session)
|
|
{
|
|
ipl2tp_attr_session_attribute_free(&session->attr);
|
|
|
|
IPL2TP_SAFE_FREE(session->local.cookie.array);
|
|
|
|
/* Is it currently owned by a tunnel? */
|
|
if (session->tunnel != IP_NULL)
|
|
ipcom_list_remove(&session->head);
|
|
|
|
/* Remove from the hash */
|
|
ipcom_hash_remove(ipl2tp.session.hash_id, session);
|
|
|
|
/* All done */
|
|
IPL2TP_TUNNEL_SESSION_DONE(session);
|
|
|
|
/* */
|
|
session->state = IPL2TP_SSTATE_VOID;
|
|
ipcom_list_insert_last(&ipl2tp.session.free_list, &session->head);
|
|
|
|
ipl2tp.open_sessions--;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_disable
|
|
*===========================================================================
|
|
* Description: Disable IPL2TP temporarily. All tunnels and sessions
|
|
* are closed and deleted.
|
|
* Parameters:
|
|
* Returns: IPL2TP_STATUS_OK if success.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_status
|
|
ipl2tp_disable(void)
|
|
{
|
|
Ipl2tp_tunnel *tnext;
|
|
Ipl2tp_tunnel *t;
|
|
|
|
/* Loop for tunnels */
|
|
for (t = IPCOM_LIST_FIRST(&ipl2tp.tunnel.v2.tunnels);
|
|
t != IP_NULL;
|
|
t = tnext)
|
|
{
|
|
tnext = IPCOM_LIST_NEXT(&t->head);
|
|
IPL2TP_TUNNEL_RESULT_SET(t,
|
|
IPL2TP_STATUS_CLOSE,
|
|
IPL2TP_RES_StopCCN_GENERAL_REQUEST,
|
|
0,
|
|
"Tunnel closed");
|
|
ipl2tp_message_stopccn(t);
|
|
ipl2tp_state_tunnel_teardown(t);
|
|
}
|
|
|
|
/* Loop for tunnels */
|
|
for (t = IPCOM_LIST_FIRST(&ipl2tp.tunnel.v3.tunnels);
|
|
t != IP_NULL;
|
|
t = tnext)
|
|
{
|
|
tnext = IPCOM_LIST_NEXT(&t->head);
|
|
IPL2TP_TUNNEL_RESULT_SET(t,
|
|
IPL2TP_STATUS_CLOSE,
|
|
IPL2TP_RES_StopCCN_GENERAL_REQUEST,
|
|
0,
|
|
"Tunnel closed");
|
|
ipl2tp_message_stopccn(t);
|
|
ipl2tp_state_tunnel_teardown(t);
|
|
}
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|
|
|