319 lines
10 KiB
C++
319 lines
10 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Copyright Test Competence Center (TCC) ETH 2008 //
|
|
// //
|
|
// 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: LLC_EncDec.cc
|
|
// Rev: R1A0
|
|
// Prodnr: CNL 113 577
|
|
// Updated: 2008-01-22
|
|
// Contact: http://ttcn.ericsson.se
|
|
// Reference: 3GPP TS 44.064 7.1.0
|
|
|
|
#include "LLC_Types.hh"
|
|
#include <string.h>
|
|
|
|
// GIVEN IN CODE RECEIVED FROM ERV
|
|
#define CRC_POLY_LLC2 0xad85dd
|
|
|
|
// GIVEN IN SPECIFICATION
|
|
//#define CRC_POLY_LLC2 0xbba1b5
|
|
|
|
#define TABLE_LENGTH 256
|
|
|
|
// For UI frames if PM bit is 0 (unprotected) then CRC will be calculated over Header + N202 octets
|
|
#define N202 4
|
|
|
|
unsigned int mCRCTable[TABLE_LENGTH];
|
|
|
|
|
|
static void BuildCrc24Table()
|
|
{
|
|
unsigned int i,j;
|
|
unsigned int reg;
|
|
|
|
//TRACE_FUNC( "BuildCrc24Table" );
|
|
|
|
for( i = 0; i < TABLE_LENGTH; i++ )
|
|
{
|
|
reg = i;
|
|
for( j = 8; j > 0; j-- )
|
|
{
|
|
if( reg & 1 )
|
|
{
|
|
|
|
reg = (reg>>1) ^ (unsigned int) CRC_POLY_LLC2;
|
|
}
|
|
else
|
|
{
|
|
reg >>= 1;
|
|
}
|
|
}
|
|
reg &= 0x00ffffffL;
|
|
|
|
mCRCTable[i] = (unsigned int)reg;
|
|
//TTCN_Logger::begin_event(TTCN_DEBUG);
|
|
|
|
//TTCN_Logger::log_event("mCRCTable[%d]= %d",i,mCRCTable[i]);
|
|
|
|
// TTCN_Logger::end_event();
|
|
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------
|
|
|
|
unsigned int Calculate_CRC(TTCN_Buffer& pdu)
|
|
{
|
|
|
|
const unsigned char* loc_pdu = pdu.get_data();
|
|
|
|
//TTCN_Logger::begin_event(TTCN_DEBUG);
|
|
|
|
//for (size_t i =0; i< pdu.get_len();i++)
|
|
// {
|
|
// TTCN_Logger::log_event("%02x ",loc_pdu[i]);
|
|
// }
|
|
|
|
//TTCN_Logger::log_event("\n");
|
|
|
|
//TTCN_Logger::end_event();
|
|
|
|
BuildCrc24Table();
|
|
|
|
//TTCN_Logger::begin_event(TTCN_DEBUG);
|
|
//TTCN_Logger::log_event("mCRCTable[%d]= %d\n",255,mCRCTable[255]);
|
|
//TTCN_Logger::log_event("mCRCTable[%d]= 0x%08x (%u)",255,mCRCTable[255]);
|
|
//TTCN_Logger::log_event("\n");
|
|
//TTCN_Logger::end_event();
|
|
|
|
unsigned int reg = 0xFFFFFF;
|
|
|
|
unsigned int length = pdu.get_len();
|
|
|
|
|
|
|
|
if ( ((loc_pdu[1] >>5) & 0x07) == 0x06 ) //UI frame
|
|
{
|
|
if ((loc_pdu[2] & 0x01) == 0x00) // PM bit is 0 (unprotected)
|
|
{
|
|
if(length > 3 + N202) // pdu length is longer than header + N202
|
|
{
|
|
length = 3 + N202; // length = header length + N202
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
while ( length--)
|
|
{
|
|
reg =
|
|
((reg>>8) & 0x00ffff)^mCRCTable[(reg^*((unsigned char*)loc_pdu++)) & 0xffL];
|
|
}
|
|
//TTCN_Logger::log(TTCN_DEBUG, "reg:%08x\n",reg);
|
|
// 1's complement of FCS
|
|
reg ^= 0xffffffL;
|
|
|
|
reg = ((reg >> 16) & 0x000000ff)+ ((reg) & 0x0000ff00) + ((reg <<16 )& 0x00ff0000);
|
|
//unsigned int tempint = *(unsigned int*)loc_crcBuffer;
|
|
//reg = (unsigned int*)loc_crcBuffer ;
|
|
//TTCN_Logger::log(TTCN_DEBUG, "reg:%08x\n",reg);
|
|
|
|
return reg & 0x00ffffffL;
|
|
}
|
|
//---------------------------------------------------------------------------------------
|
|
|
|
namespace LLC__Types {
|
|
|
|
OCTETSTRING enc__PDU__LLC(const PDU__LLC& pdu)
|
|
{
|
|
TTCN_Buffer bb;
|
|
PDU__LLC pdu2(pdu);
|
|
|
|
if (pdu2.get_selection() == PDU__LLC::ALT_pDU__LLC__U)
|
|
{
|
|
|
|
if (pdu2.pDU__LLC__U().information__field__U().get_selection() == Information__field__U::ALT_uA)
|
|
{int record_of_size = pdu2.pDU__LLC__U().information__field__U().uA().size_of();
|
|
|
|
for (int i = 0; i < (record_of_size) ; i++)
|
|
{
|
|
// AUTOMATICALLY CALCULATE WHICH LENGTH FORMAT SHOULD BE USED AND CHANGE SHORT LENGTH FORM
|
|
// TO LONG LENGTH FORM IF NECESSARY WHEN L3 PDU IS INCLUDED
|
|
if ( pdu2.pDU__LLC__U().information__field__U().uA()[i].typefield() == int2bit(11,5) )
|
|
{
|
|
if( pdu2.pDU__LLC__U().information__field__U().uA()[i].xID__Data().l3param().lengthof() > 3)
|
|
{
|
|
pdu2.pDU__LLC__U().information__field__U().uA()[i].xID__length().long__len() =
|
|
pdu2.pDU__LLC__U().information__field__U().uA()[i].xID__Data().l3param().lengthof();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pdu2.pDU__LLC__U().information__field__U().get_selection() == Information__field__U::ALT_sABM)
|
|
{int record_of_size = pdu2.pDU__LLC__U().information__field__U().sABM().size_of();
|
|
|
|
for (int i = 0; i < (record_of_size) ; i++)
|
|
{
|
|
// AUTOMATICALLY CALCULATE WHICH LENGTH FORMAT SHOULD BE USED AND CHANGE SHORT LENGTH FORM
|
|
// TO LONG LENGTH FORM IF NECESSARY WHEN L3 PDU IS INCLUDED
|
|
if ( pdu2.pDU__LLC__U().information__field__U().sABM()[i].typefield() == int2bit(11,5) )
|
|
{
|
|
if( pdu2.pDU__LLC__U().information__field__U().sABM()[i].xID__Data().l3param().lengthof() > 3)
|
|
{
|
|
pdu2.pDU__LLC__U().information__field__U().sABM()[i].xID__length().long__len() =
|
|
pdu2.pDU__LLC__U().information__field__U().sABM()[i].xID__Data().l3param().lengthof();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pdu2.pDU__LLC__U().information__field__U().get_selection() == Information__field__U::ALT_xID)
|
|
{int record_of_size = pdu2.pDU__LLC__U().information__field__U().xID().size_of();
|
|
|
|
for (int i = 0; i < (record_of_size) ; i++)
|
|
{
|
|
// AUTOMATICALLY CALCULATE WHICH LENGTH FORMAT SHOULD BE USED AND CHANGE SHORT LENGTH FORM
|
|
// TO LONG LENGTH FORM IF NECESSARY WHEN L3 PDU IS INCLUDED
|
|
if ( pdu2.pDU__LLC__U().information__field__U().xID()[i].typefield() == int2bit(11,5) )
|
|
{
|
|
if( pdu2.pDU__LLC__U().information__field__U().xID()[i].xID__Data().l3param().lengthof() > 3)
|
|
{
|
|
pdu2.pDU__LLC__U().information__field__U().xID()[i].xID__length().long__len() =
|
|
pdu2.pDU__LLC__U().information__field__U().xID()[i].xID__Data().l3param().lengthof();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (pdu2.get_selection() == PDU__LLC::ALT_pDU__LLC__U)
|
|
{
|
|
if ( pdu2.pDU__LLC__U().fCS().ispresent())
|
|
{
|
|
if ( pdu2.pDU__LLC__U().fCS() == int2oct(0,3) ) // IF ENCODER NEEDS TO GENERATE CRC
|
|
{
|
|
pdu2.pDU__LLC__U().fCS() = OMIT_VALUE;
|
|
pdu2.encode(PDU__LLC_descr_ ,bb, TTCN_EncDec::CT_RAW);
|
|
unsigned int crcBuffer = Calculate_CRC(bb);
|
|
bb.put_os(int2oct(crcBuffer,3));
|
|
return OCTETSTRING (bb.get_len(), bb.get_data());
|
|
|
|
}
|
|
|
|
else { // IF ENCODER SENDS OUT NONZERO CRC GIVEN IN TTCN TEMPLATE
|
|
pdu2.encode(PDU__LLC_descr_ ,bb, TTCN_EncDec::CT_RAW);
|
|
return OCTETSTRING (bb.get_len(), bb.get_data());
|
|
}
|
|
}
|
|
else { //FCS OMIT
|
|
pdu2.encode(PDU__LLC_descr_ ,bb, TTCN_EncDec::CT_RAW);
|
|
unsigned int crcBuffer = Calculate_CRC(bb);
|
|
bb.put_os(int2oct(crcBuffer,3));
|
|
return OCTETSTRING (bb.get_len(), bb.get_data());
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
else if (pdu2.get_selection() == PDU__LLC::ALT_pDU__LLC__UI)
|
|
{
|
|
if ( pdu2.pDU__LLC__UI().fCS().ispresent())
|
|
{
|
|
if ( pdu2.pDU__LLC__UI().fCS() == int2oct(0,3) ) // IF ENCODER NEEDS TO GENERATE CRC
|
|
{
|
|
pdu2.pDU__LLC__UI().fCS() = OMIT_VALUE;
|
|
pdu2.encode(PDU__LLC_descr_ ,bb, TTCN_EncDec::CT_RAW);
|
|
unsigned int crcBuffer = Calculate_CRC(bb);
|
|
bb.put_os(int2oct(crcBuffer,3));
|
|
return OCTETSTRING (bb.get_len(), bb.get_data());
|
|
|
|
}
|
|
|
|
else { // IF ENCODER SENDS OUT NONZERO CRC GIVEN IN TTCN TEMPLATE
|
|
pdu2.encode(PDU__LLC_descr_ ,bb, TTCN_EncDec::CT_RAW);
|
|
return OCTETSTRING (bb.get_len(), bb.get_data());
|
|
}
|
|
}
|
|
else { //FCS OMIT
|
|
pdu2.encode(PDU__LLC_descr_ ,bb, TTCN_EncDec::CT_RAW);
|
|
unsigned int crcBuffer = Calculate_CRC(bb);
|
|
bb.put_os(int2oct(crcBuffer,3));
|
|
return OCTETSTRING (bb.get_len(), bb.get_data());
|
|
}
|
|
}
|
|
else {TTCN_error("Can not encode LLC PDU"); //Neither UI NOR U
|
|
|
|
return OCTETSTRING (bb.get_len(), bb.get_data()); // this is dummy to avoid warning during compilation
|
|
}
|
|
//pdu2.encode(PDU__LLC_descr_ ,bb, TTCN_EncDec::CT_RAW);
|
|
//unsigned int crcBuffer = Calculate_CRC(bb);
|
|
|
|
//bb.put_os( int2oct(crcBuffer,3));
|
|
|
|
|
|
//return OCTETSTRING (bb.get_len(), bb.get_data());
|
|
|
|
}
|
|
|
|
|
|
OCTETSTRING enc__PDU__LLC(const PDU__LLC_template& pdu)
|
|
{
|
|
return enc__PDU__LLC(pdu.valueof());
|
|
}
|
|
|
|
|
|
PDU__LLC dec__PDU__LLC(const OCTETSTRING& stream)
|
|
{
|
|
PDU__LLC retv;
|
|
TTCN_Buffer bb;
|
|
OCTETSTRING crc = int2oct(0,3);
|
|
|
|
size_t datalength = stream.lengthof()-3;
|
|
const unsigned char * CRC_AS_RECEIVED = (const unsigned char *)stream+datalength;
|
|
bb.put_s(datalength,(const unsigned char *)stream);
|
|
|
|
unsigned int CRC_CALCULATED = Calculate_CRC(bb);
|
|
|
|
// COMPARE CRC RECEIVED IN LLC PDU WITH CRC CALCULATED FROM LLC PDU
|
|
if(
|
|
(CRC_AS_RECEIVED[ 0 ] != (CRC_CALCULATED & 0xff0000 ) >> 16) ||
|
|
(CRC_AS_RECEIVED[ 1 ] != (CRC_CALCULATED & 0xff00 ) >> 8) ||
|
|
(CRC_AS_RECEIVED[ 2 ] != (CRC_CALCULATED & 0xff ) )
|
|
)
|
|
{
|
|
TTCN_warning("CRC ERROR IN LLC PDU"); // CRC IS NOT AS EXPECTED
|
|
crc=OCTETSTRING(3,CRC_AS_RECEIVED);
|
|
}
|
|
// CRC IS
|
|
// FILL CRC octets with zeroes if CRC is OK
|
|
|
|
retv.decode(PDU__LLC_descr_, bb, TTCN_EncDec::CT_RAW);
|
|
|
|
if (retv.get_selection() == PDU__LLC::ALT_pDU__LLC__UI){
|
|
retv.pDU__LLC__UI().fCS() = crc;
|
|
}
|
|
|
|
if (retv.get_selection() == PDU__LLC::ALT_pDU__LLC__U){
|
|
retv.pDU__LLC__U().fCS() = crc;
|
|
}
|
|
|
|
|
|
return retv;
|
|
|
|
|
|
}
|
|
|
|
}//namespace
|