Home | History | Annotate | Line # | Download | only in monitoring
ntp.pl revision 1.1.1.1.14.1
      1           1.1  kardel #!/usr/bin/perl -w
      2           1.1  kardel ;#
      3           1.1  kardel ;# ntp.pl,v 3.1 1993/07/06 01:09:09 jbj Exp
      4           1.1  kardel ;#
      5           1.1  kardel ;# process loop filter statistics file and either
      6           1.1  kardel ;#     - show statistics periodically using gnuplot
      7           1.1  kardel ;#     - or print a single plot
      8           1.1  kardel ;#
      9           1.1  kardel ;#  Copyright (c) 1992 
     10           1.1  kardel ;#  Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg
     11           1.1  kardel ;#
     12           1.1  kardel ;#
     13           1.1  kardel ;#############################################################
     14           1.1  kardel 
     15           1.1  kardel package ntp;
     16           1.1  kardel 
     17           1.1  kardel $NTP_version = 2;
     18           1.1  kardel $ctrl_mode=6;
     19           1.1  kardel 
     20           1.1  kardel $byte1 = (($NTP_version & 0x7)<< 3) & 0x34 | ($ctrl_mode & 0x7);
     21           1.1  kardel $MAX_DATA = 468;
     22           1.1  kardel 
     23           1.1  kardel $sequence = 0;			# initial sequence number incred before used
     24           1.1  kardel $pad=4;
     25           1.1  kardel $do_auth=0;			# no possibility today
     26           1.1  kardel $keyid=0;
     27           1.1  kardel ;#list if known keys (passwords)
     28           1.1  kardel %KEYS = ( 0, "\200\200\200\200\200\200\200\200",
     29           1.1  kardel 	 );
     30           1.1  kardel 
     31           1.1  kardel ;#-----------------------------------------------------------------------------
     32           1.1  kardel ;# access routines for ntp control packet
     33           1.1  kardel     ;# NTP control message format
     34           1.1  kardel     ;#  C  LI|VN|MODE  LI 2bit=00  VN 3bit=2(3) MODE 3bit=6 : $byte1
     35           1.1  kardel     ;#  C  R|E|M|Op    R response  E error    M more   Op opcode
     36           1.1  kardel     ;#  n  sequence
     37           1.1  kardel     ;#  n  status
     38           1.1  kardel     ;#  n  associd
     39           1.1  kardel     ;#  n  offset
     40           1.1  kardel     ;#  n  count
     41           1.1  kardel     ;#  a+ data (+ padding)
     42           1.1  kardel     ;#  optional authentication data
     43           1.1  kardel     ;#  N  key
     44           1.1  kardel     ;#  N2 checksum
     45           1.1  kardel     
     46           1.1  kardel ;# first byte of packet
     47           1.1  kardel sub pkt_LI   { return ($_[$[] >> 6) & 0x3; }
     48           1.1  kardel sub pkt_VN   { return ($_[$[] >> 3) & 0x7; }
     49           1.1  kardel sub pkt_MODE { return ($_[$[]     ) & 0x7; }
     50           1.1  kardel 
     51           1.1  kardel ;# second byte of packet
     52           1.1  kardel sub pkt_R  { return ($_[$[] & 0x80) == 0x80; }
     53           1.1  kardel sub pkt_E  { return ($_[$[] & 0x40) == 0x40; }
     54           1.1  kardel sub pkt_M  { return ($_[$[] & 0x20) == 0x20; }
     55           1.1  kardel sub pkt_OP { return $_[$[] & 0x1f; }
     56           1.1  kardel 
     57           1.1  kardel ;#-----------------------------------------------------------------------------
     58           1.1  kardel 
     59           1.1  kardel sub setkey
     60           1.1  kardel {
     61           1.1  kardel     local($id,$key) = @_;
     62           1.1  kardel 
     63           1.1  kardel     $KEYS{$id} = $key if (defined($key));
     64           1.1  kardel     if (! defined($KEYS{$id}))
     65           1.1  kardel     {
     66           1.1  kardel 	warn "Key $id not yet specified - key not changed\n";
     67           1.1  kardel 	return undef;
     68           1.1  kardel     }
     69           1.1  kardel     return ($keyid,$keyid = $id)[$[];
     70           1.1  kardel }
     71           1.1  kardel 
     72           1.1  kardel ;#-----------------------------------------------------------------------------
     73           1.1  kardel sub numerical { $a <=> $b; }
     74           1.1  kardel 
     75           1.1  kardel ;#-----------------------------------------------------------------------------
     76           1.1  kardel 
     77           1.1  kardel sub send	#'
     78           1.1  kardel {
     79           1.1  kardel     local($fh,$opcode, $associd, $data,$address) = @_;
     80           1.1  kardel     $fh = caller(0)."'$fh";
     81           1.1  kardel 
     82           1.1  kardel     local($junksize,$junk,$packet,$offset,$ret);
     83           1.1  kardel     $offset = 0;
     84           1.1  kardel 
     85           1.1  kardel     $sequence++;
     86           1.1  kardel     while(1)
     87           1.1  kardel     {
     88           1.1  kardel 	$junksize = length($data);
     89           1.1  kardel 	$junksize = $MAX_DATA if $junksize > $MAX_DATA;
     90           1.1  kardel 	
     91           1.1  kardel 	($junk,$data) = $data =~ /^(.{$junksize})(.*)$/;
     92           1.1  kardel 	$packet
     93           1.1  kardel 	    = pack("C2n5a".(($junk eq "") ? 0 : &pad($junksize+12,$pad)-12),
     94           1.1  kardel 		   $byte1,
     95           1.1  kardel 		   ($opcode & 0x1f) | ($data ? 0x20 : 0),
     96           1.1  kardel 		   $sequence,
     97           1.1  kardel 		   0, $associd,
     98           1.1  kardel 		   $offset, $junksize, $junk);
     99           1.1  kardel 	if ($do_auth)
    100           1.1  kardel 	{
    101           1.1  kardel 	    ;# not yet
    102           1.1  kardel 	}
    103           1.1  kardel 	$offset += $junksize;
    104           1.1  kardel 
    105           1.1  kardel 	if (defined($address))
    106           1.1  kardel 	{
    107           1.1  kardel 	    $ret = send($fh, $packet, 0, $address);
    108           1.1  kardel 	}
    109           1.1  kardel 	else
    110           1.1  kardel 	{
    111           1.1  kardel 	    $ret = send($fh, $packet, 0);
    112           1.1  kardel 	}
    113           1.1  kardel 
    114           1.1  kardel 	if (! defined($ret))
    115           1.1  kardel 	{
    116           1.1  kardel 	    warn "send failed: $!\n";
    117           1.1  kardel 	    return undef;
    118           1.1  kardel 	}
    119           1.1  kardel 	elsif ($ret != length($packet))
    120           1.1  kardel 	{
    121           1.1  kardel 	    warn "send failed: sent only $ret from ".length($packet). "bytes\n";
    122           1.1  kardel 	    return undef;
    123           1.1  kardel 	}
    124           1.1  kardel 	return $sequence unless $data;
    125           1.1  kardel     }
    126           1.1  kardel }
    127           1.1  kardel 
    128           1.1  kardel ;#-----------------------------------------------------------------------------
    129           1.1  kardel ;# status interpretation
    130           1.1  kardel ;#
    131           1.1  kardel sub getval
    132           1.1  kardel {
    133           1.1  kardel     local($val,*list) = @_;
    134           1.1  kardel     
    135           1.1  kardel     return $list{$val} if defined($list{$val});
    136           1.1  kardel     return sprintf("%s#%d",$list{"-"},$val) if defined($list{"-"});
    137           1.1  kardel     return "unknown-$val";
    138           1.1  kardel }
    139           1.1  kardel 
    140           1.1  kardel ;#---------------------------------
    141           1.1  kardel ;# system status
    142           1.1  kardel ;#
    143           1.1  kardel ;# format: |LI|CS|SECnt|SECode| LI=2bit CS=6bit SECnt=4bit SECode=4bit
    144           1.1  kardel sub ssw_LI     { return ($_[$[] >> 14) & 0x3; }
    145           1.1  kardel sub ssw_CS     { return ($_[$[] >> 8)  & 0x3f; }
    146           1.1  kardel sub ssw_SECnt  { return ($_[$[] >> 4)  & 0xf; }
    147           1.1  kardel sub ssw_SECode { return $_[$[] & 0xf; }
    148           1.1  kardel 
    149           1.1  kardel %LI = ( 0, "leap_none",  1, "leap_add_sec", 2, "leap_del_sec", 3, "sync_alarm", "-", "leap");
    150           1.1  kardel %ClockSource = (0, "sync_unspec",
    151  1.1.1.1.14.1     snj 		1, "sync_pps",
    152  1.1.1.1.14.1     snj 		2, "sync_lf_clock",
    153           1.1  kardel 		3, "sync_hf_clock",
    154  1.1.1.1.14.1     snj 		4, "sync_uhf_clock",
    155  1.1.1.1.14.1     snj 		5, "sync_local_proto",
    156  1.1.1.1.14.1     snj 		6, "sync_ntp",
    157  1.1.1.1.14.1     snj 		7, "sync_udp/time",
    158  1.1.1.1.14.1     snj 		8, "sync_wristwatch",
    159  1.1.1.1.14.1     snj 		9, "sync_telephone",
    160           1.1  kardel 		"-", "ClockSource",
    161           1.1  kardel 		);
    162           1.1  kardel 
    163           1.1  kardel %SystemEvent = (0, "event_unspec",
    164  1.1.1.1.14.1     snj 		1, "event_freq_not_set",
    165  1.1.1.1.14.1     snj 		2, "event_freq_set",
    166  1.1.1.1.14.1     snj 		3, "event_spike_detect",
    167  1.1.1.1.14.1     snj 		4, "event_freq_mode",
    168  1.1.1.1.14.1     snj 		5, "event_clock_sync",
    169  1.1.1.1.14.1     snj 		6, "event_restart",
    170  1.1.1.1.14.1     snj 		7, "event_panic_stop",
    171  1.1.1.1.14.1     snj 		8, "event_no_sys_peer",
    172  1.1.1.1.14.1     snj 		9, "event_leap_armed",
    173  1.1.1.1.14.1     snj 		10, "event_leap_disarmed",
    174  1.1.1.1.14.1     snj 		11, "event_leap_event",
    175  1.1.1.1.14.1     snj 		12, "event_clock_step",
    176  1.1.1.1.14.1     snj 		13, "event_kern",
    177  1.1.1.1.14.1     snj 		14, "event_loaded_leaps",
    178  1.1.1.1.14.1     snj 		15, "event_stale_leaps",
    179           1.1  kardel 		"-", "event",
    180           1.1  kardel 		);
    181           1.1  kardel sub LI
    182           1.1  kardel {
    183           1.1  kardel     &getval(&ssw_LI($_[$[]),*LI);
    184           1.1  kardel }
    185           1.1  kardel sub ClockSource
    186           1.1  kardel {
    187           1.1  kardel     &getval(&ssw_CS($_[$[]),*ClockSource);
    188           1.1  kardel }
    189           1.1  kardel 
    190           1.1  kardel sub SystemEvent
    191           1.1  kardel {
    192           1.1  kardel     &getval(&ssw_SECode($_[$[]),*SystemEvent);
    193           1.1  kardel }
    194           1.1  kardel 
    195           1.1  kardel sub system_status
    196           1.1  kardel {
    197           1.1  kardel     return sprintf("%s, %s, %d event%s, %s", &LI($_[$[]), &ClockSource($_[$[]),
    198           1.1  kardel 		   &ssw_SECnt($_[$[]), ((&ssw_SECnt($_[$[])==1) ? "" : "s"),
    199           1.1  kardel 		   &SystemEvent($_[$[]));
    200           1.1  kardel }
    201           1.1  kardel ;#---------------------------------
    202           1.1  kardel ;# peer status
    203           1.1  kardel ;#
    204           1.1  kardel ;# format: |PStat|PSel|PCnt|PCode| Pstat=6bit PSel=2bit PCnt=4bit PCode=4bit
    205           1.1  kardel sub psw_PStat_config     { return ($_[$[] & 0x8000) == 0x8000; }
    206           1.1  kardel sub psw_PStat_authenable { return ($_[$[] & 0x4000) == 0x4000; }
    207           1.1  kardel sub psw_PStat_authentic  { return ($_[$[] & 0x2000) == 0x2000; }
    208           1.1  kardel sub psw_PStat_reach      { return ($_[$[] & 0x1000) == 0x1000; }
    209  1.1.1.1.14.1     snj sub psw_PStat_bcast      { return ($_[$[] & 0x0800) == 0x0800; }
    210           1.1  kardel sub psw_PStat { return ($_[$[] >> 10) & 0x3f; }
    211           1.1  kardel sub psw_PSel  { return ($_[$[] >> 8)  & 0x3;  }
    212           1.1  kardel sub psw_PCnt  { return ($_[$[] >> 4)  & 0xf; }
    213           1.1  kardel sub psw_PCode { return $_[$[] & 0xf; }
    214           1.1  kardel 
    215           1.1  kardel %PeerSelection = (0, "sel_reject",
    216  1.1.1.1.14.1     snj 		  1, "sel_falsetick",
    217  1.1.1.1.14.1     snj 		  2, "sel_excess",
    218  1.1.1.1.14.1     snj 		  3, "sel_outlier",
    219  1.1.1.1.14.1     snj 		  4, "sel_candidate",
    220  1.1.1.1.14.1     snj 		  5, "sel_backup",
    221  1.1.1.1.14.1     snj 		  6, "sel_sys.peer",
    222  1.1.1.1.14.1     snj 		  6, "sel_pps.peer",
    223           1.1  kardel 		  "-", "PeerSel",
    224           1.1  kardel 		  );
    225           1.1  kardel %PeerEvent = (0, "event_unspec",
    226  1.1.1.1.14.1     snj 	      1, "event_mobilize",
    227  1.1.1.1.14.1     snj 	      2, "event_demobilize",
    228           1.1  kardel 	      3, "event_unreach",
    229           1.1  kardel 	      4, "event_reach",
    230  1.1.1.1.14.1     snj 	      5, "event_restart",
    231  1.1.1.1.14.1     snj 	      6, "event_no_reply",
    232  1.1.1.1.14.1     snj 	      7, "event_rate_exceed",
    233  1.1.1.1.14.1     snj 	      8, "event_denied",
    234  1.1.1.1.14.1     snj 	      9, "event_leap_armed",
    235  1.1.1.1.14.1     snj 	      10, "event_sys_peer",
    236  1.1.1.1.14.1     snj 	      11, "event_clock_event",
    237  1.1.1.1.14.1     snj 	      12, "event_bad_auth",
    238  1.1.1.1.14.1     snj 	      13, "event_popcorn",
    239  1.1.1.1.14.1     snj 	      14, "event_intlv_mode",
    240  1.1.1.1.14.1     snj 	      15, "event_intlv_err",
    241           1.1  kardel 	      "-", "event",
    242           1.1  kardel 	      );
    243           1.1  kardel 
    244           1.1  kardel sub PeerSelection
    245           1.1  kardel {
    246           1.1  kardel     &getval(&psw_PSel($_[$[]),*PeerSelection);
    247           1.1  kardel }
    248           1.1  kardel 
    249           1.1  kardel sub PeerEvent
    250           1.1  kardel {
    251           1.1  kardel     &getval(&psw_PCode($_[$[]),*PeerEvent);
    252           1.1  kardel }
    253           1.1  kardel 
    254           1.1  kardel sub peer_status
    255           1.1  kardel {
    256           1.1  kardel     local($x) = ("");
    257           1.1  kardel     $x .= "config,"     if &psw_PStat_config($_[$[]);
    258           1.1  kardel     $x .= "authenable," if &psw_PStat_authenable($_[$[]);
    259           1.1  kardel     $x .= "authentic,"  if &psw_PStat_authentic($_[$[]);
    260           1.1  kardel     $x .= "reach,"      if &psw_PStat_reach($_[$[]);
    261  1.1.1.1.14.1     snj     $x .= "bcast,"      if &psw_PStat_bcast($_[$[]);
    262           1.1  kardel 
    263           1.1  kardel     $x .= sprintf(" %s, %d event%s, %s", &PeerSelection($_[$[]),
    264           1.1  kardel 		  &psw_PCnt($_[$[]), ((&psw_PCnt($_[$[]) == 1) ? "" : "s"),
    265           1.1  kardel 		  &PeerEvent($_[$[]));
    266           1.1  kardel     return $x;
    267           1.1  kardel }
    268           1.1  kardel 
    269           1.1  kardel ;#---------------------------------
    270           1.1  kardel ;# clock status
    271           1.1  kardel ;#
    272           1.1  kardel ;# format: |CStat|CEvnt| CStat=8bit CEvnt=8bit
    273           1.1  kardel sub csw_CStat { return ($_[$[] >> 8) & 0xff; }
    274           1.1  kardel sub csw_CEvnt { return $_[$[] & 0xff; }
    275           1.1  kardel 
    276           1.1  kardel %ClockStatus = (0, "clk_nominal",
    277           1.1  kardel 		1, "clk_timeout",
    278           1.1  kardel 		2, "clk_badreply",
    279           1.1  kardel 		3, "clk_fault",
    280  1.1.1.1.14.1     snj 		4, "clk_badsig",
    281           1.1  kardel 		5, "clk_baddate",
    282           1.1  kardel 		6, "clk_badtime",
    283           1.1  kardel 		"-", "clk",
    284           1.1  kardel 	       );
    285           1.1  kardel 
    286           1.1  kardel sub clock_status
    287           1.1  kardel {
    288           1.1  kardel     return sprintf("%s, last %s",
    289           1.1  kardel 		   &getval(&csw_CStat($_[$[]),*ClockStatus),
    290           1.1  kardel 		   &getval(&csw_CEvnt($_[$[]),*ClockStatus));
    291           1.1  kardel }
    292           1.1  kardel 
    293           1.1  kardel ;#---------------------------------
    294           1.1  kardel ;# error status
    295           1.1  kardel ;#
    296           1.1  kardel ;# format: |Err|reserved|  Err=8bit
    297           1.1  kardel ;#
    298           1.1  kardel sub esw_Err { return ($_[$[] >> 8) & 0xff; }
    299           1.1  kardel 
    300           1.1  kardel %ErrorStatus = (0, "err_unspec",
    301           1.1  kardel 		1, "err_auth_fail",
    302           1.1  kardel 		2, "err_invalid_fmt",
    303           1.1  kardel 		3, "err_invalid_opcode",
    304           1.1  kardel 		4, "err_unknown_assoc",
    305           1.1  kardel 		5, "err_unknown_var",
    306           1.1  kardel 		6, "err_invalid_value",
    307           1.1  kardel 		7, "err_adm_prohibit",
    308           1.1  kardel 		);
    309           1.1  kardel 
    310           1.1  kardel sub error_status
    311           1.1  kardel {
    312           1.1  kardel     return sprintf("%s", &getval(&esw_Err($_[$[]),*ErrorStatus));
    313           1.1  kardel }
    314           1.1  kardel 
    315           1.1  kardel ;#-----------------------------------------------------------------------------
    316           1.1  kardel ;#
    317           1.1  kardel ;# cntrl op name translation
    318           1.1  kardel 
    319  1.1.1.1.14.1     snj %CntrlOpName = (0, "reserved",
    320  1.1.1.1.14.1     snj 		1, "read_status",
    321           1.1  kardel 		2, "read_variables",
    322           1.1  kardel 		3, "write_variables",
    323           1.1  kardel 		4, "read_clock_variables",
    324           1.1  kardel 		5, "write_clock_variables",
    325           1.1  kardel 		6, "set_trap",
    326           1.1  kardel 		7, "trap_response",
    327  1.1.1.1.14.1     snj 		8, "configure",
    328  1.1.1.1.14.1     snj 		9, "saveconf",
    329  1.1.1.1.14.1     snj 		10, "read_mru",
    330  1.1.1.1.14.1     snj 		11, "read_ordlist",
    331  1.1.1.1.14.1     snj 		12, "rqst_nonce",
    332           1.1  kardel 		31, "unset_trap", # !!! unofficial !!!
    333           1.1  kardel 		"-", "cntrlop",
    334           1.1  kardel 		);
    335           1.1  kardel 
    336           1.1  kardel sub cntrlop_name
    337           1.1  kardel {
    338           1.1  kardel     return &getval($_[$[],*CntrlOpName);
    339           1.1  kardel }
    340           1.1  kardel 
    341           1.1  kardel ;#-----------------------------------------------------------------------------
    342           1.1  kardel 
    343           1.1  kardel $STAT_short_pkt = 0;
    344           1.1  kardel $STAT_pkt = 0;
    345           1.1  kardel 
    346           1.1  kardel ;# process a NTP control message (response) packet
    347           1.1  kardel ;# returns a list ($ret,$data,$status,$associd,$op,$seq,$auth_keyid)
    348           1.1  kardel ;#      $ret: undef     --> not yet complete
    349           1.1  kardel ;#            ""        --> complete packet received
    350           1.1  kardel ;#            "ERROR"   --> error during receive, bad packet, ...
    351           1.1  kardel ;#          else        --> error packet - list may contain useful info
    352           1.1  kardel 
    353           1.1  kardel 
    354           1.1  kardel sub handle_packet
    355           1.1  kardel {
    356           1.1  kardel     local($pkt,$from) = @_;	# parameters
    357           1.1  kardel     local($len_pkt) = (length($pkt));
    358           1.1  kardel ;#    local(*FRAGS,*lastseen);
    359           1.1  kardel     local($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data);
    360           1.1  kardel     local($autch_keyid,$auth_cksum);
    361           1.1  kardel 
    362           1.1  kardel     $STAT_pkt++;
    363           1.1  kardel     if ($len_pkt < 12)
    364           1.1  kardel     {
    365           1.1  kardel 	$STAT_short_pkt++;
    366           1.1  kardel 	return ("ERROR","short packet received");
    367           1.1  kardel     }
    368           1.1  kardel 
    369           1.1  kardel     ;# now break packet apart
    370           1.1  kardel     ($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data) =
    371           1.1  kardel 	unpack("C2n5a".($len_pkt-12),$pkt);
    372           1.1  kardel     $data=substr($data,$[,$count);
    373           1.1  kardel     if ((($len_pkt - 12) - &pad($count,4)) >= 12)
    374           1.1  kardel     {
    375           1.1  kardel 	;# looks like an authenticator
    376           1.1  kardel 	($auth_keyid,$auth_cksum) =
    377           1.1  kardel 	    unpack("Na8",substr($pkt,$len_pkt-12+$[,12));
    378           1.1  kardel 	$STAT_auth++;
    379           1.1  kardel 	;# no checking of auth_cksum (yet ?)
    380           1.1  kardel     }
    381           1.1  kardel 
    382           1.1  kardel     if (&pkt_VN($li_vn_mode) != $NTP_version)
    383           1.1  kardel     {
    384           1.1  kardel 	$STAT_bad_version++;
    385           1.1  kardel 	return ("ERROR","version ".&pkt_VN($li_vn_mode)."packet ignored");
    386           1.1  kardel     }
    387           1.1  kardel 
    388           1.1  kardel     if (&pkt_MODE($li_vn_mode) != $ctrl_mode)
    389           1.1  kardel     {
    390           1.1  kardel 	$STAT_bad_mode++;
    391           1.1  kardel 	return ("ERROR", "mode ".&pkt_MODE($li_vn_mode)." packet ignored");
    392           1.1  kardel     }
    393           1.1  kardel     
    394           1.1  kardel     ;# handle single fragment fast
    395           1.1  kardel     if ($offset == 0 && &pkt_M($r_e_m_op) == 0)
    396           1.1  kardel     {
    397           1.1  kardel 	$STAT_single_frag++;
    398           1.1  kardel 	if (&pkt_E($r_e_m_op))
    399           1.1  kardel 	{
    400           1.1  kardel 	    $STAT_err_pkt++;
    401           1.1  kardel 	    return (&error_status($status),
    402           1.1  kardel 		    $data,$status,$associd,&pkt_OP($r_e_m_op),$seq,
    403           1.1  kardel 		    $auth_keyid);
    404           1.1  kardel 	}
    405           1.1  kardel 	else
    406           1.1  kardel 	{
    407           1.1  kardel 	    return ("",
    408           1.1  kardel 		    $data,$status,$associd,&pkt_OP($r_e_m_op),$seq,
    409           1.1  kardel 		    $auth_keyid);
    410           1.1  kardel 	}
    411           1.1  kardel     }
    412           1.1  kardel     else
    413           1.1  kardel     {
    414           1.1  kardel 	;# fragment - set up local name space
    415           1.1  kardel 	$id = "$from$seq".&pkt_OP($r_e_m_op);
    416           1.1  kardel 	$ID{$id} = 1;
    417           1.1  kardel 	*FRAGS = "$id FRAGS";
    418           1.1  kardel 	*lastseen = "$id lastseen";
    419           1.1  kardel 	
    420           1.1  kardel 	$STAT_frag++;
    421           1.1  kardel 	
    422           1.1  kardel 	$lastseen = 1 if !&pkt_M($r_e_m_op);
    423  1.1.1.1.14.1     snj 	if (!%FRAGS)
    424           1.1  kardel 	{
    425           1.1  kardel 	    print((&pkt_M($r_e_m_op) ? " more" : "")."\n");
    426           1.1  kardel 	    $FRAGS{$offset} = $data;
    427           1.1  kardel 	    ;# save other info
    428           1.1  kardel 	    @FRAGS = ($status,$associd,&pkt_OP($r_e_m_op),$seq,$auth_keyid,$r_e_m_op);
    429           1.1  kardel 	}
    430           1.1  kardel 	else
    431           1.1  kardel 	{
    432           1.1  kardel 	    print((&pkt_M($r_e_m_op) ? " more" : "")."\n");
    433           1.1  kardel 	    ;# add frag to previous - combine on the fly
    434           1.1  kardel 	    if (defined($FRAGS{$offset}))
    435           1.1  kardel 	    {
    436           1.1  kardel 		$STAT_dup_frag++;
    437           1.1  kardel 		return ("ERROR","duplicate fragment at $offset seq=$seq");
    438           1.1  kardel 	    }
    439           1.1  kardel 	    
    440           1.1  kardel 	    $FRAGS{$offset} = $data;
    441           1.1  kardel 	    
    442           1.1  kardel 	    undef($loff);
    443           1.1  kardel 	    foreach $off (sort numerical keys(%FRAGS))
    444           1.1  kardel 	    {
    445           1.1  kardel 		next unless defined($FRAGS{$off});
    446           1.1  kardel 		if (defined($loff) &&
    447           1.1  kardel 		    ($loff + length($FRAGS{$loff})) == $off)
    448           1.1  kardel 		{
    449           1.1  kardel 		    $FRAGS{$loff} .= $FRAGS{$off};
    450           1.1  kardel 		    delete $FRAGS{$off};
    451           1.1  kardel 		    last;
    452           1.1  kardel 		}
    453           1.1  kardel 		$loff = $off;
    454           1.1  kardel 	    }
    455           1.1  kardel 
    456           1.1  kardel 	    ;# return packet if all frags arrived
    457           1.1  kardel 	    ;# at most two frags with possible padding ???
    458           1.1  kardel 	    if ($lastseen && defined($FRAGS{0}) &&
    459           1.1  kardel 		(((scalar(@x=sort numerical keys(%FRAGS)) == 2) &&
    460           1.1  kardel 		  (length($FRAGS{0}) + 8) > $x[$[+1]) ||
    461           1.1  kardel 		  (scalar(@x=sort numerical keys(%FRAGS)) < 2)))
    462           1.1  kardel 	    {
    463           1.1  kardel 		@x=((&pkt_E($r_e_m_op) ? &error_status($status) : ""),
    464           1.1  kardel 		    $FRAGS{0},@FRAGS);
    465           1.1  kardel 		&pkt_E($r_e_m_op) ? $STAT_err_frag++ : $STAT_frag_all++;
    466           1.1  kardel 		undef(%FRAGS);
    467           1.1  kardel 		undef(@FRAGS);
    468           1.1  kardel 		undef($lastseen);
    469           1.1  kardel 		delete $ID{$id};
    470           1.1  kardel 		&main'clear_timeout($id);
    471           1.1  kardel 		return @x;
    472           1.1  kardel 	    }
    473           1.1  kardel 	    else
    474           1.1  kardel 	    {
    475           1.1  kardel 		&main'set_timeout($id,time+$timeout,"&ntp'handle_packet_timeout(\"".unpack("H*",$id)."\");"); #'";
    476           1.1  kardel 	    }
    477           1.1  kardel 	}
    478           1.1  kardel 	return (undef);
    479           1.1  kardel     }
    480           1.1  kardel }
    481           1.1  kardel 
    482           1.1  kardel sub handle_packet_timeout
    483           1.1  kardel {
    484           1.1  kardel     local($id) = @_;
    485           1.1  kardel     local($r_e_m_op,*FRAGS,*lastseen,@x) = (@FRAGS[$[+5]);
    486           1.1  kardel     
    487           1.1  kardel     *FRAGS = "$id FRAGS";
    488           1.1  kardel     *lastseen = "$id lastseen";
    489           1.1  kardel     
    490           1.1  kardel     @x=((&pkt_E($r_e_m_op) ? &error_status($status) : "TIMEOUT"),
    491           1.1  kardel 	$FRAGS{0},@FRAGS[$[ .. $[+4]);
    492           1.1  kardel     $STAT_frag_timeout++;
    493           1.1  kardel     undef(%FRAGS);
    494           1.1  kardel     undef(@FRAGS);
    495           1.1  kardel     undef($lastseen);
    496           1.1  kardel     delete $ID{$id};
    497           1.1  kardel     return @x;
    498           1.1  kardel }
    499           1.1  kardel 
    500           1.1  kardel 
    501           1.1  kardel sub pad
    502           1.1  kardel {
    503           1.1  kardel     return $_[$[+1] * int(($_[$[] + $_[$[+1] - 1) / $_[$[+1]);
    504           1.1  kardel }
    505           1.1  kardel 
    506           1.1  kardel 1;
    507