blob: 17bda7e43c330368b060cd91eaf04f25f71d94b5 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
// //
// Copyright (c) 2000-2019 Ericsson Telecom AB //
// //
// All rights reserved. This program and the accompanying materials //
// are made available under the terms of the Eclipse Public License v2.0 //
// which accompanies this distribution, and is available at //
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html //
// //
///////////////////////////////////////////////////////////////////////////////
#include <string.h>
#include <TTCN3.hh>
#include <netinet/in.h> // htons
//#include <arpa/inet.h> // inet_ntoa
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include "EPTF_CLL_TransportIPL2_Functions.hh"
#include "IP_Types.hh"
using namespace IP__Types;
namespace EPTF__CLL__TransportIPL2__Functions
{
INTEGER f__EPTF__TransportIPL2__tcpIsn(){
struct timeval tv;
gettimeofday(&tv, NULL);
unsigned long long tmp = 1000000 * (unsigned long long)tv.tv_sec + tv.tv_usec;
tmp >>= 2;
// tmp &= 0x0fffffff;
return INTEGER((int)tmp);
}
// and operation for integers
INTEGER f__EPTF__and4i(const INTEGER& i1, const INTEGER& i2)
{
return INTEGER((int)i1 & (int)i2);
}
// or operation for integers
INTEGER f__EPTF__or4i(const INTEGER& i1, const INTEGER& i2)
{
return INTEGER((int)i1 | (int)i2);
}
// xor operation for integers
INTEGER f__EPTF__xor4i(const INTEGER& i1, const INTEGER& i2)
{
return INTEGER((int)i1 ^ (int)i2);
}
// not operation for integers
INTEGER f__EPTF__not4i(const INTEGER& i)
{
return INTEGER(~(int)i);
}
// shift left operation for integers
INTEGER f__EPTF__intShiftLeft(const INTEGER& i, const INTEGER& bits)
{
return INTEGER((int)i << (int)bits);
}
// shift right operation for integers
INTEGER f__EPTF__intShiftRight(const INTEGER& i, const INTEGER& bits)
{
return INTEGER((int)i >> (int)bits);
}
INTEGER f__EPTF__mod32Add(const INTEGER& i1, const INTEGER& i2)
{
unsigned long l1 = (int)i1;
unsigned long l2 = (int)i2;
l1 += l2;
return INTEGER((int)l1);
}
INTEGER f__EPTF__mod32Sub(const INTEGER& i1, const INTEGER& i2)
{
unsigned long l1 = (int)i1;
unsigned long l2 = (int)i2;
l1 -= l2;
return INTEGER((int)l1);
}
BOOLEAN f__EPTF__mod32Less(const INTEGER& i1, const INTEGER& i2)
{
if(i1 == i2) return BOOLEAN(FALSE);
return f__EPTF__mod32LessOrEqual(i1, i2);
}
BOOLEAN f__EPTF__mod32LessOrEqual(const INTEGER& i1, const INTEGER& i2)
{
unsigned long l1 = (int)i1;
unsigned long l2 = (int)i2;
l2 -= l1;
return BOOLEAN(l2 <= 0x7FFFFFFF);
}
BOOLEAN f__EPTF__mod32Greater(const INTEGER& i1, const INTEGER& i2)
{
if(i1 == i2) return BOOLEAN(FALSE);
return f__EPTF__mod32GreaterOrEqual(i1, i2);
}
BOOLEAN f__EPTF__mod32GreaterOrEqual(const INTEGER& i1, const INTEGER& i2)
{
unsigned long l1 = (int)i1;
unsigned long l2 = (int)i2;
l1 -= l2;
return BOOLEAN(l1 <= 0x7FFFFFFF);
}
OCTETSTRING f__EPTF__TransportIPL2__insertOctets(
const OCTETSTRING &pl_buffer,
const OCTETSTRING &pl_fragment,
const INTEGER &pl_offset)
{
int len = (int)pl_offset + pl_fragment.lengthof();
int bufLen = pl_buffer.lengthof();
if(len < bufLen) len = bufLen;
unsigned char *buf = new unsigned char[len + 1];
memcpy(buf, (const unsigned char*)pl_buffer, pl_buffer.lengthof());
memcpy(buf + pl_offset, (const unsigned char*)pl_fragment, pl_fragment.lengthof());
OCTETSTRING retVal = OCTETSTRING(len, buf);
delete []buf;
return retVal;
}
CHARSTRING f__EPTF__TransportIPL2__ip2str(const OCTETSTRING& pl_ipAddr)
{
if(pl_ipAddr.lengthof() != 4) return CHARSTRING("");
char str[32];
const unsigned char *addr = pl_ipAddr;
char *p = str;
for(int i=0; i<4; i++) {
unsigned char tmp = *addr++;
bool gr100 = false;
if(tmp>=200) {
*p++ = '2';
tmp -= 200;
gr100 = true;
} else if(tmp>=100) {
*p++ = '1';
tmp -= 100;
gr100 = true;
}
if(tmp >= 10) {
*p = '0';
do { (*p)++; tmp -= 10; } while(tmp >= 10);
p++;
} else if(gr100) {
*p++ = '0';
}
*p++ = tmp + '0';
*p++= '.';
}
return CHARSTRING(p-str-1, str);
/* struct in_addr tmp;
const unsigned char *addr = pl_ipAddr;
tmp.s_addr = (addr[0]<<24) | (addr[1]<<16) | (addr[2]<<8) | addr[3];
return CHARSTRING(inet_ntoa(tmp));*/
}
OCTETSTRING f__EPTF__TransportIPL2__getHashKey4UDP(const OCTETSTRING &pl__locAddr, const INTEGER &pl__locPort)
{
static unsigned char buff[8];
if(pl__locAddr.lengthof() != 4) {
TTCN_error("f_EPTF_TransportIPL2_getHashKey4UDP: local address length is %d octet, expected 4.", pl__locAddr.lengthof());
return OCTETSTRING(0,NULL);
}
int tmp = (int)pl__locPort;
const unsigned char *addr = (const unsigned char *) pl__locAddr;
buff[0] = tmp;
buff[1] = addr[3];
buff[2] = tmp >> 8;
buff[3] = addr[2];
buff[4] = addr[1];
buff[5] = addr[0];
buff[6] = 1; // UDP
return OCTETSTRING(7, buff);
}
OCTETSTRING f__EPTF__TransportIPL2__getHashKey4TCP(
const OCTETSTRING &pl__locAddr,
const INTEGER &pl__locPort,
const OCTETSTRING &pl__remAddr,
const INTEGER &pl__remPort)
{
static unsigned char buff[16];
if(pl__locAddr.lengthof() != 4) {
TTCN_error("f_EPTF_TransportIPL2_getHashKey4UDP: local address length is %d octet, expected 4.", pl__locAddr.lengthof());
return OCTETSTRING(0,NULL);
}
int locPort = (int)pl__locPort;
const unsigned char *locAddr = (const unsigned char *) pl__locAddr;
if(pl__remAddr.lengthof() != 4) {
// listen socket
buff[0] = locPort;
buff[1] = locAddr[3];
buff[2] = locPort >> 8;
buff[3] = locAddr[2];
buff[4] = locAddr[1];
buff[5] = locAddr[0];
buff[6] = 2; // TCP
return OCTETSTRING(7, buff);
} else {
// connected socket
int remPort = (int)pl__remPort;
const unsigned char *remAddr = (const unsigned char *) pl__remAddr;
buff[0] = locPort;
buff[1] = locAddr[3];
buff[2] = locPort >> 8;
buff[3] = locAddr[2];
buff[4] = locAddr[1];
buff[5] = locAddr[0];
buff[6] = 2; // TCP
buff[7] = remPort;
buff[8] = remAddr[3];
buff[9] = remPort >> 8;
buff[10] = remAddr[2];
buff[11] = remAddr[1];
buff[12] = remAddr[0];
return OCTETSTRING(13, buff);
}
}
// Note: the following function doesn't support extension headers.
OCTETSTRING f__EPTF__TransportIPL2__encodeIP(
const IPv4__packet &pdu)
{
int len = 0;
if(pdu.payload().ispresent()) len = pdu.payload()().lengthof();
if(len >= (65536 - 20)) {
TTCN_warning("f_EPTF_TransportIPL2_encodeIP: invalid payload length %d, should be less than (65536 - 20)", len);
return OCTETSTRING(0,NULL);
}
if(pdu.header().srcaddr().lengthof() < 4) {
TTCN_Logger::begin_event(TTCN_WARNING);
TTCN_Logger::log_event_str("f_EPTF_TransportIPL2_encodeIP: invalid source IP address ");
pdu.header().srcaddr().log();
TTCN_Logger::end_event();
return OCTETSTRING(0,NULL);
}
if(pdu.header().dstaddr().lengthof() < 4) {
TTCN_Logger::begin_event(TTCN_WARNING);
TTCN_Logger::log_event_str("f_EPTF_TransportIPL2_encodeIP: invalid destination IP address ");
pdu.header().dstaddr().log();
TTCN_Logger::end_event();
return OCTETSTRING(0,NULL);
}
static unsigned char buff[65536];
unsigned char *p = buff;
*p++ = 0x45; // note the version is fixed at v4 and header length is fixed at 5 words (20 bytes)
// *p++ = ((int)pdu.header().ver())<<4 | (int)pdu.header().hlen(); // - don't uncomment unless extension headers are implemented
*p++ = pdu.header().tos(); // Type Of Service
int tmp = len + 20;
*p++ = tmp >> 8; // Total Length
*p++ = tmp;
tmp = pdu.header().id();
*p++ = tmp >> 8; // Identification
*p++ = tmp;
tmp = (int)pdu.header().foffset();
*p = (tmp >> 8) & 0x1f; // MSB of fragment offset
if(*((const unsigned char *)pdu.header().dfrag())) *p |= 0x40; // flags
if(*((const unsigned char *)pdu.header().mfrag())) *p |= 0x20;
p++;
*p++ = tmp; // LSB of fragment offset
*p++ = (int)pdu.header().ttl(); // time to live
*p++ = (int)pdu.header().proto(); // protocol
*p++ = 0; // checksum MSB - will be calculated later
*p++ = 0; // checksum LSB
const unsigned char* addr = (const unsigned char*) pdu.header().srcaddr();
*p++ = addr[0];
*p++ = addr[1];
*p++ = addr[2];
*p++ = addr[3];
addr = (const unsigned char*) pdu.header().dstaddr();
*p++ = addr[0];
*p++ = addr[1];
*p++ = addr[2];
*p++ = addr[3];
if(pdu.ext__headers().ispresent()) {
TTCN_warning("f_EPTF_TransportIPL2_encodeIP: extension headers are not supported, use f_IPv4_enc instead.");
}
if(len > 0) memcpy(p, (const unsigned char*)pdu.payload()(), len);
const unsigned short *stemp = (const unsigned short*) buff;
unsigned long sum = 0;
// calculate checksum for IP header
for (int i = 0; i < 10; i++) {
sum += htons(*stemp++);
}
sum = (sum & 0xFFFF) + (sum >> 16);
sum = ~sum;
buff[10] = sum >> 8;
buff[11] = sum;
return OCTETSTRING(len + 20, buff);
}
BOOLEAN f__EPTF__TransportIPL2__decodeIP(
const OCTETSTRING &data,
IPv4__packet &pdu) // returns true if packet is a fragment, false if not
{
const unsigned char *p = (const unsigned char*) data;
boolean isFragment = FALSE;
pdu.header().ver() = *p >> 4;
int hlen = *p & 0x0f;
pdu.header().hlen() = hlen;
hlen <<= 2;
p++;
pdu.header().tos() = *p++;
int pdulen = (*p << 8) + *(p+1);
p+=2;
if(pdulen > data.lengthof()) { // libpcap (1.0.0.6) bug maybe?
TTCN_warning("IP datagram length %d, ethernet payload length only %d bytes, using latter.",
pdulen, data.lengthof());
pdulen = data.lengthof();
}
pdu.header().tlen() = pdulen;
pdu.header().id() = (*p << 8) + *(p+1);
p+=2;
unsigned char zero = 0, one = 1;
pdu.header().res() = BITSTRING(1, &zero);
if(*p & 0x40) pdu.header().dfrag() = BITSTRING(1, &one);
else pdu.header().dfrag() = BITSTRING(1, &zero);
if(*p & 0x20) {
pdu.header().mfrag() = BITSTRING(1, &one);
isFragment = TRUE;
}
else pdu.header().mfrag() = BITSTRING(1, &zero);
int tmp = ((*p & 0x1f) << 8) + *(p+1);
pdu.header().foffset() = tmp;
isFragment |= tmp > 0;
p+=2;
pdu.header().ttl() = *p++;
pdu.header().proto() = *p++;
pdu.header().cksum() = (*p << 8) + *(p+1);
p+=2;
pdu.header().srcaddr() = OCTETSTRING(4, p);
p+=4;
pdu.header().dstaddr() = OCTETSTRING(4, p);
p+=4;
p += hlen - 20;
pdu.payload() = OCTETSTRING(pdulen - hlen, p);
pdu.ext__headers() = OMIT_VALUE;
return BOOLEAN(isFragment);
}
/*OCTETSTRING f__EPTF__TransportIPL2__encodeUDPPseudoHead(
const OCTETSTRING &srcaddr,
const OCTETSTRING &dstaddr,
const INTEGER &payloadlength)
{
static unsigned char buff[16];
unsigned char *p = buff;
*p++ = srcaddr[0].get_octet();
*p++ = srcaddr[1].get_octet();
*p++ = srcaddr[2].get_octet();
*p++ = srcaddr[3].get_octet();
*p++ = dstaddr[0].get_octet();
*p++ = dstaddr[1].get_octet();
*p++ = dstaddr[2].get_octet();
*p++ = dstaddr[3].get_octet();
*p++ = 0;
*p++ = 17; // UDP protocol
int len = (int) payloadlength;
*p++ = len >> 8;
*p = len;
return OCTETSTRING(12, buff);
}
OCTETSTRING f__EPTF__TransportIPL2__encodeUDP(
const INTEGER &srcport,
const INTEGER &dstport,
const OCTETSTRING &payload)
{
int len = payload.lengthof();
if(len > (65536 - 8)) return OCTETSTRING(0,NULL);
static short sbuff[32768];
short *p = &sbuff[0];
*p++ = htons((int) srcport);
*p++ = htons((int) dstport);
*p++ = htons(len);
*p++ = 0; // checksum
memcpy(p, (const unsigned char *) payload, len);
return OCTETSTRING(len + 8, (unsigned char *)sbuff);
}*/
const unsigned char prot_id_tcp = 6;
const unsigned char prot_id_udp = 17;
const unsigned char checksum_offset_udp = 6;
const unsigned char checksum_offset_tcp = 16;
void calcInternetChecksum(
const unsigned char *pdu, int pdulen, unsigned char prot_id, unsigned char checksum_offset,
const unsigned char *psrcaddr,
const unsigned char *pdstaddr,
unsigned char *ck1, unsigned char *ck2) // out
{
// it is assumed here that short is 16bit long
//if(pdulen < 20) return;
// initializing checksum with UDP/TCP pseudo header
const unsigned short *stemp = (const unsigned short*) psrcaddr;
unsigned long sum = *stemp++;
sum += *stemp;
stemp = (const unsigned short*) pdstaddr;
sum += *stemp++;
sum += *stemp;
sum += htons(prot_id); // UDP/TCP protocol
sum += htons(pdulen);
stemp = (const unsigned short*) pdu;
const unsigned short *p_end = (const unsigned short*)(pdu+checksum_offset);
while (stemp<p_end) {
sum += *stemp++;
}
stemp++; // skip checksum field
p_end = (const unsigned short*)(pdu+pdulen-1);
while (stemp<p_end) {
sum += *stemp++;
}
if (pdulen & 1) {
sum += htons(pdu[pdulen-1] << 8); // convert to network byte order
}
// keep only the last 16 bits of the 32 bit calculated sum and add the carries
while (sum>>16) {
sum = (sum & 0xFFFF)+(sum >> 16);
}
// finalize checksum, copy to buffer
unsigned short checksum = ~sum;
if(checksum == 0) checksum = 0xFFFF;
*ck1 = *(unsigned char*)&checksum;
*ck2 = *((unsigned char*)&checksum+1);
}
OCTETSTRING f__EPTF__TransportIPL2__encodeUDPWithChecksum(
const OCTETSTRING &srcaddr,
const INTEGER &srcport,
const OCTETSTRING &dstaddr,
const INTEGER &dstport,
const OCTETSTRING &payload)
{
int len = payload.lengthof();
int pdulen = len + 8;
if(pdulen > 65535) return OCTETSTRING(0,NULL);
const unsigned char *psrcaddr = (const unsigned char *)srcaddr;
const unsigned char *pdstaddr = (const unsigned char *)dstaddr;
if(psrcaddr == NULL || pdstaddr == NULL) return OCTETSTRING(0,NULL);
// create UDP header + checksum update
static unsigned short sbuff[32768];
unsigned short *p = &sbuff[0];
unsigned char *checksum_addr;
*p++ = htons((int) srcport);
*p++ = htons((int) dstport);
*p++ = htons(pdulen);
checksum_addr=(unsigned char *)p;
p++; // skip checksum field - set later via checksum_addr
if (len > 0) {
// OCTETSTRING in network byte order!!!!
// copy payload + checksum update
memcpy(p, (const unsigned char*) payload, len);
p += len;
}
calcInternetChecksum(
(const unsigned char *)sbuff, pdulen,prot_id_udp,checksum_offset_udp,
psrcaddr,
pdstaddr,
checksum_addr,
checksum_addr + 1
);
return OCTETSTRING(pdulen, (unsigned char *)sbuff);
}
BOOLEAN f__EPTF__TransportIPL2__decodeUDPWithChecksum(
const OCTETSTRING &srcaddr,
const OCTETSTRING &dstaddr,
const OCTETSTRING &udppdu,
INTEGER &srcport,
INTEGER &dstport,
OCTETSTRING &payload)
{
int pdulen = udppdu.lengthof(); // length of the whole UDP PDU
int len = pdulen - 8; // length of payload
if(pdulen > 65535 || len < 0 || srcaddr.lengthof() < 4 || dstaddr.lengthof() < 4) return BOOLEAN(FALSE);
const unsigned char *psrcaddr = (const unsigned char *)srcaddr;
const unsigned char *pdstaddr = (const unsigned char *)dstaddr;
if(psrcaddr == NULL || pdstaddr == NULL) return BOOLEAN(FALSE);
const unsigned char *ctemp = (const unsigned char*) udppdu;
const unsigned short *stemp = (const unsigned short*) ctemp;
int encoded_pdulen = ntohs(stemp[2]);
if(encoded_pdulen != pdulen) {
#ifdef EPTF_DEBUG
TTCN_Logger::log(TTCN_DEBUG, "f_EPTF_TransportIPL2_decodeUDPWithChecksum: "
"incoming UDP PDU has invalid length. Encoded: %d, should be: %d",
encoded_pdulen, pdulen);
#endif
if(encoded_pdulen < pdulen) {
pdulen = encoded_pdulen;
len = encoded_pdulen - 8;
if(len < 0) return BOOLEAN(FALSE);
} else return BOOLEAN(FALSE);
}
// UDP header
srcport = ntohs(stemp[0]);
dstport = ntohs(stemp[1]);
unsigned short encoded_checksum = ntohs(stemp[3]) & 0xFFFF; // short can be longer than 16 bits
stemp += 4;
// calculate the checksum:
unsigned short checksum = 0;
unsigned char *checksum_addr = (unsigned char *)&checksum;
calcInternetChecksum(
ctemp, pdulen,prot_id_udp,checksum_offset_udp,
psrcaddr,
pdstaddr,
checksum_addr,
checksum_addr + 1
);
checksum=ntohs(checksum);
if(encoded_checksum != checksum) {
#ifdef EPTF_DEBUG
TTCN_Logger::log(TTCN_DEBUG, "f_EPTF_TransportIPL2_decodeUDPWithChecksum: "
"incoming UDP PDU has invalid checksum. Encoded: %4.4X, should be: %4.4X",
encoded_checksum, checksum);
#endif
return BOOLEAN(FALSE);
}
payload = OCTETSTRING(len, ctemp + 8);
return BOOLEAN(TRUE);
}
BOOLEAN f__EPTF__TransportIPL2__verifyUDPChecksum(
const OCTETSTRING &srcaddr,
const OCTETSTRING &dstaddr,
const OCTETSTRING &tcppdu) {
unsigned char ck1, ck2;
const unsigned char *ppdu = (const unsigned char *)tcppdu;
calcInternetChecksum(
ppdu, tcppdu.lengthof(),prot_id_udp,checksum_offset_udp,
(const unsigned char *)srcaddr,
(const unsigned char *)dstaddr,
&ck1, &ck2);
if(ck1 != ppdu[checksum_offset_udp] || ck2 != ppdu[checksum_offset_udp+1]) {
TTCN_Logger::log(TTCN_DEBUG,
"UDP checksum verification failed.\n"
" Expected %2.2X %2.2X\n Received %2.2X %2.2X",
ck1, ck2, ppdu[6], ppdu[7]);
return BOOLEAN(FALSE);
}
else return BOOLEAN(TRUE);
}
OCTETSTRING f__EPTF__TransportIPL2__encodeTCPWithChecksum(
const OCTETSTRING &srcaddr,
const OCTETSTRING &dstaddr,
const EPTF__CLL__TransportIPL2__Definitions::EPTF__TransportIPL2__PDU__TCP & pdu) {
// for getting the necessary padding values
// optionslen % 4 == 0 -> no pad needed
// optionslen % 4 == 1 -> 3 zero pad needed
// optionslen % 4 == 2 -> 2 zero pad needed
// optionslen % 4 == 3 -> 1 zero pad needed
// The index of this array is the reminder of div 4
static const int padtable[4] = { 0, 3, 2, 1 };
int datalen = pdu.data().lengthof();
int optionslen_orig = pdu.options().lengthof();
int options_padlen = padtable[optionslen_orig & 0x03];
int optionslen = optionslen_orig + options_padlen;
int headlen = 20 + optionslen;
int pdulen = datalen + headlen;
if (pdulen > 65535) {
return OCTETSTRING(0, NULL);
}
const unsigned char *psrcaddr = (const unsigned char *) srcaddr;
const unsigned char *pdstaddr = (const unsigned char *) dstaddr;
if (psrcaddr == NULL || pdstaddr == NULL) {
return OCTETSTRING(0, NULL);
}
// create TCP header + checksum update
static unsigned char buff[65535];
unsigned char *p = &buff[0];
unsigned char *checksum_addr;
*p++ = pdu.source__port() >> 8;
*p++ = pdu.source__port();
*p++ = pdu.dest__port() >> 8;
*p++ = pdu.dest__port();
unsigned long seqno = (int) pdu.sequence__number();
*p++ = seqno >> 24;
*p++ = seqno >> 16;
*p++ = seqno >> 8;
*p++ = seqno;
unsigned long ackno = (int) pdu.acknowledgment__number();
*p++ = ackno >> 24;
*p++ = ackno >> 16;
*p++ = ackno >> 8;
*p++ = ackno;
unsigned char dataoffset = (headlen << 2) & 0xF0;
unsigned char flags = pdu.control__bits();
*p++ = dataoffset;
*p++ = flags;
*p++ = pdu.window() >> 8;
*p++ = pdu.window();
// Save the checksum pointer. It will be set later.
checksum_addr = p;
*p++ = 0;
*p++ = 0;
// urgent pointer not used
*p++ = 0;
*p++ = 0;
// Adding options
if (optionslen_orig > 0) {
// OCTETSTRING in network byte order!!!!
memcpy(p, (const unsigned char*) pdu.options(), optionslen_orig);
p += optionslen_orig;
//Add padding. Checksum update doesn't needed (sum+=0)
for (int i = 0; i < options_padlen; i++) {
*p++ = 0;
}
}
if (datalen > 0) {
// OCTETSTRING in network byte order!!!!
// copy payload + checksum update
memcpy(p, (const unsigned char*) pdu.data(), datalen);
p += datalen;
}
calcInternetChecksum(
buff, pdulen,prot_id_tcp,checksum_offset_tcp,
psrcaddr,
pdstaddr,
checksum_addr,
checksum_addr + 1
);
return OCTETSTRING(pdulen, (unsigned char *) buff);
}
BOOLEAN f__EPTF__TransportIPL2__verifyTCPChecksum(
const OCTETSTRING &srcaddr,
const OCTETSTRING &dstaddr,
const OCTETSTRING &tcppdu) {
unsigned char ck1, ck2;
const unsigned char *ppdu = (const unsigned char *)tcppdu;
calcInternetChecksum(
ppdu, tcppdu.lengthof(),prot_id_tcp,checksum_offset_tcp,
(const unsigned char *)srcaddr,
(const unsigned char *)dstaddr,
&ck1, &ck2);
if(ck1 != ppdu[checksum_offset_tcp] || ck2 != ppdu[checksum_offset_tcp+1]) {
TTCN_Logger::log(TTCN_DEBUG,
"TCP checksum verification failed.\n"
" Expected %2.2X %2.2X\n Received %2.2X %2.2X",
ck1, ck2, ppdu[16], ppdu[17]);
return BOOLEAN(FALSE);
}
else return BOOLEAN(TRUE);
}
BOOLEAN f__EPTF__TransportIPL2__decodeTCP(
const OCTETSTRING &tcppdu,
EPTF__CLL__TransportIPL2__Definitions::EPTF__TransportIPL2__PDU__TCP &pdu) {
const unsigned char *ctemp = (const unsigned char*) tcppdu; // char list
int pdulen = tcppdu.lengthof(); // length of the whole TCP PDU
// Invalid pdu length (20=min header size)
if (pdulen > 65535 || pdulen < 20) {
return BOOLEAN(FALSE);
}
// s:0 c:0
pdu.source__port() = (*ctemp << 8) + *(ctemp+1);
ctemp += 2;
// s:1 c:2
pdu.dest__port() = (*ctemp << 8) + *(ctemp+1);
ctemp += 2;
// s:2 c:4
unsigned long tmp = 0;
tmp = *ctemp++;
tmp<<=8;
tmp += *ctemp++;
tmp<<=8;
tmp += *ctemp++;
tmp<<=8;
tmp += *ctemp++;
pdu.sequence__number() = (int)tmp;
// s:4 c:8
tmp = *ctemp++;
tmp<<=8;
tmp += *ctemp++;
tmp<<=8;
tmp += *ctemp++;
tmp<<=8;
tmp += *ctemp++;
pdu.acknowledgment__number() = (int)tmp;
// s:6 c:12
int data_offset = (*ctemp & 0xF0) >> 2;
ctemp++;
// reserved is zero but not verified
// s:6 c:13
pdu.control__bits() = *ctemp++;
// s:7 c:14
pdu.window() = (*ctemp << 8) + *(ctemp+1);
ctemp += 2;
// s:8 c:16 !!! CHECKSUM !!!
ctemp += 2;
// s:9 c:18
// urgent pointer not used
ctemp += 2;
// s:10 c:20
int optionslen = data_offset - 20;
if (optionslen == 0) {
pdu.options() = OCTETSTRING(0, NULL);
} else if (optionslen > 0) {
pdu.options() = OCTETSTRING(optionslen, ctemp);
ctemp += optionslen;
} else {
// TODO: Log some fancy message
pdu.options() = OCTETSTRING(0, NULL);
pdu.data() = OCTETSTRING(0, NULL);
return BOOLEAN(FALSE);
}
int datalen = pdulen - data_offset;
if (datalen == 0) {
pdu.data() = OCTETSTRING(0, NULL);
} else if (datalen > 0) {
pdu.data() = OCTETSTRING(datalen, ctemp);
ctemp += datalen;
} else {
// TODO: Log some fancy message
pdu.data() = OCTETSTRING(0, NULL);
return BOOLEAN(FALSE);
}
return BOOLEAN(TRUE);
}
#define RTF_UP 0x0001 /* route usable */
#define PATH_PROCNET_ROUTE "/proc/net/route"
static char *proc_gen_fmt(char *name, int more, FILE * fh, ...) {
char buf[512], format[512] = "";
char *title, *head, *hdr;
va_list ap;
if (!fgets(buf, (sizeof buf) - 1, fh))
return NULL;
strcat(buf, " ");
va_start(ap, fh);
title = va_arg(ap, char *);
for (hdr = buf; hdr;) {
while (isspace(*hdr) || *hdr == '|')
hdr++;
head = hdr;
hdr = strpbrk(hdr, "| \t\n");
if (hdr)
*hdr++ = 0;
if (!strcmp(title, head)) {
strcat(format, va_arg(ap, char *));
title = va_arg(ap, char *);
if (!title || !head)
break;
} else {
strcat(format, "%*s"); /* XXX */
}
strcat(format, " ");
}
va_end(ap);
if (!more && title) {
fprintf(stderr, "warning: %s does not contain required field %s\n",
name, title);
return NULL;
}
return strdup(format);
}
void f__EPTF__TransportIPL2__getHostRoutingTable(
EPTF__CLL__TransportIPL2__Definitions::EPTF__TransportIPL2__RouteTable &pl__table)
{
// Clear the table in any case.
pl__table.set_size(0);
#ifdef LINUX
char buff[1024], iface[16];
unsigned int gate_addr, net_addr;
unsigned int mask_addr;
int num, iflags, metric, refcnt, use, mss, window, irtt;
FILE *fp;
fp = fopen(PATH_PROCNET_ROUTE, "r");
char *fmt;
if (!fp) {
perror( PATH_PROCNET_ROUTE);
printf("INET (IPv4) not configured in this system.\n");
return;
}
irtt = 0;
window = 0;
mss = 0;
fmt = proc_gen_fmt(PATH_PROCNET_ROUTE, 0, fp,
"Iface", "%16s",
"Destination", "%X",
"Gateway", "%X",
"Flags", "%X",
"RefCnt", "%d",
"Use", "%d",
"Metric", "%d",
"Mask", "%X",
"MTU", "%d",
"Window", "%d",
"IRTT", "%d", NULL);
/* "%16s %X %X %X %d %d %d %X %d %d %d\n" */
int i=0;
while (fgets(buff, 1023, fp)) {
num = sscanf(buff, fmt, iface, &net_addr, &gate_addr, &iflags, &refcnt,
&use, &metric, &mask_addr, &mss, &window, &irtt);
if (num < 10 || !(iflags & RTF_UP)) {
continue;
}
pl__table[i].destination() = OCTETSTRING(4, (const unsigned char*)&net_addr);
pl__table[i].gateway() = OCTETSTRING(4, (const unsigned char*)&gate_addr);
pl__table[i].genmask() = OCTETSTRING(4, (const unsigned char*)&mask_addr);
pl__table[i].iface() = CHARSTRING(strlen(iface), (const char*)iface);
i++;
}
#endif
#if defined(SOLARIS) || defined(SOLARIS8)
// Solaris8 to be implemented
#endif
}
}