6768 lines
189 KiB
C++
6768 lines
189 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Copyright Test Competence Center (TCC) ETH 2003 //
|
|
// //
|
|
// The copyright to the computer program(s) herein is the property of TCC. //
|
|
// The program(s) may be used and/or copied only with the written permission //
|
|
// of TCC or in accordance with the terms and conditions stipulated in the //
|
|
// agreement/contract under which the program(s) has been supplied. //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// File: ROHC_EncDec.cc
|
|
// Description: ROHC
|
|
// Rev: R3A01
|
|
// Prodnr: CNL 113 426
|
|
// Updated: 2007-02-07
|
|
// Contact: http://ttcn.ericsson.se
|
|
//
|
|
|
|
/* Based on RFC 3095, July 2001 */
|
|
|
|
#include "IP_Types.hh"
|
|
#include "UDP_Types.hh"
|
|
#include "RTP_Types.hh"
|
|
#include "ROHC_Types.hh"
|
|
|
|
/* ============ Constants ============ */
|
|
|
|
/* Encoding and decoding is performed using static buffers */
|
|
#define MAX_PACKET_SIZE 1500
|
|
#define HEXDUMP_BUFFER_SIZE 1500
|
|
|
|
/* ROHC mode constants */
|
|
#define ROHC_mode_C 0
|
|
#define ROHC_mode_U 1
|
|
#define ROHC_mode_O 2
|
|
#define ROHC_mode_R 3
|
|
|
|
/* Inner and outer IP level numbers */
|
|
#define Inner_IP 1
|
|
#define Outer_IP 0
|
|
|
|
/* ============ Utilities ============ */
|
|
|
|
#define isIR(val) (((val) & 0xFE) == 0xFC)
|
|
#define isIRDYN(val) ((val) == 0xF8)
|
|
#define isUOR2(val) (((val) & 0xE0) == 0xC0)
|
|
|
|
/* Shifts the passed bit value from the position 0 to position N. */
|
|
#define ShiftUpBit(val, position) ((val) << (position)) & (0x01 << (position))
|
|
|
|
/* Shifts the passed bit value from the position N to position 0. */
|
|
#define ShiftDownBit(val, position) (((val) >> (position)) & 0x01)
|
|
|
|
/* Logs an event, when the 'value' field in the type 'typename' is not
|
|
implemented. 'typename' must be provided in '"'s */
|
|
#define Log_not_implemented_union_field(typename, value) \
|
|
TTCN_error("Encoding of the selected union field (%u) in type " \
|
|
typename " is not implemented", (value));
|
|
|
|
/* Prints a hexdump of the buffer 'buf' in length 'length'. */
|
|
#define Log_hexdump(buf, length) \
|
|
TTCN_logger.log(TTCN_DEBUG, "Buffer (length = %d):\n%s", \
|
|
(length), debug_hexdump((buf), debug_buf, (length)));
|
|
|
|
/* Logs the name of the function on entering */
|
|
#define Log_function_name_on_enter() \
|
|
TTCN_logger.log(TTCN_DEBUG, "Entering %s", __FUNCTION__);
|
|
|
|
/* Logs the name of the function on leaving */
|
|
#define Log_function_name_on_leave() \
|
|
TTCN_logger.log(TTCN_DEBUG, "Leaving %s", __FUNCTION__);
|
|
|
|
/* Logs an object */
|
|
#define Log_object(o) \
|
|
TTCN_logger.begin_event(TTCN_DEBUG); \
|
|
(o).log(); \
|
|
TTCN_logger.end_event(); \
|
|
|
|
//**********************************************************
|
|
// NAMESPACE
|
|
//**********************************************************
|
|
|
|
namespace ROHC__Types {
|
|
|
|
using namespace General__Types;
|
|
using namespace IP__Types;
|
|
using namespace UDP__Types;
|
|
using namespace RTP__Types;
|
|
|
|
/* Umbrella type for parsing an incoming ROHC packet */
|
|
typedef struct
|
|
{
|
|
ROHC__context & context;
|
|
int cid;
|
|
int compressed_ah_data_len[2];
|
|
bool ipx_gre_cksum_present[2];
|
|
} t_dat;
|
|
|
|
/* TODO: this is not a thread-safe thing to do. For FT, it does not
|
|
matter, but the buffer should be allocated dynamically. */
|
|
static char debug_buf[HEXDUMP_BUFFER_SIZE];
|
|
|
|
static char *
|
|
debug_hexdump(const unsigned char *src_buf, char *dest_buf, unsigned int len)
|
|
{
|
|
unsigned int offset = 0;
|
|
char val;
|
|
|
|
memset(dest_buf, 0, HEXDUMP_BUFFER_SIZE);
|
|
|
|
if (src_buf == NULL || len == 0)
|
|
return dest_buf;
|
|
|
|
for (unsigned int i = 0; i < len; i++)
|
|
{
|
|
if ((i % 16) == 0 && i > 0)
|
|
{
|
|
dest_buf[offset] = 0x0A; /* newline after each line */
|
|
offset++;
|
|
}
|
|
if ((i % 8) == 0)
|
|
{
|
|
dest_buf[offset] = 0x20; /* space after 8 characters */
|
|
offset++;
|
|
}
|
|
val = (src_buf[i] >> 4) & 0x0F; /* First digit */
|
|
val = (val < 10) ? (val + 48) : (val + 65 - 10);
|
|
dest_buf[offset] = val;
|
|
offset++;
|
|
val = src_buf[i] & 0x0F; /* Second digit */
|
|
val = (val < 10) ? (val + 48) : (val + 65 - 10);
|
|
dest_buf[offset] += val;
|
|
offset++;
|
|
dest_buf[offset] = 0x20; /* space after the value */
|
|
offset++;
|
|
}
|
|
|
|
return dest_buf;
|
|
}
|
|
|
|
/* ============ Consistency check routines ============ */
|
|
void
|
|
Check_field_value(char *text, int urherenow, int wannabe)
|
|
{
|
|
if (wannabe != urherenow)
|
|
{
|
|
TTCN_logger.log(TTCN_WARNING, "Field '%s' must be %u, %u is given",
|
|
text, wannabe, urherenow);
|
|
}
|
|
}
|
|
|
|
void
|
|
Check_field_presence(char *text, bool flag, bool presence)
|
|
{
|
|
if (flag && !presence)
|
|
{
|
|
TTCN_logger.log(TTCN_WARNING, "Field '%s' must be present, when "
|
|
"its presence flag is set", text);
|
|
}
|
|
else if (!flag && presence)
|
|
{
|
|
TTCN_logger.log(TTCN_WARNING, "Field '%s' must not be present, when "
|
|
"its presence flag is unset", text);
|
|
}
|
|
}
|
|
|
|
void
|
|
Check_feedback_code__size(const INT3b & code, const OPTIONAL < LIN1 > &size)
|
|
{
|
|
if (size.ispresent() && code > 0)
|
|
{
|
|
TTCN_logger.log(TTCN_WARNING,
|
|
"Code field must be 0, when size field is specified");
|
|
}
|
|
}
|
|
|
|
void
|
|
Check_feedback_optlen__optsize(const INT4b & len,
|
|
const OPTIONAL < OCTETSTRING > &data)
|
|
{
|
|
if (data.ispresent() && (data().lengthof() != len))
|
|
{
|
|
int flen = len;
|
|
int fdatalen = data().lengthof();
|
|
TTCN_logger.log(TTCN_WARNING,
|
|
"Feedback option length (%u) is different from "
|
|
"the length of feedback option data (%u)", flen, fdatalen);
|
|
}
|
|
else if (!data.ispresent() && len > 0)
|
|
{
|
|
int flen = len;
|
|
TTCN_logger.log(TTCN_WARNING,
|
|
"No feedback option data, but feedback option length "
|
|
"is not 0 (%u)", flen);
|
|
}
|
|
}
|
|
|
|
void
|
|
Check_ps_bit__xi_format(const BIT1 & psbit,
|
|
const OPTIONAL < XI__list > &xilist)
|
|
{
|
|
if (!xilist.ispresent())
|
|
return;
|
|
if (xilist().get_selection() == XI__list::ALT_xi__item8 && (*psbit) == 0)
|
|
{
|
|
TTCN_logger.log(TTCN_WARNING, "PS bit is 0, 4-bit indices must be used");
|
|
}
|
|
else if (xilist().get_selection() == XI__list::ALT_xi__item4 && (*psbit) == 1)
|
|
{
|
|
TTCN_logger.log(TTCN_WARNING, "PS bit is 1, 8-bit indices must be used");
|
|
}
|
|
}
|
|
|
|
INTEGER
|
|
ComputeCRC(const unsigned char *buf, int length, int crclen)
|
|
{
|
|
int crcval, poly, shiftmask;
|
|
|
|
Log_function_name_on_enter();
|
|
TTCN_logger.log(TTCN_DEBUG, "Calculating CRC-%d over:", crclen);
|
|
Log_hexdump(buf, length);
|
|
|
|
switch (crclen)
|
|
{
|
|
case 3:
|
|
poly = 0x06;
|
|
crcval = 0x07;
|
|
shiftmask = 0x03;
|
|
break;
|
|
|
|
case 7:
|
|
poly = 0x79;
|
|
crcval = 0x7F;
|
|
shiftmask = 0x3F;
|
|
break;
|
|
|
|
case 8:
|
|
poly = 0xE0;
|
|
crcval = 0xFF;
|
|
shiftmask = 0x7F;
|
|
break;
|
|
|
|
case 32:
|
|
poly = 0xEDB88320;
|
|
crcval = 0xFFFFFFFF;
|
|
shiftmask = 0x7FFFFFFF;
|
|
break;
|
|
|
|
default:
|
|
poly = 0;
|
|
TTCN_error("Unknown CRC length(%d)\n", crclen);
|
|
break;
|
|
}
|
|
|
|
if (poly == 0)
|
|
return 0;
|
|
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
for (int j = 0; j < 8; j++)
|
|
{
|
|
if ((crcval & 0x01) ^ (ShiftDownBit(buf[i], j)))
|
|
{
|
|
crcval = (crcval >> 1) & shiftmask;
|
|
crcval ^= poly;
|
|
}
|
|
else
|
|
{
|
|
crcval = (crcval >> 1) & shiftmask;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* CRC-32 in ROHC needs to be negated at the end */
|
|
if (crclen == 32)
|
|
{
|
|
crcval ^= 0xffffffff;
|
|
}
|
|
|
|
Log_function_name_on_leave();
|
|
|
|
unsigned int ui = (unsigned int)crcval;
|
|
char sbuf[16];
|
|
sprintf(sbuf, "%u", ui);
|
|
|
|
return INTEGER(sbuf);
|
|
}
|
|
|
|
/* ============ Encoding functions for base types ============ */
|
|
|
|
/** Returns the index of the innermost IP level, based on the number of
|
|
IP levels in the context. */
|
|
int
|
|
getInnermostIPidx(t_dat *dat)
|
|
{
|
|
// More than 1 levels: the innermost is always the index = 1
|
|
if (dat->context.ip__ctx().size_of() > 1)
|
|
return Inner_IP;
|
|
else
|
|
// The index is the one and only 0.
|
|
return Outer_IP;
|
|
}
|
|
|
|
/* Returns the index of the inner or outer IP level in the context, based on the
|
|
number of the IP levels in the context. If the return value is negative,
|
|
it indicates that the outer IP level does not exists. Negative value is
|
|
never returned, if the ip_level is the Inner IP level. */
|
|
int
|
|
getIPidx(t_dat *dat, int ip_level)
|
|
{
|
|
if (ip_level == Outer_IP)
|
|
{
|
|
if (dat->context.ip__ctx().size_of() > 1)
|
|
return Outer_IP;
|
|
else
|
|
return -1;
|
|
}
|
|
else if (ip_level == Inner_IP)
|
|
return getInnermostIPidx(dat);
|
|
else
|
|
return ip_level;
|
|
}
|
|
|
|
/** Initializes the context of the specified IP level. */
|
|
void
|
|
initIPcontext(t_dat *dat, int ip_level, int ip_version)
|
|
{
|
|
unsigned char ctemp = 0;
|
|
IP__context & field = dat->context.ip__ctx()[ip_level];
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
field.version() = INTEGER(ip_version);
|
|
if (! field.rnd__bit().is_bound()) field.rnd__bit() = BOOLEAN(ctemp);
|
|
if (! field.ah__present().is_bound()) field.ah__present() = BOOLEAN(ctemp);
|
|
if (! field.gre__present().is_bound()) field.gre__present() = BOOLEAN(ctemp);
|
|
if (! field.esp__present().is_bound()) field.esp__present() = BOOLEAN(ctemp);
|
|
if (! field.ah__data__len().is_bound())
|
|
field.ah__data__len() = INTEGER(ctemp);
|
|
if (! field.gre__cksum__present().is_bound())
|
|
field.gre__cksum__present() = BOOLEAN(ctemp);
|
|
|
|
Log_object(dat->context);
|
|
|
|
Log_function_name_on_leave();
|
|
}
|
|
|
|
/** Initializes the UDP context. */
|
|
void
|
|
initUDPcontext(t_dat *dat)
|
|
{
|
|
unsigned char ctemp = 1;
|
|
UDP__context & field = dat->context.udp__ctx();
|
|
|
|
if (! field.udp__cksum().is_bound()) field.udp__cksum() = BOOLEAN(ctemp);
|
|
}
|
|
|
|
/** Initializes the specified CID's context. */
|
|
void
|
|
initCIDcontext(t_dat *dat)
|
|
{
|
|
unsigned char ctemp = 0;
|
|
ROHC__context & field = dat->context;
|
|
|
|
if (! field.mode().is_bound()) field.mode() = INTEGER(cg__ROHC__mode__U);
|
|
if (! field.profile().is_bound()) field.profile() = INTEGER(ctemp);
|
|
if (! field.pkt().is_bound()) field.pkt() = Packet__type(Packet__type::IR);
|
|
if (! field.ip__ctx().is_bound()) initIPcontext(dat, 0, 4);
|
|
initUDPcontext(dat);
|
|
}
|
|
|
|
/** Initializes the umbrella type before the ROHC packet parsing starts. */
|
|
t_dat
|
|
initTDAT(ROHC__config & config, int cid)
|
|
{
|
|
t_dat dat = { config.context()[cid], cid, {0, 0}, {false, false} };
|
|
|
|
// Expect AH auth data and GRE checksum after the compressed header
|
|
// by default. If the uncompressed form is used, these values will be
|
|
// set to 0 or false during parsing.
|
|
dat.compressed_ah_data_len[0] =
|
|
config.context()[cid].ip__ctx()[0].ah__data__len();
|
|
dat.ipx_gre_cksum_present[0] =
|
|
config.context()[cid].ip__ctx()[0].gre__cksum__present();
|
|
if (config.context()[cid].ip__ctx().size_of() > 1)
|
|
{
|
|
dat.compressed_ah_data_len[1] =
|
|
config.context()[cid].ip__ctx()[1].ah__data__len();
|
|
dat.ipx_gre_cksum_present[1] =
|
|
config.context()[cid].ip__ctx()[1].gre__cksum__present();
|
|
}
|
|
return dat;
|
|
}
|
|
|
|
/** Returns, whether there is any compressed IPv4 level,
|
|
where the RND bit is 0. */
|
|
bool
|
|
isAnyIPv4RNDunset(t_dat *dat)
|
|
{
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
int ip_idx = getIPidx(dat, i);
|
|
|
|
if (ip_idx >= 0) // IP level exists
|
|
{
|
|
if (! dat->context.ip__ctx()[ip_idx].rnd__bit())
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Encodes an OCTETSTING value */
|
|
int
|
|
Set_octetstring(unsigned char *buf, const OCTETSTRING & val)
|
|
{
|
|
memcpy(&(buf[0]), val, val.lengthof());
|
|
return val.lengthof();
|
|
}
|
|
|
|
/* Encodes a LIN2_BO_LAST value */
|
|
int
|
|
Set_LIN2_BO_LAST(unsigned char *buf, const LIN2__BO__LAST & val)
|
|
{
|
|
buf[0] = (val >> 8) & 0xFF;
|
|
buf[1] = val & 0xFF;
|
|
return 2;
|
|
}
|
|
|
|
/* Encodes a LIN4_BO_LAST value */
|
|
int
|
|
Set_LIN4_BO_LAST(unsigned char *buf, const LIN4__BO__LAST & val)
|
|
{
|
|
buf[0] = (val >> 24) & 0xFF;
|
|
buf[1] = (val >> 16) & 0xFF;
|
|
buf[2] = (val >> 8) & 0xFF;
|
|
buf[3] = val & 0xFF;
|
|
return 4;
|
|
}
|
|
|
|
/* Encodes a LIN1 value */
|
|
int
|
|
Set_LIN1(unsigned char *buf, const LIN1 & val)
|
|
{
|
|
buf[0] = val & 0xFF;
|
|
return 1;
|
|
}
|
|
|
|
/* Returns the length of the SDVL encoded CID value 'val'. If the value
|
|
is invalid, exits via the ttcn_error(). */
|
|
int
|
|
SDVL_encoded_CID_length(int val)
|
|
{
|
|
if (val <= 0x7F)
|
|
return 1;
|
|
else if (val <= 0x3FFF)
|
|
return 2;
|
|
else if (val <= 0x1FFFFF)
|
|
return 3;
|
|
else if (val <= 0x1FFFFFFF)
|
|
return 4;
|
|
else
|
|
TTCN_error("Value %u is too big for the SDVL encoder "
|
|
"(at most 29 bits can be used)", val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
Set_SDVL_field(unsigned char *buf, const INTEGER & val, int encoded_length)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if ((val <= 0x7F && encoded_length == 0) || encoded_length == 1)
|
|
{
|
|
buf[len] = val & 0x7F;
|
|
len += 1;
|
|
}
|
|
else if ((val <= 0x3FFF && encoded_length == 0) || encoded_length == 2)
|
|
{
|
|
buf[len] = 0x80 | ((val >> 8) & 0x7F);
|
|
len += 1;
|
|
buf[len] = val & 0xFF;
|
|
len += 1;
|
|
}
|
|
else if ((val <= 0x1FFFFF && encoded_length == 0) || encoded_length == 3)
|
|
{
|
|
buf[len] = 0xC0 | ((val >> 16) & 0x3F);
|
|
len += 1;
|
|
buf[len] = (val >> 8) & 0xFF;
|
|
len += 1;
|
|
buf[len] = val & 0xFF;
|
|
len += 1;
|
|
}
|
|
else if ((val <= 0x1FFFFFFF && encoded_length == 0) || encoded_length == 4)
|
|
{
|
|
buf[len] = 0xE0 | ((val >> 24) & 0x1F);
|
|
len += 1;
|
|
buf[len] = (val >> 16) & 0xFF;
|
|
len += 1;
|
|
buf[len] = (val >> 8) & 0xFF;
|
|
len += 1;
|
|
buf[len] = val & 0xFF;
|
|
len += 1;
|
|
}
|
|
else
|
|
{
|
|
int tmp = val;
|
|
TTCN_error("Value %u (specified length is %u) is too big for the "
|
|
"SDVL encoder (at most 29 bits can be used)",
|
|
tmp, encoded_length);
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
/* ============ Encoding wrappers for optional base types ============ */
|
|
|
|
/* Encodes an optional OCTETSTING value */
|
|
int
|
|
Set_octetstring_opt(unsigned char *buf, const OPTIONAL < OCTETSTRING > &val)
|
|
{
|
|
if (!val.ispresent())
|
|
return 0;
|
|
return Set_octetstring(buf, val());
|
|
}
|
|
|
|
/* Encodes an optional LIN2_BO_LAST value */
|
|
int
|
|
Set_LIN2_BO_LAST_opt(unsigned char *buf,
|
|
const OPTIONAL < LIN2__BO__LAST > &val)
|
|
{
|
|
if (!val.ispresent())
|
|
return 0;
|
|
return Set_LIN2_BO_LAST(buf, val());
|
|
}
|
|
|
|
/* Encodes an optional LIN4_BO_LAST value */
|
|
int
|
|
Set_LIN4_BO_LAST_opt(unsigned char *buf,
|
|
const OPTIONAL < LIN4__BO__LAST > &val)
|
|
{
|
|
if (!val.ispresent())
|
|
return 0;
|
|
return Set_LIN4_BO_LAST(buf, val());
|
|
}
|
|
|
|
/* Encodes an optional LIN1 value */
|
|
int
|
|
Set_LIN1_opt(unsigned char *buf, const OPTIONAL < LIN1 > &val)
|
|
{
|
|
if (!val.ispresent())
|
|
return 0;
|
|
return Set_LIN1(buf, val());
|
|
}
|
|
|
|
int
|
|
Set_SDVL_field_opt(unsigned char *buf,
|
|
const OPTIONAL < INTEGER > &val, int length)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!val.ispresent())
|
|
return 0;
|
|
len += Set_SDVL_field(buf, val(), length);
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
|
|
/* ============ Encoding functions for common ROHC types ============ */
|
|
|
|
int
|
|
Set_CID(unsigned char *buf, const INTEGER & cid, BOOLEAN const &large_cid)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (large_cid == false)
|
|
{
|
|
if (cid > 0)
|
|
{
|
|
buf[len] = 0xE0 + (cid & 0x0F);
|
|
len += 1;
|
|
}
|
|
}
|
|
else
|
|
len += Set_SDVL_field(&buf[len], cid, 0);
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
/* CSRC and IP extension header item list encoding */
|
|
int
|
|
Set_Item_list_opt(unsigned char *buf, const OPTIONAL < Item__list > &item_list)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!item_list.ispresent())
|
|
{
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
|
|
/* Item list is an IP extension header list */
|
|
if (item_list().get_selection() == Item__list::ALT_ip__item__list)
|
|
{
|
|
IP__Item__list ip_item_list = item_list().ip__item__list();
|
|
|
|
for (int num = 0; num < ip_item_list.size_of(); num++)
|
|
{
|
|
int start_pos = len;
|
|
|
|
switch (ip_item_list[num].get_selection())
|
|
{
|
|
case Item::ALT_ipv6__ext__item:
|
|
{
|
|
IPv6__ext__item & item = ip_item_list[num].ipv6__ext__item();
|
|
|
|
len += Set_LIN1(&buf[len], item.nexthead());
|
|
/* Length of the header in 8-octet units, not including
|
|
the first 8 octets. */
|
|
if (item.hdr__ext__len() == 0)
|
|
{
|
|
if ((item.data().lengthof() + 2) % 8 != 0)
|
|
{
|
|
TTCN_error("Invalid length (%u) of the IPv6 extension header",
|
|
item.data().lengthof());
|
|
}
|
|
buf[len] = (item.data().lengthof() + 2) / 8 - 1;
|
|
len += 1;
|
|
}
|
|
else
|
|
len += Set_LIN1(&buf[len], item.hdr__ext__len());
|
|
len += Set_octetstring(&buf[len], item.data());
|
|
break;
|
|
}
|
|
case Item::ALT_mine__item:
|
|
{
|
|
MINE__item & item = ip_item_list[num].mine__item();
|
|
|
|
Check_field_value("MINE protocol", item.protocol(), c__ip__proto__mine);
|
|
Check_field_value("MINE reserved", *item.reserved(), 0);
|
|
|
|
len += Set_LIN1(&buf[len], item.protocol());
|
|
buf[len] = (*item.s__bit()) << 7;
|
|
buf[len] += *item.reserved();
|
|
len += 1;
|
|
len += Set_LIN2_BO_LAST(&buf[len], item.cksum());
|
|
len += Set_octetstring(&buf[len], item.dstaddr());
|
|
len += Set_octetstring_opt(&buf[len], item.srcaddr());
|
|
break;
|
|
}
|
|
case Item::ALT_ah__item:
|
|
{
|
|
AH__item & item = ip_item_list[num].ah__item();
|
|
|
|
Check_field_value("AH nexthead", item.nexthead(), c__ip__proto__ah);
|
|
len += Set_LIN1(&buf[len], item.nexthead());
|
|
|
|
/* RFC 2402: This 8-bit field specifies the length of AH in
|
|
32-bit words (4-byte units), minus "2". */
|
|
if (item.payload__len() == 0)
|
|
{
|
|
if (item.auth__data().ispresent())
|
|
buf[len] = (item.auth__data()().lengthof() / 4) + 3 - 2;
|
|
else
|
|
buf[len] = 1;
|
|
len += 1;
|
|
}
|
|
else
|
|
len += Set_LIN1(&buf[len], item.payload__len());
|
|
|
|
Check_field_value("AH reserved", item.reserved(), 0);
|
|
len += Set_LIN2_BO_LAST(&buf[len], item.reserved());
|
|
len += Set_LIN4_BO_LAST(&buf[len], item.spi());
|
|
len += Set_LIN4_BO_LAST(&buf[len], item.sn());
|
|
len += Set_octetstring_opt(&buf[len], item.auth__data());
|
|
break;
|
|
}
|
|
case Item::ALT_esp__item:
|
|
{
|
|
ESP__item & item = ip_item_list[num].esp__item();
|
|
|
|
Check_field_value("ESP nexthead", item.nexthead(), c__ip__proto__esp);
|
|
len += Set_LIN1(&buf[len], item.nexthead());
|
|
len += Set_LIN4_BO_LAST(&buf[len], item.spi());
|
|
len += Set_LIN4_BO_LAST(&buf[len], item.sn());
|
|
break;
|
|
}
|
|
case Item::ALT_gre__item:
|
|
{
|
|
GRE__item & item = ip_item_list[num].gre__item();
|
|
|
|
Check_field_value("GRE nexthead", item.nexthead(), c__ip__proto__gre2);
|
|
len += Set_LIN1(&buf[len], item.nexthead());
|
|
buf[len] = (*item.C__bit()) << 7;
|
|
Check_field_value("GRE reserved1", (int) *item.reserved__1(), 0);
|
|
buf[len] += (*item.reserved__1()) << 6;
|
|
buf[len] += (*item.K__bit()) << 5;
|
|
buf[len] += (*item.S__bit()) << 4;
|
|
Check_field_value("GRE reserved2", (int) *item.reserved__2(), 0);
|
|
buf[len] += (*item.reserved__2()) << 3;
|
|
buf[len] += *item.version();
|
|
len += 1;
|
|
Check_field_presence("checksum", *item.C__bit() == 1,
|
|
item.cksum().ispresent());
|
|
Check_field_presence("key", *item.K__bit() == 1,
|
|
item.key().ispresent());
|
|
Check_field_presence("sn", *item.S__bit() == 1,
|
|
item.sn().ispresent());
|
|
len += Set_LIN2_BO_LAST_opt(&buf[len], item.cksum());
|
|
len += Set_LIN4_BO_LAST_opt(&buf[len], item.key());
|
|
len += Set_LIN4_BO_LAST_opt(&buf[len], item.sn());
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
Log_not_implemented_union_field("Item",
|
|
ip_item_list[num].get_selection());
|
|
break;
|
|
}
|
|
}
|
|
TTCN_logger.log(TTCN_DEBUG, "%uth item:", num);
|
|
Log_hexdump(&(buf[start_pos]), len - start_pos);
|
|
}
|
|
}
|
|
else if (item_list().get_selection() == Item__list::ALT_csrc__item__list)
|
|
{
|
|
/* Item list is CSRC item list */
|
|
for (int num = 0; num < item_list().csrc__item__list().size_of(); num++)
|
|
{
|
|
int start_pos = len;
|
|
|
|
len += Set_octetstring( &buf[len],
|
|
item_list().csrc__item__list()[num] );
|
|
TTCN_logger.log(TTCN_DEBUG, "%uth item:", num);
|
|
Log_hexdump(&(buf[start_pos]), len - start_pos);
|
|
}
|
|
}
|
|
else if (item_list().get_selection() == Item__list::ALT_raw__data)
|
|
{
|
|
/* Item list is a raw octetstring */
|
|
for (int num = 0; num < item_list().csrc__item__list().size_of(); num++)
|
|
{
|
|
int start_pos = len;
|
|
|
|
len += Set_octetstring(&buf[len], item_list().raw__data()[num] );
|
|
TTCN_logger.log(TTCN_DEBUG, "%uth item:", num);
|
|
Log_hexdump(&(buf[start_pos]), len - start_pos);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log_not_implemented_union_field("Item_list", item_list().get_selection());
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_XI_list_opt(unsigned char *buf, const OPTIONAL < XI__list > &xilist,
|
|
const OPTIONAL < BITSTRING > &padding, int length)
|
|
{
|
|
int len = 0;
|
|
int halfbyte = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!xilist.ispresent())
|
|
{
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
|
|
switch (xilist().get_selection())
|
|
{
|
|
case XI__list::ALT_xi__item4:
|
|
{
|
|
if (length != xilist().xi__item4().size_of())
|
|
TTCN_logger.log(TTCN_WARNING,
|
|
"Number of indices != value of CC field");
|
|
for (int num = 0; num < xilist().xi__item4().size_of(); num++)
|
|
{
|
|
if (halfbyte)
|
|
{
|
|
buf[len] += ((*xilist().xi__item4()[num].x__ind()) << 3) & 0x08;
|
|
buf[len] += xilist().xi__item4()[num].index() & 0x07;
|
|
len += 1;
|
|
}
|
|
else
|
|
{
|
|
buf[len] = ((*xilist().xi__item4()[num].x__ind()) << 7) & 0x80;
|
|
buf[len] += (xilist().xi__item4()[num].index() << 4) & 0x70;
|
|
}
|
|
halfbyte = 1 - halfbyte; // Invert the value (0 -> 1 or 1 -> 0)
|
|
}
|
|
break;
|
|
}
|
|
|
|
case XI__list::ALT_xi__item8:
|
|
{
|
|
if (length != xilist().xi__item8().size_of())
|
|
TTCN_logger.log(TTCN_WARNING,
|
|
"Number of indices != value of CC field");
|
|
for (int num = 0; num < xilist().xi__item8().size_of(); num++)
|
|
{
|
|
buf[len] = ((*xilist().xi__item8()[num].x__ind()) << 7) & 0x80;
|
|
buf[len] += xilist().xi__item8()[num].index() & 0x7F;
|
|
len += 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
Log_not_implemented_union_field("XI_list", xilist().get_selection());
|
|
break;
|
|
}
|
|
|
|
if (padding.ispresent() && halfbyte == 0)
|
|
{
|
|
TTCN_logger.log(TTCN_WARNING, "Specified padding is ignored");
|
|
}
|
|
else if (!padding.ispresent() && halfbyte)
|
|
{
|
|
TTCN_logger.log(TTCN_WARNING,
|
|
"Padding not specified, padding bits left uninitialized");
|
|
}
|
|
else if (padding.ispresent())
|
|
{
|
|
Check_field_value("Index padding", *padding(), 0);
|
|
buf[len] += (*padding()) & 0x0F;
|
|
len += 1;
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Encoding_Type_0(unsigned char *buf, const Enc__Type__0 & enct0)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_presence("gen_id", *enct0.gp__bit() == 1,
|
|
enct0.gen__id().ispresent());
|
|
|
|
Check_field_value("Encoding type", *enct0.et(), 0);
|
|
buf[len] = ((*enct0.et()) << 6) & 0xC0;
|
|
buf[len] += ShiftUpBit(*enct0.gp__bit(), 5);
|
|
buf[len] += ShiftUpBit(*enct0.ps__bit(), 4);
|
|
buf[len] += enct0.cc() & 0x0F;
|
|
len += 1;
|
|
len += Set_LIN1_opt(&buf[len], enct0.gen__id());
|
|
Check_ps_bit__xi_format(enct0.ps__bit(), enct0.xi__list());
|
|
len += Set_XI_list_opt(&buf[len], enct0.xi__list(), enct0.padding(),
|
|
enct0.cc());
|
|
len += Set_Item_list_opt(&buf[len], enct0.item__list());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
int
|
|
Set_Encoding_Type_1(unsigned char *buf, const Enc__Type__1 & enct1)
|
|
{
|
|
int len = 0;
|
|
int n = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_presence("gen_id", *enct1.gp__bit() == 1,
|
|
enct1.gen__id().ispresent());
|
|
|
|
Check_field_value("Encoding type", *enct1.et(), 1);
|
|
buf[len] = ((*enct1.et()) << 6) & 0xC0;
|
|
buf[len] += ShiftUpBit(*enct1.gp__bit(), 5);
|
|
buf[len] += ShiftUpBit(*enct1.ps__bit(), 4);
|
|
buf[len] += enct1.xi1() & 0x0F;
|
|
len += 1;
|
|
len += Set_LIN1_opt(&buf[len], enct1.gen__id());
|
|
len += Set_LIN1_opt(&buf[len], enct1.ref__id());
|
|
len += Set_octetstring(&buf[len], enct1.insbitmask());
|
|
|
|
// Count the number of 1's in the bitmask
|
|
for (int i = 0; i < enct1.insbitmask().lengthof(); ++i)
|
|
{
|
|
if (enct1.insbitmask() & int2oct(i + 1, enct1.insbitmask().lengthof()))
|
|
++n;
|
|
}
|
|
|
|
Check_ps_bit__xi_format(enct1.ps__bit(), enct1.xi__list());
|
|
len += Set_XI_list_opt(&buf[len], enct1.xi__list(), enct1.padding(), n);
|
|
len += Set_Item_list_opt(&buf[len], enct1.item__list());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
int
|
|
Set_Encoding_Type_2(unsigned char *buf, const Enc__Type__2 & enct2)
|
|
{
|
|
int len = 0;
|
|
|
|
Check_field_presence("gen_id", *enct2.gp__bit() == 1,
|
|
enct2.gen__id().ispresent());
|
|
|
|
Check_field_value("Encoding type", *enct2.et(), 2);
|
|
buf[len] = ((*enct2.et()) << 6) & 0xC0;
|
|
buf[len] += ShiftUpBit(*enct2.gp__bit(), 5);
|
|
buf[len] += ShiftUpBit(*enct2.res(), 4);
|
|
buf[len] += enct2.count() & 0x0F;
|
|
len += 1;
|
|
len += Set_LIN1_opt(&buf[len], enct2.gen__id());
|
|
len += Set_LIN1_opt(&buf[len], enct2.ref__id());
|
|
len += Set_octetstring(&buf[len], enct2.rembitmask());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
int
|
|
Set_Encoding_Type_3(unsigned char *buf, const Enc__Type__3 & enct3)
|
|
{
|
|
int len = 0;
|
|
int n = 0;
|
|
|
|
Check_field_presence("gen_id", *enct3.gp__bit() == 1,
|
|
enct3.gen__id().ispresent());
|
|
|
|
Check_field_value("Encoding type", *enct3.et(), 3);
|
|
buf[len] = ((*enct3.et()) << 6) & 0xC0;
|
|
buf[len] += ShiftUpBit(*enct3.gp__bit(), 5);
|
|
buf[len] += ShiftUpBit(*enct3.ps__bit(), 4);
|
|
buf[len] += enct3.xi1() & 0x0F;
|
|
len += 1;
|
|
len += Set_LIN1_opt(&buf[len], enct3.gen__id());
|
|
len += Set_LIN1_opt(&buf[len], enct3.ref__id());
|
|
len += Set_octetstring(&buf[len], enct3.rembitmask());
|
|
len += Set_octetstring(&buf[len], enct3.insbitmask());
|
|
|
|
// Count the number of 1's in the bitmask
|
|
for (int i = 0; i < enct3.insbitmask().lengthof(); ++i)
|
|
{
|
|
if (enct3.insbitmask() & int2oct(i + 1, enct3.insbitmask().lengthof()))
|
|
++n;
|
|
}
|
|
Check_ps_bit__xi_format(enct3.ps__bit(), enct3.xi__list());
|
|
len += Set_XI_list_opt(&buf[len], enct3.xi__list(), enct3.padding(), n);
|
|
len += Set_Item_list_opt(&buf[len], enct3.item__list());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Compr_head_list_opt(unsigned char *buf,
|
|
const OPTIONAL < Compr__head__list > &chl)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!chl.ispresent())
|
|
{
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
if (chl().get_selection() == Compr__head__list::ALT_enctype0)
|
|
len += Set_Encoding_Type_0(&buf[len], chl().enctype0());
|
|
else if (chl().get_selection() == Compr__head__list::ALT_enctype1)
|
|
len += Set_Encoding_Type_1(&buf[len], chl().enctype1());
|
|
else if (chl().get_selection() == Compr__head__list::ALT_enctype2)
|
|
len += Set_Encoding_Type_2(&buf[len], chl().enctype2());
|
|
else if (chl().get_selection() == Compr__head__list::ALT_enctype3)
|
|
len += Set_Encoding_Type_3(&buf[len], chl().enctype3());
|
|
else
|
|
{
|
|
Log_not_implemented_union_field("Compr_head_list", chl().get_selection());
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_AEGSeqnum_opt(unsigned char *buf, const OPTIONAL < AEGSeqnum > &oseqn)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!oseqn.ispresent())
|
|
{
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
if (oseqn().get_selection() == AEGSeqnum::ALT_short__form)
|
|
{
|
|
Check_field_value("form-bit", (int) *oseqn().short__form().ind(), 0);
|
|
buf[len] = ShiftUpBit(*oseqn().short__form().ind(), 7);
|
|
buf[len] += oseqn().short__form().lsb__of__seqnum() & 0x7F;
|
|
len += 1;
|
|
}
|
|
else if (oseqn().get_selection() == AEGSeqnum::ALT_long__form)
|
|
{
|
|
Check_field_value("form-bit", (int) *oseqn().long__form().ind(), 1);
|
|
buf[len] = ShiftUpBit(*oseqn().long__form().ind(), 7);
|
|
buf[len] += (oseqn().long__form().lsb__of__seqnum() >> 24) & 0x7F;
|
|
len += 1;
|
|
|
|
buf[len] = (oseqn().long__form().lsb__of__seqnum() >> 16) & 0xFF;
|
|
len += 1;
|
|
|
|
buf[len] = (oseqn().long__form().lsb__of__seqnum() >> 8) & 0xFF;
|
|
len += 1;
|
|
|
|
buf[len] = oseqn().long__form().lsb__of__seqnum() & 0xFF;
|
|
len += 1;
|
|
}
|
|
else
|
|
Log_not_implemented_union_field("AEGSeqnum", oseqn().get_selection());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_IPv4_static_chain(unsigned char *buf, const IPv4__Static & chain)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("IPv4 version", chain.version(), 4);
|
|
buf[len] = (chain.version() << 4) & 0xF0;
|
|
Check_field_value("IPv4 reserved (static chain)", chain.reserved(), 0);
|
|
buf[len] += chain.reserved() & 0x0F;
|
|
len += 1;
|
|
len += Set_LIN1(&buf[len], chain.proto());
|
|
len += Set_octetstring(&buf[len], chain.srcaddr());
|
|
len += Set_octetstring(&buf[len], chain.dstaddr());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_IPv6_static_chain(unsigned char *buf, const IPv6__Static & chain)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("IPv6 version", chain.version(), 6);
|
|
buf[len] = (chain.version() << 4) & 0xF0;
|
|
buf[len] += (chain.flowlabel() >> 16) & 0x0F;
|
|
len += 1;
|
|
|
|
buf[len] = (chain.flowlabel() >> 8) & 0xFF;
|
|
len += 1;
|
|
buf[len] = chain.flowlabel() & 0xFF;
|
|
len += 1;
|
|
|
|
len += Set_LIN1(&buf[len], chain.nexthead());
|
|
len += Set_octetstring(&buf[len], chain.srcaddr());
|
|
len += Set_octetstring(&buf[len], chain.dstaddr());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_UDP_static_chain(unsigned char *buf, const UDP__Static & chain)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
len += Set_LIN2_BO_LAST(&buf[len], chain.srcport());
|
|
len += Set_LIN2_BO_LAST(&buf[len], chain.dstport());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_RTP_static_chain(unsigned char *buf, const RTP__Static & chain)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
len += Set_octetstring(&buf[len], chain.ssrc());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_RTP_dynamic_chain(unsigned char *buf, const RTP__Dynamic & chain)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("RTP version", chain.vfield(), 2);
|
|
buf[len] = (chain.vfield() << 6) & 0xC0;
|
|
buf[len] += ShiftUpBit(*chain.pbit(), 5);
|
|
buf[len] += ShiftUpBit(*chain.rxbit(), 4);
|
|
buf[len] += chain.ccfield() & 0x0F;
|
|
len += 1;
|
|
buf[len] = ShiftUpBit(*chain.mbit(), 7);
|
|
buf[len] += chain.ptfield() & 0x7F;
|
|
len += 1;
|
|
len += Set_LIN2_BO_LAST(&buf[len], chain.rtpseqnum());
|
|
len += Set_LIN4_BO_LAST(&buf[len], chain.rtpts());
|
|
len += Set_Encoding_Type_0(&buf[len], chain.gencsrclist());
|
|
Check_field_presence("RTP rx", *chain.rxbit() == 1,
|
|
chain.rx__field().ispresent());
|
|
if (chain.rx__field().ispresent())
|
|
{
|
|
Check_field_value("RX reserved", (int) *chain.rx__field()().reserved(), 0);
|
|
buf[len] = ((*chain.rx__field()().reserved()) << 5) & 0xE0;
|
|
buf[len] += ShiftUpBit(*chain.rx__field()().xbit(), 4);
|
|
buf[len] += (chain.rx__field()().mode() << 2) & 0x0C;
|
|
buf[len] += ShiftUpBit(*chain.rx__field()().tisbit(), 1);
|
|
buf[len] += ShiftUpBit(*chain.rx__field()().tssbit(), 0);
|
|
len += 1;
|
|
}
|
|
Check_field_presence("TS Stride",
|
|
chain.rx__field().ispresent() &&
|
|
(*chain.rx__field()().tssbit()) == 1,
|
|
chain.ts__stride().ispresent());
|
|
Check_field_presence("TIME Stride",
|
|
chain.rx__field().ispresent() &&
|
|
(*chain.rx__field()().tisbit()) == 1,
|
|
chain.time__stride().ispresent());
|
|
len += Set_SDVL_field_opt(&buf[len], chain.ts__stride(), 0);
|
|
len += Set_SDVL_field_opt(&buf[len], chain.time__stride(), 0);
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_RTP_flags_fields_opt(unsigned char *buf,
|
|
const OPTIONAL < RTP__flags__fields > &field)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!field.ispresent())
|
|
{
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
buf[len] = (field().mode() << 6) & 0xC0;
|
|
buf[len] += ShiftUpBit(*field().r__pt(), 5);
|
|
buf[len] += ShiftUpBit(*field().m__bit(), 4);
|
|
buf[len] += ShiftUpBit(*field().r__x(), 3);
|
|
buf[len] += ShiftUpBit(*field().csrc(), 2);
|
|
buf[len] += ShiftUpBit(*field().tss(), 1);
|
|
buf[len] += ShiftUpBit(*field().tis(), 0);
|
|
len += 1;
|
|
|
|
Check_field_presence("RTP flags",
|
|
*field().r__pt() == 1, field().flags().ispresent());
|
|
if (field().flags().ispresent())
|
|
{
|
|
buf[len] = (((*field().flags()().r__p()) << 7) & 0x80) +
|
|
(field().flags()().rtp__pt() & 0x7F);
|
|
len += 1;
|
|
}
|
|
Check_field_presence("Compressed CSRC list",
|
|
*field().csrc() == 1, field().csrc__list().ispresent());
|
|
len += Set_Compr_head_list_opt(&buf[len], field().csrc__list());
|
|
Check_field_presence("TS_STRIDE",
|
|
*field().tss() == 1, field().ts__stride().ispresent());
|
|
len += Set_SDVL_field_opt(&buf[len], field().ts__stride(), 0);
|
|
Check_field_presence("TIME_STRIDE",
|
|
*field().tis() == 1,
|
|
field().time__stride().ispresent());
|
|
len += Set_SDVL_field_opt(&buf[len], field().time__stride(), 0);
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_IPv4_dynamic_chain(unsigned char *buf, const IPv4__Dynamic & chain)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
len += Set_LIN1(&buf[len], chain.tos());
|
|
len += Set_LIN1(&buf[len], chain.ttl());
|
|
len += Set_LIN2_BO_LAST(&buf[len], chain.identification());
|
|
|
|
buf[len] = ShiftUpBit(*chain.df__bit(), 7);
|
|
buf[len] += ShiftUpBit(*chain.rnd__bit(), 6);
|
|
buf[len] += ShiftUpBit(*chain.nbo__bit(), 5);
|
|
Check_field_value("IPv4 reserved (dynamic chain)", *chain.reserved(), 0);
|
|
buf[len] += (*chain.reserved()) & 0x1F;
|
|
len += 1;
|
|
len += Set_Encoding_Type_0(&buf[len], chain.genextheadlist());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_IPv6_dynamic_chain(unsigned char *buf, const IPv6__Dynamic & chain)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
len += Set_LIN1(&buf[len], chain.trafficclass());
|
|
len += Set_LIN1(&buf[len], chain.hoplimit());
|
|
len += Set_Encoding_Type_0(&buf[len], chain.genextheadlist());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
/* ============ Encoding functions for ROHC types ============ */
|
|
int
|
|
Set_feedback(unsigned char *buf, const Feedback__u & feedback,
|
|
BOOLEAN const &large_cid)
|
|
{
|
|
int len = 0, crcpos = 0, crcstart = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("feedback type", (int) *feedback.feedback__type(), 30);
|
|
Check_feedback_code__size(feedback.code(), feedback.size());
|
|
buf[len] = ((*feedback.feedback__type()) << 3) & 0xF8;
|
|
buf[len] += feedback.code() & 0x07;
|
|
len += 1;
|
|
|
|
len += Set_LIN1_opt(&buf[len], feedback.size());
|
|
|
|
crcstart = len;
|
|
|
|
len += Set_CID(&buf[len], feedback.feedback__data().cid(), large_cid);
|
|
|
|
switch (feedback.feedback__data().feedback__type().get_selection())
|
|
{
|
|
case Feedback__type::ALT_feedback1:
|
|
{
|
|
Feedback1 fback1 =
|
|
feedback.feedback__data().feedback__type().feedback1();
|
|
|
|
len += Set_octetstring(&buf[len], fback1);
|
|
break;
|
|
}
|
|
|
|
case Feedback__type::ALT_feedback2:
|
|
{
|
|
Feedback2 fback2 =
|
|
feedback.feedback__data().feedback__type().feedback2();
|
|
|
|
buf[len] = (fback2.acktype() << 6) & 0xC0;
|
|
buf[len] += (fback2.mode() << 4) & 0x30;
|
|
buf[len] += (fback2.sn() >> 8) & 0x0F;
|
|
len += 1;
|
|
|
|
buf[len] = fback2.sn() & 0xFF;
|
|
len += 1;
|
|
|
|
if (fback2.feedback__opts().ispresent())
|
|
{
|
|
Feedback__opts & fbopts = fback2.feedback__opts();
|
|
|
|
for (int num = 0; num < fbopts.size_of(); num++)
|
|
{
|
|
buf[len] = (fbopts[num].opt__type() << 4) & 0xF0;
|
|
Check_feedback_optlen__optsize(fbopts[num].opt__len(),
|
|
fbopts[num].opt__data());
|
|
buf[len] += fbopts[num].opt__len() & 0x0F;
|
|
len += 1;
|
|
|
|
len += Set_octetstring_opt(&buf[len], fbopts[num].opt__data());
|
|
if (fbopts[num].opt__data().ispresent())
|
|
{
|
|
if ((fbopts[num].opt__len() == 1)
|
|
&& (fbopts[num].opt__type() == 1) && (buf[len - 1] == 0))
|
|
crcpos = len - 1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (feedback.size().ispresent() && feedback.size() == 0)
|
|
{
|
|
buf[1] = (len - 2) & 0xFF;
|
|
}
|
|
if ((!feedback.size().ispresent()) && feedback.code() == 0)
|
|
{
|
|
buf[0] = (buf[0] & 0xF8) + ((len - 1) & 0x07);
|
|
}
|
|
|
|
if ((crcpos > crcstart) && (buf[crcpos] == 0))
|
|
buf[crcpos] = ComputeCRC(&(buf[crcstart]), len - crcstart, 8);
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_ROHC_Feedback_opt(unsigned char *buf,
|
|
const OPTIONAL < Feedback > &feedback,
|
|
BOOLEAN const &large_cid)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!feedback.ispresent())
|
|
{
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
for (int num = 0; num < feedback().size_of(); num++)
|
|
{
|
|
len += Set_feedback(&buf[len], feedback()[num], large_cid);
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
|
|
/* Inserts CID infomation into the buffer by moving memory areas */
|
|
int
|
|
Set_CID_for_packets(unsigned char *buf, ROHC__config const &config,
|
|
int cid, int buflen)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (config.large__cid() == false)
|
|
{ /* Small CID: first octet is the CID */
|
|
if (cid > 0)
|
|
{
|
|
// Overlapping memory areas, use memmove
|
|
memmove(&(buf[1]), &(buf[0]), buflen);
|
|
buf[0] = 0xE0 + (cid & 0x0F);
|
|
len += 1;
|
|
}
|
|
}
|
|
else
|
|
{ /* Large CID: CID is placed after the first octet */
|
|
int cidlen = SDVL_encoded_CID_length(cid);
|
|
|
|
// Overlapping memory areas, use memmove
|
|
memmove(&(buf[1 + cidlen]), &(buf[1]), buflen - 1);
|
|
len += Set_SDVL_field(&(buf[1]), cid, 0);
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_ROHC_Header_Profile0(unsigned char *buf,
|
|
const Profile0__headers & hdr,
|
|
ROHC__config const &config)
|
|
{
|
|
int len = 0, crcpos = 0, cidlen, cid;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
switch (hdr.get_selection())
|
|
{
|
|
case Profile0__headers::ALT_ir:
|
|
{
|
|
cid = hdr.ir().cid();
|
|
Check_field_value("packet type", (int) *hdr.ir().type__ind(), 126);
|
|
buf[len] = ((*hdr.ir().type__ind()) << 1) & 0xFE;
|
|
buf[len] += (*hdr.ir().d()) & 0x01;
|
|
len += 1;
|
|
Check_field_value("profile", hdr.ir().profile(), 0);
|
|
len += Set_LIN1(&buf[len], hdr.ir().profile());
|
|
crcpos = len;
|
|
len += Set_LIN1(&buf[len], hdr.ir().crc());
|
|
len += Set_octetstring(&buf[len], hdr.ir().orig__packet());
|
|
break;
|
|
}
|
|
|
|
case Profile0__headers::ALT_normal:
|
|
{
|
|
cid = hdr.normal().cid();
|
|
len += Set_octetstring(&buf[len], hdr.normal().orig__packet());
|
|
break;
|
|
}
|
|
|
|
default:
|
|
Log_not_implemented_union_field("Profile0_headers", hdr.get_selection());
|
|
break;
|
|
}
|
|
|
|
cidlen = Set_CID_for_packets(buf, config, cid, len);
|
|
crcpos += cidlen;
|
|
len += cidlen;
|
|
|
|
if (hdr.get_selection() == Profile0__headers::ALT_ir && hdr.ir().crc() == 0)
|
|
{
|
|
buf[crcpos] = ComputeCRC(&(buf[0]), crcpos, 8);
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Static_Chain_Profile1(unsigned char *buf, const Static__Chain & chain)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
for (int num = 0; num < chain.size_of(); num++)
|
|
{
|
|
switch (chain[num].get_selection())
|
|
{
|
|
case Static__Chain__u::ALT_ipv4__stat:
|
|
len += Set_IPv4_static_chain(&buf[len], chain[num].ipv4__stat());
|
|
break;
|
|
case Static__Chain__u::ALT_ipv6__stat:
|
|
len += Set_IPv6_static_chain(&buf[len], chain[num].ipv6__stat());
|
|
break;
|
|
case Static__Chain__u::ALT_udp__stat:
|
|
len += Set_UDP_static_chain(&buf[len], chain[num].udp__stat());
|
|
break;
|
|
case Static__Chain__u::ALT_rtp__stat:
|
|
len += Set_RTP_static_chain(&buf[len], chain[num].rtp__stat());
|
|
break;
|
|
default:
|
|
Log_not_implemented_union_field
|
|
("Static_Chain_u", chain[num].get_selection());
|
|
break;
|
|
}
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Dynamic_Chain_Profile1(unsigned char *buf, const Dynamic__Chain & dynch)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
for (int num = 0; num < dynch.size_of(); num++)
|
|
{
|
|
switch (dynch[num].get_selection())
|
|
{
|
|
case Dynamic__Chain__u::ALT_ipv4__dyn:
|
|
len += Set_IPv4_dynamic_chain(&buf[len], dynch[num].ipv4__dyn());
|
|
break;
|
|
case Dynamic__Chain__u::ALT_ipv6__dyn:
|
|
len += Set_IPv6_dynamic_chain(&buf[len], dynch[num].ipv6__dyn());
|
|
break;
|
|
case Dynamic__Chain__u::ALT_udp__dyn:
|
|
len += Set_LIN2_BO_LAST(&buf[len], dynch[num].udp__dyn().cksum());
|
|
break;
|
|
case Dynamic__Chain__u::ALT_rtp__dyn:
|
|
len += Set_RTP_dynamic_chain(&buf[len], dynch[num].rtp__dyn());
|
|
break;
|
|
default:
|
|
Log_not_implemented_union_field
|
|
("Dynamic_Chain_u", dynch[num].get_selection());
|
|
break;
|
|
}
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_ir(unsigned char *buf,
|
|
const Profile1__IR__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 126);
|
|
buf[len] = ((*hdr.type__ind()) << 1) & 0xFE;
|
|
Check_field_presence("dynamic chain", *hdr.d() == 1,
|
|
hdr.dyn__chain().ispresent());
|
|
buf[len] += ShiftUpBit(*hdr.d(), 0);
|
|
len += 1;
|
|
Check_field_value("profile", hdr.profile(), 1);
|
|
len += Set_LIN1(&buf[len], hdr.profile());
|
|
len += Set_LIN1(&buf[len], hdr.crc());
|
|
len += Set_Static_Chain_Profile1(&buf[len], hdr.stat__chain());
|
|
if (hdr.dyn__chain().ispresent())
|
|
len += Set_Dynamic_Chain_Profile1(&buf[len], hdr.dyn__chain());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_irdyn(unsigned char *buf,
|
|
const Profile1__IR__DYN__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 248);
|
|
buf[len] = *hdr.type__ind();
|
|
len += 1;
|
|
Check_field_value("profile", hdr.profile(), 1);
|
|
len += Set_LIN1(&buf[len], hdr.profile());
|
|
len += Set_LIN1(&buf[len], hdr.crc());
|
|
len += Set_Dynamic_Chain_Profile1(&buf[len], hdr.dyn__chain());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_r0(unsigned char *buf,
|
|
const Profile1__R__0__header & hdr)
|
|
{
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 0);
|
|
buf[0] = ((*hdr.type__ind()) << 6) & 0xC0;
|
|
buf[0] += hdr.sn() & 0x3F;
|
|
|
|
Log_hexdump(buf, 1);
|
|
Log_function_name_on_leave();
|
|
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_r0crc(unsigned char *buf,
|
|
const Profile1__R__0__CRC__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 1);
|
|
buf[len] = ((*hdr.type__ind()) << 6) & 0xC0;
|
|
buf[len] += (hdr.sn() >> 1) & 0x3F;
|
|
len += 1;
|
|
buf[len] = (hdr.sn() << 7) & 0x80;
|
|
buf[len] += hdr.crc() & 0x7F;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_uo0(unsigned char *buf,
|
|
const Profile1__UO__0__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 0);
|
|
buf[len] = ((*hdr.type__ind()) << 7) & 0x80;
|
|
buf[len] += (hdr.sn() << 3) & 0x78;
|
|
buf[len] += hdr.crc() & 0x07;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_r1(unsigned char *buf,
|
|
const Profile1__R__1__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 2);
|
|
buf[len] = ((*hdr.type__ind()) << 6) & 0xC0;
|
|
buf[len] += hdr.sn() & 0x3F;
|
|
len += 1;
|
|
buf[len] = ShiftUpBit(*hdr.m__bit(), 7);
|
|
buf[len] += ShiftUpBit(*hdr.x__bit(), 6);
|
|
buf[len] += hdr.ts() & 0x3F;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_r1id(unsigned char *buf,
|
|
const Profile1__R__1__ID__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 2);
|
|
buf[len] = ((*hdr.type__ind()) << 6) & 0xC0;
|
|
buf[len] += hdr.sn() & 0x3F;
|
|
len += 1;
|
|
buf[len] = ShiftUpBit(*hdr.m__bit(), 7);
|
|
buf[len] += ShiftUpBit(*hdr.x__bit(), 6);
|
|
Check_field_value("T-bit", (int) *hdr.t__bit(), 0);
|
|
buf[len] += ShiftUpBit(*hdr.t__bit(), 5);
|
|
buf[len] += hdr.ip__id() & 0x1F;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_r1ts(unsigned char *buf,
|
|
const Profile1__R__1__TS__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 2);
|
|
buf[len] = ((*hdr.type__ind()) << 6) & 0xC0;
|
|
buf[len] += hdr.sn() & 0x3F;
|
|
len += 1;
|
|
buf[len] = ShiftUpBit(*hdr.m__bit(), 7);
|
|
buf[len] += ShiftUpBit(*hdr.x__bit(), 6);
|
|
Check_field_value("T-bit", (int) *hdr.t__bit(), 1);
|
|
buf[len] += ShiftUpBit(*hdr.t__bit(), 5);
|
|
buf[len] += hdr.ts() & 0x1F;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_uo1(unsigned char *buf,
|
|
const Profile1__UO__1__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 2);
|
|
buf[len] = ((*hdr.type__ind()) << 6) & 0xC0;
|
|
buf[len] += hdr.ts() & 0x3F;
|
|
len += 1;
|
|
buf[len] = ShiftUpBit(*hdr.m__bit(), 7);
|
|
buf[len] += (hdr.sn() << 3) & 0x78;
|
|
buf[len] += hdr.crc() & 0x07;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_uo1id(unsigned char *buf,
|
|
const Profile1__UO__1__ID__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 2);
|
|
buf[len] = ((*hdr.type__ind()) << 6) & 0xC0;
|
|
Check_field_value("T-bit", (int) *hdr.t__bit(), 0);
|
|
buf[len] += ShiftUpBit(*hdr.t__bit(), 5);
|
|
buf[len] += hdr.ip__id() & 0x1F;
|
|
len += 1;
|
|
buf[len] = ShiftUpBit(*hdr.x__bit(), 7);
|
|
buf[len] += (hdr.sn() << 3) & 0x78;
|
|
buf[len] += hdr.crc() & 0x07;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_uo1ts(unsigned char *buf,
|
|
const Profile1__UO__1__TS__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 2);
|
|
buf[len] = ((*hdr.type__ind()) << 6) & 0xC0;
|
|
Check_field_value("T-bit", (int) *hdr.t__bit(), 1);
|
|
buf[len] += ShiftUpBit(*hdr.t__bit(), 5);
|
|
buf[len] += hdr.ts() & 0x1F;
|
|
len += 1;
|
|
buf[len] = ShiftUpBit(*hdr.m__bit(), 7);
|
|
buf[len] += (hdr.sn() << 3) & 0x78;
|
|
buf[len] += hdr.crc() & 0x07;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_uor2(unsigned char *buf,
|
|
const Profile1__UOR__2__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 6);
|
|
buf[len] = ((*hdr.type__ind()) << 5) & 0xE0;
|
|
buf[len] += (hdr.ts() >> 1) & 0x1F;
|
|
len += 1;
|
|
buf[len] = (hdr.ts() << 7) & 0x80;
|
|
buf[len] += ShiftUpBit(*hdr.m__bit(), 6);
|
|
buf[len] += hdr.sn() & 0x3F;
|
|
len += 1;
|
|
buf[len] = ShiftUpBit(*hdr.x__bit(), 7);
|
|
buf[len] += hdr.crc() & 0x7F;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_uor2id(unsigned char *buf,
|
|
const Profile1__UOR__2__ID__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 6);
|
|
buf[len] = ((*hdr.type__ind()) << 5) & 0xE0;
|
|
buf[len] += hdr.ip__id() & 0x1F;
|
|
len += 1;
|
|
Check_field_value("T-bit", (int) *hdr.t__bit(), 0);
|
|
buf[len] = ShiftUpBit(*hdr.t__bit(), 7);
|
|
buf[len] += ShiftUpBit(*hdr.m__bit(), 6);
|
|
buf[len] += hdr.sn() & 0x3F;
|
|
len += 1;
|
|
buf[len] = ShiftUpBit(*hdr.x__bit(), 7);
|
|
buf[len] += hdr.crc() & 0x7F;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_uor2ts(unsigned char *buf,
|
|
const Profile1__UOR__2__TS__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 6);
|
|
Log_hexdump(buf, len);
|
|
buf[len] = ((*hdr.type__ind()) << 5) & 0xE0;
|
|
buf[len] += hdr.ts() & 0x1F;
|
|
len += 1;
|
|
Check_field_value("T-bit", (int) *hdr.t__bit(), 1);
|
|
buf[len] = ShiftUpBit(*hdr.t__bit(), 7);
|
|
buf[len] += ShiftUpBit(*hdr.m__bit(), 6);
|
|
buf[len] += hdr.sn() & 0x3F;
|
|
len += 1;
|
|
buf[len] = ShiftUpBit(*hdr.x__bit(), 7);
|
|
buf[len] += hdr.crc() & 0x7F;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_Inner_IP_flags_opt(unsigned char *buf,
|
|
const OPTIONAL < Inner__IP__flags > &field)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!field.ispresent())
|
|
{
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
buf[len] = ShiftUpBit(*field().tos(), 7);
|
|
buf[len] += ShiftUpBit(*field().ttl(), 6);
|
|
buf[len] += ShiftUpBit(*field().df(), 5);
|
|
buf[len] += ShiftUpBit(*field().pr(), 4);
|
|
buf[len] += ShiftUpBit(*field().ipx(), 3);
|
|
buf[len] += ShiftUpBit(*field().nbo(), 2);
|
|
buf[len] += ShiftUpBit(*field().rnd__bit(), 1);
|
|
buf[len] += ShiftUpBit(*field().ip2__bit(), 0);
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_Outer_IP_flags_opt(unsigned char *buf,
|
|
const OPTIONAL < Outer__IP__flags > &field)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!field.ispresent())
|
|
{
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
buf[len] = ShiftUpBit(*field().tos2(), 7);
|
|
buf[len] += ShiftUpBit(*field().ttl2(), 6);
|
|
buf[len] += ShiftUpBit(*field().df2(), 5);
|
|
buf[len] += ShiftUpBit(*field().pr2(), 4);
|
|
buf[len] += ShiftUpBit(*field().ipx2(), 3);
|
|
buf[len] += ShiftUpBit(*field().nbo2(), 2);
|
|
buf[len] += ShiftUpBit(*field().rnd2(), 1);
|
|
buf[len] += ShiftUpBit(*field().i2__bit(), 0);
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ipx_headers_opt(unsigned char *buf,
|
|
const OPTIONAL < IP__Ext__heads > &field)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!field.ispresent())
|
|
{
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
buf[len] = ShiftUpBit(*field().cl(), 7);
|
|
buf[len] += ShiftUpBit(*field().aseq(), 6);
|
|
buf[len] += ShiftUpBit(*field().eseq(), 5);
|
|
buf[len] += ShiftUpBit(*field().gseq(), 4);
|
|
buf[len] += (*field().res()) & 0x0F;
|
|
len += 1;
|
|
|
|
Check_field_presence("AH SN", *field().aseq() == 1,
|
|
field().ah__seq().ispresent());
|
|
Check_field_presence("ESP SN", *field().eseq() == 1,
|
|
field().esp__seq().ispresent());
|
|
Check_field_presence("GRE SN", *field().gseq() == 1,
|
|
field().gre__seq().ispresent());
|
|
Check_field_presence("Compressed header list", *field().cl() == 1,
|
|
field().compr__head__list().ispresent());
|
|
len += Set_AEGSeqnum_opt(&buf[len], field().ah__seq());
|
|
len += Set_AEGSeqnum_opt(&buf[len], field().esp__seq());
|
|
len += Set_AEGSeqnum_opt(&buf[len], field().gre__seq());
|
|
len += Set_Compr_head_list_opt(&buf[len], field().compr__head__list());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_Inner_IP_fields_opt(unsigned char *buf,
|
|
const OPTIONAL < Inner__IP__flags > &flags,
|
|
const OPTIONAL < Inner__IP__fields > &field)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!field.ispresent())
|
|
{
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
Check_field_presence("TOS (inner IP)",
|
|
flags.ispresent() && (*flags().tos() == 1),
|
|
field().tos().ispresent());
|
|
len += Set_LIN1_opt(&buf[len], field().tos());
|
|
Check_field_presence("TTL (inner IP)",
|
|
flags.ispresent() && (*flags().ttl() == 1),
|
|
field().ttl().ispresent());
|
|
len += Set_LIN1_opt(&buf[len], field().ttl());
|
|
Check_field_presence("PROTO (inner IP)",
|
|
flags.ispresent() && (*flags().pr() == 1),
|
|
field().proto().ispresent());
|
|
len += Set_LIN1_opt(&buf[len], field().proto());
|
|
|
|
Check_field_presence("IP extension headers (inner IP)",
|
|
flags.ispresent() && (*flags().ipx() == 1),
|
|
field().ext__heads().ispresent());
|
|
len += Set_Profile1_ipx_headers_opt(&buf[len], field().ext__heads());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_Outer_IP_fields_opt(unsigned char *buf,
|
|
const OPTIONAL < Outer__IP__flags > &flags,
|
|
const OPTIONAL < Outer__IP__fields > &field)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (!field.ispresent())
|
|
{
|
|
Log_function_name_on_leave();
|
|
return len;
|
|
}
|
|
Check_field_presence("TOS (outer IP)",
|
|
flags.ispresent() && (*flags().tos2() == 1),
|
|
field().tos().ispresent());
|
|
len += Set_LIN1_opt(&buf[len], field().tos());
|
|
Check_field_presence("TTL (outer IP)",
|
|
flags.ispresent() && (*flags().ttl2() == 1),
|
|
field().ttl().ispresent());
|
|
len += Set_LIN1_opt(&buf[len], field().ttl());
|
|
Check_field_presence("PROTO (outer IP)",
|
|
flags.ispresent() && (*flags().pr2() == 1),
|
|
field().proto().ispresent());
|
|
len += Set_LIN1_opt(&buf[len], field().proto());
|
|
|
|
Check_field_presence("IP extension headers (outer IP)",
|
|
flags.ispresent() && (*flags().ipx2() == 1),
|
|
field().ext__heads().ispresent());
|
|
len += Set_Profile1_ipx_headers_opt(&buf[len], field().ext__heads());
|
|
Check_field_presence("IP-ID (outer IP)",
|
|
flags.ispresent() && (*flags().i2__bit() == 1),
|
|
field().ip__id().ispresent());
|
|
len += Set_LIN2_BO_LAST_opt(&buf[len], field().ip__id());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_Extension0(unsigned char *buf, const Extension0 & ext)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("extension type", (int) *ext.ext__type(), 0);
|
|
buf[len] = ((*ext.ext__type()) << 6) & 0xC0;
|
|
buf[len] += (ext.sn() << 3) & 0x38;
|
|
buf[len] += ext.plust() & 0x07;
|
|
len += 1;
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_Extension1(unsigned char *buf, const Extension1 & ext)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("extension type", (int) *ext.ext__type(), 1);
|
|
buf[len] = ((*ext.ext__type()) << 6) & 0xC0;
|
|
buf[len] += (ext.sn() << 3) & 0x38;
|
|
buf[len] += ext.plust() & 0x07;
|
|
len += 1;
|
|
len += Set_LIN1(&buf[len], ext.minust());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_Extension2(unsigned char *buf, const Extension2 & ext)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("extension type", (int) *ext.ext__type(), 2);
|
|
buf[len] = ((*ext.ext__type()) << 6) & 0xC0;
|
|
buf[len] += (ext.sn() << 3) & 0x38;
|
|
buf[len] += (ext.plust() >> 8) & 0x07;
|
|
len += 1;
|
|
buf[len] = ext.plust() & 0xFF;
|
|
len += 1;
|
|
len += Set_LIN1(&buf[len], ext.minust());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_Extension3(unsigned char *buf, const Extension3 & ext)
|
|
{
|
|
int len = 0;
|
|
int ts_length = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("extension type", (int) *ext.ext__type(), 3);
|
|
buf[len] = ((*ext.ext__type()) << 6) & 0xC0;
|
|
buf[len] += ShiftUpBit(*ext.s__bit(), 5);
|
|
buf[len] += ShiftUpBit(*ext.r__ts__bit(), 4);
|
|
buf[len] += ShiftUpBit(*ext.tsc__bit(), 3);
|
|
buf[len] += ShiftUpBit(*ext.i__bit(), 2);
|
|
buf[len] += ShiftUpBit(*ext.ip__bit(), 1);
|
|
buf[len] += ShiftUpBit(*ext.rtp__bit(), 0);
|
|
len += 1;
|
|
|
|
Check_field_presence("Inner IP flags",
|
|
*ext.ip__bit() == 1,
|
|
ext.inner__ip__flags().ispresent());
|
|
len += Set_Profile1_Inner_IP_flags_opt(&buf[len], ext.inner__ip__flags());
|
|
Check_field_presence("Outer IP flags",
|
|
ext.inner__ip__flags().ispresent() &&
|
|
(*ext.inner__ip__flags()().ip2__bit() == 1),
|
|
ext.outer__ip__flags().ispresent());
|
|
len += Set_Profile1_Outer_IP_flags_opt(&buf[len], ext.outer__ip__flags());
|
|
Check_field_presence("SN", *ext.s__bit() == 1, ext.sn().ispresent());
|
|
len += Set_LIN1_opt(&buf[len], ext.sn());
|
|
Check_field_presence("RTP TS", *ext.r__ts__bit() == 1, ext.ts().ispresent());
|
|
if (ext.ts__length().ispresent()) ts_length = ext.ts__length()();
|
|
len += Set_SDVL_field_opt(&buf[len], ext.ts(), ts_length);
|
|
Check_field_presence("Inner IP fields",
|
|
*ext.ip__bit() == 1, ext.inner__ip__hdr().ispresent());
|
|
len += Set_Profile1_Inner_IP_fields_opt(&buf[len], ext.inner__ip__flags(),
|
|
ext.inner__ip__hdr());
|
|
Check_field_presence("Inner IP-ID",
|
|
*ext.i__bit() == 1, ext.ip__id().ispresent());
|
|
len += Set_LIN2_BO_LAST_opt(&buf[len], ext.ip__id());
|
|
Check_field_presence("Outer IP fields",
|
|
ext.inner__ip__flags().ispresent() &&
|
|
(*ext.inner__ip__flags()().ip2__bit() == 1),
|
|
ext.outer__ip__hdr().ispresent());
|
|
len += Set_Profile1_Outer_IP_fields_opt(&buf[len], ext.outer__ip__flags(),
|
|
ext.outer__ip__hdr());
|
|
Check_field_presence("RTP flags and fields",
|
|
*ext.rtp__bit() == 1, ext.rtp__fl__fi().ispresent());
|
|
len += Set_RTP_flags_fields_opt(&buf[len], ext.rtp__fl__fi());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_Extension_opt(unsigned char *buf,
|
|
const OPTIONAL < Profile1__Extension >
|
|
&ext)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
if (ext.ispresent())
|
|
{
|
|
if (ext().get_selection() == Profile1__Extension::ALT_ext0)
|
|
{
|
|
len += Set_Profile1_ROHC_Header_Extension0(&buf[len], ext().ext0());
|
|
}
|
|
else if (ext().get_selection() == Profile1__Extension::ALT_ext1)
|
|
{
|
|
len += Set_Profile1_ROHC_Header_Extension1(&buf[len], ext().ext1());
|
|
}
|
|
else if (ext().get_selection() == Profile1__Extension::ALT_ext2)
|
|
{
|
|
len += Set_Profile1_ROHC_Header_Extension2(&buf[len], ext().ext2());
|
|
}
|
|
else if (ext().get_selection() == Profile1__Extension::ALT_ext3)
|
|
{
|
|
len += Set_Profile1_ROHC_Header_Extension3(&buf[len], ext().ext3());
|
|
}
|
|
else
|
|
{
|
|
Log_not_implemented_union_field("Profile1_Extension",
|
|
ext().get_selection());
|
|
}
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header_ipid_ah_gre(unsigned char *buf,
|
|
const Profile1__headers & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
len += Set_LIN2_BO_LAST_opt(&buf[len], hdr.ip__id__outer());
|
|
len += Set_octetstring_opt(&buf[len], hdr.ah__outer());
|
|
len += Set_LIN2_BO_LAST_opt(&buf[len], hdr.gre__cksum1());
|
|
len += Set_LIN2_BO_LAST_opt(&buf[len], hdr.ip__id__inner());
|
|
len += Set_octetstring_opt(&buf[len], hdr.ah__inner());
|
|
len += Set_LIN2_BO_LAST_opt(&buf[len], hdr.gre__cksum2());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile1_ROHC_Header(unsigned char *buf,
|
|
const Profile1__headers & hdr,
|
|
ROHC__config const &config)
|
|
{
|
|
int len = 0, crcpos = 0, cidlen = 0, cid;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
switch (hdr.base__header().get_selection())
|
|
{
|
|
case Profile1__base__header::ALT_ir:
|
|
cid = hdr.base__header().ir().cid();
|
|
crcpos = len + 2;
|
|
len += Set_Profile1_ROHC_Header_ir(&buf[len], hdr.base__header().ir());
|
|
break;
|
|
case Profile1__base__header::ALT_ir__dyn:
|
|
cid = hdr.base__header().ir__dyn().cid();
|
|
crcpos = len + 2;
|
|
len += Set_Profile1_ROHC_Header_irdyn(&buf[len],
|
|
hdr.base__header().ir__dyn());
|
|
break;
|
|
case Profile1__base__header::ALT_r__0:
|
|
cid = hdr.base__header().r__0().cid();
|
|
len += Set_Profile1_ROHC_Header_r0(&buf[len], hdr.base__header().r__0());
|
|
break;
|
|
case Profile1__base__header::ALT_r__0__crc:
|
|
cid = hdr.base__header().r__0__crc().cid();
|
|
len += Set_Profile1_ROHC_Header_r0crc(&buf[len],
|
|
hdr.base__header().r__0__crc());
|
|
break;
|
|
case Profile1__base__header::ALT_uo__0:
|
|
cid = hdr.base__header().uo__0().cid();
|
|
len += Set_Profile1_ROHC_Header_uo0(&buf[len], hdr.base__header().uo__0());
|
|
break;
|
|
case Profile1__base__header::ALT_r__1:
|
|
cid = hdr.base__header().r__1().cid();
|
|
len += Set_Profile1_ROHC_Header_r1(&buf[len], hdr.base__header().r__1());
|
|
break;
|
|
case Profile1__base__header::ALT_r__1__id:
|
|
cid = hdr.base__header().r__1__id().cid();
|
|
len +=
|
|
Set_Profile1_ROHC_Header_r1id(&buf[len], hdr.base__header().r__1__id());
|
|
break;
|
|
case Profile1__base__header::ALT_r__1__ts:
|
|
cid = hdr.base__header().r__1__ts().cid();
|
|
len +=
|
|
Set_Profile1_ROHC_Header_r1ts(&buf[len], hdr.base__header().r__1__ts());
|
|
break;
|
|
case Profile1__base__header::ALT_uo__1:
|
|
cid = hdr.base__header().uo__1().cid();
|
|
len += Set_Profile1_ROHC_Header_uo1(&buf[len], hdr.base__header().uo__1());
|
|
break;
|
|
case Profile1__base__header::ALT_uo__1__id:
|
|
cid = hdr.base__header().uo__1__id().cid();
|
|
len +=
|
|
Set_Profile1_ROHC_Header_uo1id(&buf[len],
|
|
hdr.base__header().uo__1__id());
|
|
break;
|
|
case Profile1__base__header::ALT_uo__1__ts:
|
|
cid = hdr.base__header().uo__1__ts().cid();
|
|
len +=
|
|
Set_Profile1_ROHC_Header_uo1ts(&buf[len],
|
|
hdr.base__header().uo__1__ts());
|
|
break;
|
|
case Profile1__base__header::ALT_uor__2:
|
|
cid = hdr.base__header().uor__2().cid();
|
|
len +=
|
|
Set_Profile1_ROHC_Header_uor2(&buf[len], hdr.base__header().uor__2());
|
|
break;
|
|
case Profile1__base__header::ALT_uor__2__id:
|
|
cid = hdr.base__header().uor__2__id().cid();
|
|
len +=
|
|
Set_Profile1_ROHC_Header_uor2id(&buf[len],
|
|
hdr.base__header().uor__2__id());
|
|
break;
|
|
case Profile1__base__header::ALT_uor__2__ts:
|
|
cid = hdr.base__header().uor__2__ts().cid();
|
|
len +=
|
|
Set_Profile1_ROHC_Header_uor2ts(&buf[len],
|
|
hdr.base__header().uor__2__ts());
|
|
break;
|
|
default:
|
|
Log_not_implemented_union_field
|
|
("Profile1_base_header", hdr.base__header().get_selection());
|
|
break;
|
|
}
|
|
|
|
len += Set_Profile1_ROHC_Header_Extension_opt(&buf[len], hdr.ext());
|
|
len += Set_Profile1_ROHC_Header_ipid_ah_gre(&buf[len], hdr);
|
|
len += Set_LIN2_BO_LAST_opt(&buf[len], hdr.udp__cksum());
|
|
|
|
cidlen = Set_CID_for_packets(buf, config, cid, len);
|
|
crcpos += cidlen;
|
|
len += cidlen;
|
|
|
|
if (hdr.base__header().get_selection() == Profile1__base__header::ALT_ir
|
|
&& hdr.base__header().ir().crc() == 0)
|
|
buf[crcpos] = ComputeCRC(&(buf[0]), len, 8);
|
|
else if (hdr.base__header().get_selection() ==
|
|
Profile1__base__header::ALT_ir__dyn
|
|
&& hdr.base__header().ir__dyn().crc() == 0)
|
|
buf[crcpos] = ComputeCRC(&(buf[0]), len, 8);
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile2_Static_Chain(unsigned char
|
|
*buf, const Profile2__Static__Chain & chain)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
for (int num = 0; num < chain.size_of(); num++)
|
|
{
|
|
switch (chain[num].get_selection())
|
|
{
|
|
case Static__Chain__u::ALT_ipv4__stat:
|
|
len += Set_IPv4_static_chain(&buf[len], chain[num].ipv4__stat());
|
|
break;
|
|
case Static__Chain__u::ALT_ipv6__stat:
|
|
len += Set_IPv6_static_chain(&buf[len], chain[num].ipv6__stat());
|
|
break;
|
|
case Static__Chain__u::ALT_udp__stat:
|
|
len += Set_UDP_static_chain(&buf[len], chain[num].udp__stat());
|
|
break;
|
|
default:
|
|
Log_not_implemented_union_field
|
|
("Profile2_Static_Chain", chain[num].get_selection());
|
|
break;
|
|
}
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile2_Dynamic_Chain(unsigned char
|
|
*buf, const Profile2__Dynamic__Chain & dynch)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
for (int num = 0; num < dynch.size_of(); num++)
|
|
{
|
|
switch (dynch[num].get_selection())
|
|
{
|
|
case Profile2__Dynamic__Chain__u::ALT_ipv4__dyn:
|
|
len += Set_IPv4_dynamic_chain(&buf[len], dynch[num].ipv4__dyn());
|
|
break;
|
|
case Profile2__Dynamic__Chain__u::ALT_ipv6__dyn:
|
|
len += Set_IPv6_dynamic_chain(&buf[len], dynch[num].ipv6__dyn());
|
|
break;
|
|
case Profile2__Dynamic__Chain__u::ALT_udp__dyn:
|
|
len += Set_LIN2_BO_LAST(&buf[len], dynch[num].udp__dyn().cksum());
|
|
len += Set_LIN2_BO_LAST(&buf[len], dynch[num].udp__dyn().udp__sn());
|
|
break;
|
|
default:
|
|
Log_not_implemented_union_field
|
|
("Profile2_Dynamic_Chain", dynch[num].get_selection());
|
|
break;
|
|
}
|
|
}
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile2_ROHC_Header_ir(unsigned char
|
|
*buf, const Profile2__IR__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 126);
|
|
buf[len] = ((*hdr.type__ind()) << 1) & 0xFE;
|
|
Check_field_presence("dynamic chain", *hdr.d() == 1,
|
|
hdr.dyn__chain().ispresent());
|
|
buf[len] += ShiftUpBit(*hdr.d(), 0);
|
|
len += 1;
|
|
Check_field_value("profile", hdr.profile(), 2);
|
|
len += Set_LIN1(&buf[len], hdr.profile());
|
|
len += Set_LIN1(&buf[len], hdr.crc());
|
|
len += Set_Profile2_Static_Chain(&buf[len], hdr.stat__chain());
|
|
if (hdr.dyn__chain().ispresent())
|
|
len += Set_Profile2_Dynamic_Chain(&buf[len], hdr.dyn__chain());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile2_ROHC_Header_irdyn(unsigned
|
|
char *buf,
|
|
const Profile2__IR__DYN__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 248);
|
|
buf[len] = *hdr.type__ind();
|
|
len += 1;
|
|
Check_field_value("profile", hdr.profile(), 2);
|
|
len += Set_LIN1(&buf[len], hdr.profile());
|
|
len += Set_LIN1(&buf[len], hdr.crc());
|
|
len += Set_Profile2_Dynamic_Chain(&buf[len], hdr.dyn__chain());
|
|
|
|
Log_hexdump(buf, len);
|
|
Log_function_name_on_leave();
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
Set_Profile2_ROHC_Header_r1(unsigned char
|
|
*buf, const Profile2__R__1__header & hdr)
|
|
{
|
|
int len = 0;
|
|
|
|
Log_function_name_on_enter();
|
|
|
|
Check_field_value("packet type", (int) *hdr.type__ind(), 2);
|
|
buf[len] = ((*hdr.type__ind()) << 6) & 0xC0;
|
|
buf[len] += hdr.sn() & 0x3F;
|
|
len += 1;
|
|
buf[len] = ShiftUpBit(*hdr.x__bit(), 7);
|
|
buf[len] += hdr.ip__id() & 0x7F;
|
|
len += 1;
|
|
|