original files of m241
This commit is contained in:
@@ -0,0 +1,472 @@
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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
|
||||
****************************************************************************
|
||||
*/
|
||||
Reference in New Issue
Block a user