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

473 lines
17 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipl2tp_v3_pw.c,v $ $Revision: 1.6.12.1 $
* $Source: /home/interpeak/CVSRoot/ipl2tp/src/ipl2tp_v3_pw.c,v $
* $Author: jren $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include "ipl2tp_h.h"
#include "ipl2tp_api.h"
#include "ipl2tp_avp.h"
#include "ipl2tp_data.h"
#include "ipl2tp_message.h"
#include "ipl2tp_state.h"
#include "ipl2tp_pseudowire.h"
#include "ipl2tp_trpt.h"
#include "ipl2tp_v3.h"
#include "ipl2tp_v3_state.h"
#include "ipl2tp_v3_pw.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/* L2 sequence valid flag */
#define IPL2TP_V3_DS_L2_DEFAULT_SEQ_FLAG 0x40000000
#define IPL2TP_V3_DS_L2_DEFAULT_SEQ_MASK 0x00ffffff
#define IPL2TP_V3_DS_L2_DEFAULT_LTE 0x007fffff
#define IPL2TP_V3_PW_L2_SEQUENCE_MISS_OUT_OF_WINDOW 0
#define IPL2TP_V3_PW_L2_SEQUENCE_MISS_DUPLICATE 1
#define IPL2TP_V3_PW_L2_SEQUENCE_MATCH_IN_WINDOW 2
#define IPL2TP_V3_PW_L2_SEQUENCE_MATCH_EXPECTED 3
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipl2tp_v3_pw_header
*===========================================================================
* Description: Create the pseudowire header, including data sequencing.
* Parameters: session - The session
* buf - The buffer
* is_ip - Is it IP?
* Returns: The size of the header.
*
*/
IP_STATIC Ip_size_t
ipl2tp_v3_pw_header(Ipl2tp_session *session,
Ip_u8 *buf,
Ip_bool is_ip)
{
Ip_size_t res = 0;
if (session->tunnel->attr.transport == IPL2TP_ATTR_TRANSPORT_UDP)
{
/* No flags set */
IP_SET_HTONS(&buf[res], IPL2TP_VERSION_L2TPV3);
res += 2;
/* Reserved field should be zero */
IP_SET_HTONS(&buf[res], 0);
res += 2;
}
/* Set session identifier */
IP_SET_HTONL(&buf[res], session->remote.key.ident);
res += 4;
/* If there's a cookie, set it */
if (session->remote.cookie.size)
{
ipcom_memcpy(&buf[res],
session->remote.cookie.array,
session->remote.cookie.size);
res += session->remote.cookie.size;
}
/* Deal with sequencing */
if (session->attr.data_sequencing != IPL2TP_ATTR_DATA_SEQUENCING_NEVER)
{
/* Only know how to deal with sublayer default */
if (session->attr.l2_sublayer == IPL2TP_ATTR_L2_SUBLAYER_DEFAULT)
{
Ip_u32 seq = 0;
/* Either always, or non ip */
if (session->attr.data_sequencing == IPL2TP_ATTR_DATA_SEQUENCING_ALWAYS ||
is_ip == IP_FALSE)
{
seq = session->v.v3.dataseq.l2.dfl.next_seq++;
/* Wrap if we go above the 24 bits we have available */
if (session->v.v3.dataseq.l2.dfl.next_seq > IPL2TP_V3_DS_L2_DEFAULT_SEQ_MASK)
session->v.v3.dataseq.l2.dfl.next_seq = 0;
seq |= IPL2TP_V3_DS_L2_DEFAULT_SEQ_FLAG;
}
IP_SET_HTONL(&buf[res], seq);
res += 4;
}
}
return res;
}
/*
*===========================================================================
* ipl2tp_v3_pw_l2_sequence
*===========================================================================
* Description: Calculate the 'flattened' difference between
* the sequence numbers.
* Parameters: first - First received packet for this sequencing
* current - The current sequence number
* last - Last received sequence number
* window - Window size.
* Returns: The difference.
*
*/
IP_STATIC int
ipl2tp_v3_pw_l2_sequence(Ip_bool first,
Ip_u32 current,
Ip_u32 last,
Ip_u32 window)
{
Ip_u32 top;
Ip_u32 diff;
top = current;
if (top < last)
top += window;
/* Get the total difference in the 'flattened' seq nr space */
diff = top - last;
IPCOM_LOG5(ERR,
"window: %u, first = %u, current = %u, last = %u, diff = %u",
window, first, current, last, diff);
/* Wraparound? */
if (diff > window / 2)
/* Outside the window, LE */
return IPL2TP_V3_PW_L2_SEQUENCE_MISS_OUT_OF_WINDOW;
else if (diff == 0 && first == IP_FALSE)
/* Equal to previous received sequenced packet */
return IPL2TP_V3_PW_L2_SEQUENCE_MISS_DUPLICATE;
else if (diff > 1)
/* Within the window but out of order */
return IPL2TP_V3_PW_L2_SEQUENCE_MATCH_IN_WINDOW;
/* Perfect frame */
return IPL2TP_V3_PW_L2_SEQUENCE_MATCH_EXPECTED;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipl2tp_v3_pw_ethernet_input
*===========================================================================
* Description: Feed an incoming Ethernet packet to the IPL2TP engine.
* Parameters: session - 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_GLOBAL Ipl2tp_status
ipl2tp_v3_pw_ethernet_input(Ipl2tp_session *session,
void *buffer,
int length,
int offset,
int align,
Ip_bool is_ip)
{
Ipl2tp_tunnel *tunnel = session->tunnel;
struct Ip_iovec vec[2];
Ip_u8 hdr[4 + 4 + 4 + 8]; /* Max transport header */
Ip_size_t hsize;
Ip_u8 *frame = buffer;
int iovlen = 0;
/**/
IPL2TP_UNUSED(align);
hsize = ipl2tp_v3_pw_header(session, hdr, is_ip);
/* Can we just append the header? */
if ((Ip_size_t)offset >= hsize)
{
frame -= hsize;
length += hsize;
/* Copy in the header */
ipcom_memcpy(frame, hdr, hsize);
/* Store it in the io vector */
vec[iovlen].iov_base = frame;
vec[iovlen].iov_len = length;
iovlen++;
}
else
{
/* Vector them up */
vec[iovlen].iov_base = hdr;
vec[iovlen].iov_len = hsize;
iovlen++;
vec[iovlen].iov_base = frame;
vec[iovlen].iov_len = length;
iovlen++;
}
/* And transmit */
ipl2tp_trpt_data_output(tunnel,
vec,
iovlen);
return IPL2TP_STATUS_OK;
}
/*
*===========================================================================
* ipl2tp_v3_pw_session_data
*===========================================================================
* Description: Feed the incoming data to the proper callback.
* Parameters: buffer - Original buffer
* session - The session in question.
* data - The data we're looking at
* size - Size of the data
* Returns: The status.
*
*/
IP_GLOBAL Ipl2tp_status
ipl2tp_v3_pw_session_data(void *buffer,
Ipl2tp_session *session,
Ip_u8 *data,
Ip_size_t size)
{
/* Data sequencing? */
if (session->attr.data_sequencing)
{
/* Which sublayer are we using? */
if (session->attr.l2_sublayer == IPL2TP_ATTR_L2_SUBLAYER_DEFAULT)
{
Ip_u32 ds = IP_GET_NTOHL(data);
/* Remove the sublayer */
data += 4;
size -= 4;
/* Is there a valid sequence number*/
if (IP_BIT_ISSET(ds, IPL2TP_V3_DS_L2_DEFAULT_SEQ_FLAG))
{
int type;
/* Remove the flags */
ds &= IPL2TP_V3_DS_L2_DEFAULT_SEQ_MASK;
/* The number of sequence numbers we have 'above' our
* last received one */
type = ipl2tp_v3_pw_l2_sequence(session->v.v3.dataseq.received == 0,
ds,
session->v.v3.dataseq.l2.dfl.match_last,
IPL2TP_V3_DS_L2_DEFAULT_SEQ_MASK);
/* Duplicate; just abort */
if (type == IPL2TP_V3_PW_L2_SEQUENCE_MISS_DUPLICATE)
{
if (session->tunnel != IP_NULL)
IPCOM_LOG4(DEBUG,
"%s(%d,%d,%s): Duplicate session level data frame.",
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
(int)session->tunnel->local.key.ident,
(int)session->local.key.ident,
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
return IPL2TP_STATUS_IGNORE;
}
/* We're out of window */
if (type == IPL2TP_V3_PW_L2_SEQUENCE_MISS_OUT_OF_WINDOW)
{
if (session->tunnel != IP_NULL)
IPCOM_LOG4(DEBUG,
"%s(%d,%d,%s): Out of window session level data frame.",
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
(int)session->tunnel->local.key.ident,
(int)session->local.key.ident,
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
/* Deal with out of order */
if (session->v.v3.dataseq.l2.dfl.miss_in_sequence == 0)
{
session->v.v3.dataseq.l2.dfl.miss_last = ds;
session->v.v3.dataseq.l2.dfl.miss_in_sequence = 1;
return IPL2TP_STATUS_IGNORE;
}
else
{
int oorder = ipl2tp_v3_pw_l2_sequence(IP_FALSE,
ds,
session->v.v3.dataseq.l2.dfl.miss_last,
IPL2TP_V3_DS_L2_DEFAULT_SEQ_MASK);
/* If its not in order, reset out of order counter */
if (oorder != IPL2TP_V3_PW_L2_SEQUENCE_MATCH_EXPECTED)
{
session->v.v3.dataseq.l2.dfl.miss_last = ds;
session->v.v3.dataseq.l2.dfl.miss_in_sequence = 1;
return IPL2TP_STATUS_IGNORE;
}
/* Reset if we have this many L2 sequence number in line misses */
if (++session->v.v3.dataseq.l2.dfl.miss_in_sequence < session->attr.l2_out_of_order_reset)
{
session->v.v3.dataseq.l2.dfl.miss_last = ds;
return IPL2TP_STATUS_IGNORE;
}
if (session->tunnel != IP_NULL)
IPCOM_LOG4(DEBUG,
"%s(%d,%d,%s): Out of window session level data frame -- too many misses, resetting sequence.",
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
(int)session->tunnel->local.key.ident,
(int)session->local.key.ident,
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
}
}
/* Either EXPECTED or IN_WINDOW; just accept both */
if (type == IPL2TP_V3_PW_L2_SEQUENCE_MATCH_IN_WINDOW)
{
if (session->tunnel != IP_NULL)
IPCOM_LOG4(DEBUG,
"%s(%d,%d,%s): In window session level data frame",
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
(int)session->tunnel->local.key.ident,
(int)session->local.key.ident,
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
}
if (type == IPL2TP_V3_PW_L2_SEQUENCE_MATCH_EXPECTED)
{
if (session->tunnel != IP_NULL)
IPCOM_LOG4(DEBUG,
"%s(%d,%d,%s): In sequence session level data frame",
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
(int)session->tunnel->local.key.ident,
(int)session->local.key.ident,
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
}
/* Feed this message; it's a match */
session->v.v3.dataseq.l2.dfl.match_last = ds;
session->v.v3.dataseq.l2.dfl.miss_in_sequence = 0;
session->v.v3.dataseq.received++;
}
}
}
if (session->tunnel != IP_NULL)
IPCOM_LOG4(DEBUG,
"%s(%d,%d,%s): Session data received",
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
(int)session->tunnel->local.key.ident,
(int)session->local.key.ident,
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
if (session->attr.circuit_status != IPL2TP_MIB_UP ||
session->v.v3.circuit_status != IPL2TP_MIB_UP)
{
if (session->tunnel != IP_NULL)
IPCOM_LOG4(INFO,
"%s(%d,%d,%s): Session circuit is not currently up, frame discarded",
ipl2tp_versions[IPL2TP_VERSION_L2TPV3],
(int)session->tunnel->local.key.ident,
(int)session->local.key.ident,
ipl2tp_util_ntoa(&session->tunnel->remote.addr));
return IPL2TP_STATUS_CIRCUIT_DOWN;
}
/* Send to user interface */
IPL2TP_SAFE_CALLBACK(session->attr.dcallback,
(session->attr.user_data,
&session->local.key,
buffer,
data,
(Ip_u16)size));
/* Do process */
return IPL2TP_STATUS_OK;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/