#! /usr/local/bin/perl

# converter from http://moat.nlanr.net/Traces/
# for converting network traces to jdb
# with some small hacks.
# John Heidemann
# (originally by NLANR people, I presume)



# input file format:
#
# 512 byte header
# 17408*60 bytes data
# 512 byte header
# 17408*60 bytes data
# . . . .
#
# bytes 2/3 in the headers contain the usable cell count for the data portion
# bytes 4/5 contain the interface number for the data portion
#
# for the data part:
#
#    0                   1                   2                   3
#    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#0  |                          clockstamp                           | Header
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#1  |          clockstamp           |          FIFO depth           |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#2  |                          ATM header                           |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#3  |                           LLC/SNAP                            |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#4  |                           LLC/SNAP                            |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#5  |Version|  IHL  |Type of Service|          Total Length         | IP
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#6  |         Identification        |Flags|      Fragment Offset    |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#7  |  Time to Live |    Protocol   |         Header Checksum       |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#8  |                       Source Address                          |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#9  |                    Destination Address                        |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
# option(s) or other header following; e.g., for TCP:
#
#   |          Source Port          |       Destination Port        | TCP
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#   |                        Sequence Number                        |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#   |                    Acknowledgment Number                      |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#   |  Data |           |U|A|P|R|S|F|                               |
#   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
#   |       |           |G|K|H|T|N|N|                               |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#

my($tcp_only);
if ($ARGV[0] eq "tcp") { $tcp_only = 1; shift @ARGV; };

open(infile,$ARGV[0]) || die("Can't open input file\n");
$if=$ARGV[1];		# requested interface

$tdelta=0.01;
$oldtimestamp=0;

print "#h interface tpcount timestamp timediff src dst plen prot sport dport seqno ackno flags wnd\n";

# skip header
while(read(infile,$record,512)){
 $cflag=vec($record,0,16);                         #non-byte-swapped clock if -1
 $cellcount=vec($record,2,8)*256+vec($record,3,8);
 $interface=vec($record,4,8)*256+vec($record,5,8);
 printf stderr "#(stderr)block $interface\t$cellcount\n";
# Start reading in entries
 for ($lccnt = 1; $lccnt <= 17408; $lccnt++) {
  read(infile,$record,60) || exit;
  if($lccnt > $cellcount){next;}
  if(($if ne "") && ($if != $interface)){next;}
  $tpcount++;

  if($cflag == 0xffff) {
   $ts1= vec($record,3,8); $ts2= vec($record,2,8);
  }else{
   $ts1= vec($record,4,8); $ts2= vec($record,5,8);
  }
  $clock=($ts1<<8)+$ts2;
  if($clock < $oldclock){$clock2++;}
  $oldclock=$clock;
  $timestamp=(($clock2*65536)+$clock)*0.00000004;

  if(vec($record,18,8) == 0x08){
   $src  = vec($record,8,32);
   $dst  = vec($record,9,32);
   $src1 = vec($record,32,8);
   $src2 = vec($record,33,8);
   $src3 = vec($record,34,8);
   $src4 = vec($record,35,8);
   $dst1 = vec($record,36,8);
   $dst2 = vec($record,37,8);
   $dst3 = vec($record,38,8);
   $dst4 = vec($record,39,8);

   $plen       = vec($record,22,8)*256+vec($record,23,8);
   $prot       = vec($record,29,8);

   $ihl        = (vec($record,20,8)&0xf)*4;
   $sport      = vec($record,$ihl+20,8)*256+vec($record,$ihl+21,8);
   $dport      = vec($record,$ihl+22,8)*256+vec($record,$ihl+23,8);

   #johnh
   $seqno = ((vec($record,$ihl+22,8)*256 +
	      vec($record,$ihl+23,8))*256 +
	     vec($record,$ihl+24,8))*256 +
	     vec($record,$ihl+25,8);
   $ackno = ((vec($record,$ihl+26,8)*256 +
	      vec($record,$ihl+27,8))*256 +
	     vec($record,$ihl+28,8))*256 +
	     vec($record,$ihl+29,8);
   $flags    = vec($record,$ihl+30,8)*256+vec($record,$ihl+31,8);
   $wnd      = vec($record,$ihl+32,8)*256+vec($record,$ihl+33,8);
   #end johnh

   printf"%d\t%d\t%.8f\t%.8f\t%d.%d.%d.%d\t%d.%d.%d.%d\t%d\t%d\t%d\t%d\t%ud\t%ud\t0x%x\t%d \n",
        $interface,$tpcount,$timestamp,$timestamp-$oldtimestamp,
        $src1,$src2,$src3,$src4,
        $dst1,$dst2,$dst3,$dst4,
        $plen,$prot,$sport,$dport,
	$seqno, $ackno, $flags, $wnd;
   if(($timestamp > ($oldtimestamp+$tdelta)) || ($timestamp < $oldtimestamp)){
    printf stderr "#(stderr) Time delta: $oldtimestamp $timestamp (%s)\n",
     $timestamp-$oldtimestamp;
   }
   $oldtimestamp=$timestamp;
  }else{
   $nippcount++;
   next if ($tcp_only);
   printf"%d\t%d\t%.8f\t%.8f\t",$interface,$tpcount,$timestamp,$timestamp-$oldtimestamp;
   for ($j= 0; $j<=19; $j++){printf"%2x ",vec($record,$j,8);}
   printf"\n\t\t\t\t\t\t";
   for ($j=20; $j<=39; $j++){printf"%2x ",vec($record,$j,8);}
   printf"\n\t\t\t\t\t\t";
   for ($j=40; $j<=59; $j++){printf"%2x ",vec($record,$j,8);}
   printf"\n\n";
  }
 }
}
