182498Sroberto#!/usr/bin/perl -w
254359Sroberto;#
354359Sroberto;# ntp.pl,v 3.1 1993/07/06 01:09:09 jbj Exp
454359Sroberto;#
554359Sroberto;# process loop filter statistics file and either
654359Sroberto;#     - show statistics periodically using gnuplot
754359Sroberto;#     - or print a single plot
854359Sroberto;#
954359Sroberto;#  Copyright (c) 1992
1054359Sroberto;#  Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg
1154359Sroberto;#
1254359Sroberto;#
1354359Sroberto;#############################################################
1454359Sroberto
1554359Srobertopackage ntp;
1654359Sroberto
1754359Sroberto$NTP_version = 2;
1854359Sroberto$ctrl_mode=6;
1954359Sroberto
2054359Sroberto$byte1 = (($NTP_version & 0x7)<< 3) & 0x34 | ($ctrl_mode & 0x7);
2154359Sroberto$MAX_DATA = 468;
2254359Sroberto
2354359Sroberto$sequence = 0;			# initial sequence number incred before used
2454359Sroberto$pad=4;
2554359Sroberto$do_auth=0;			# no possibility today
2654359Sroberto$keyid=0;
2754359Sroberto;#list if known keys (passwords)
2854359Sroberto%KEYS = ( 0, "\200\200\200\200\200\200\200\200",
2954359Sroberto	 );
3054359Sroberto
3154359Sroberto;#-----------------------------------------------------------------------------
3254359Sroberto;# access routines for ntp control packet
3354359Sroberto    ;# NTP control message format
3454359Sroberto    ;#  C  LI|VN|MODE  LI 2bit=00  VN 3bit=2(3) MODE 3bit=6 : $byte1
3554359Sroberto    ;#  C  R|E|M|Op    R response  E error    M more   Op opcode
3654359Sroberto    ;#  n  sequence
3754359Sroberto    ;#  n  status
3854359Sroberto    ;#  n  associd
3954359Sroberto    ;#  n  offset
4054359Sroberto    ;#  n  count
4154359Sroberto    ;#  a+ data (+ padding)
4254359Sroberto    ;#  optional authentication data
4354359Sroberto    ;#  N  key
4454359Sroberto    ;#  N2 checksum
4554359Sroberto
4682498Sroberto;# first byte of packet
4754359Srobertosub pkt_LI   { return ($_[$[] >> 6) & 0x3; }
4854359Srobertosub pkt_VN   { return ($_[$[] >> 3) & 0x7; }
4954359Srobertosub pkt_MODE { return ($_[$[]     ) & 0x7; }
5054359Sroberto
5154359Sroberto;# second byte of packet
5254359Srobertosub pkt_R  { return ($_[$[] & 0x80) == 0x80; }
5354359Srobertosub pkt_E  { return ($_[$[] & 0x40) == 0x40; }
5454359Srobertosub pkt_M  { return ($_[$[] & 0x20) == 0x20; }
5554359Srobertosub pkt_OP { return $_[$[] & 0x1f; }
5654359Sroberto
5754359Sroberto;#-----------------------------------------------------------------------------
5854359Sroberto
5954359Srobertosub setkey
6054359Sroberto{
6154359Sroberto    local($id,$key) = @_;
6254359Sroberto
6354359Sroberto    $KEYS{$id} = $key if (defined($key));
6454359Sroberto    if (! defined($KEYS{$id}))
6554359Sroberto    {
6654359Sroberto	warn "Key $id not yet specified - key not changed\n";
6754359Sroberto	return undef;
6854359Sroberto    }
6954359Sroberto    return ($keyid,$keyid = $id)[$[];
7054359Sroberto}
7154359Sroberto
7254359Sroberto;#-----------------------------------------------------------------------------
7354359Srobertosub numerical { $a <=> $b; }
7454359Sroberto
7554359Sroberto;#-----------------------------------------------------------------------------
7654359Sroberto
7754359Srobertosub send	#'
7854359Sroberto{
7954359Sroberto    local($fh,$opcode, $associd, $data,$address) = @_;
8054359Sroberto    $fh = caller(0)."'$fh";
8154359Sroberto
8254359Sroberto    local($junksize,$junk,$packet,$offset,$ret);
8354359Sroberto    $offset = 0;
8454359Sroberto
8554359Sroberto    $sequence++;
8654359Sroberto    while(1)
8754359Sroberto    {
8854359Sroberto	$junksize = length($data);
8954359Sroberto	$junksize = $MAX_DATA if $junksize > $MAX_DATA;
9054359Sroberto
9154359Sroberto	($junk,$data) = $data =~ /^(.{$junksize})(.*)$/;
9254359Sroberto	$packet
9354359Sroberto	    = pack("C2n5a".(($junk eq "") ? 0 : &pad($junksize+12,$pad)-12),
9454359Sroberto		   $byte1,
9554359Sroberto		   ($opcode & 0x1f) | ($data ? 0x20 : 0),
9654359Sroberto		   $sequence,
9754359Sroberto		   0, $associd,
9854359Sroberto		   $offset, $junksize, $junk);
9954359Sroberto	if ($do_auth)
10054359Sroberto	{
10154359Sroberto	    ;# not yet
10254359Sroberto	}
10354359Sroberto	$offset += $junksize;
10454359Sroberto
10554359Sroberto	if (defined($address))
10654359Sroberto	{
10754359Sroberto	    $ret = send($fh, $packet, 0, $address);
10854359Sroberto	}
10954359Sroberto	else
11054359Sroberto	{
11154359Sroberto	    $ret = send($fh, $packet, 0);
11254359Sroberto	}
11354359Sroberto
11454359Sroberto	if (! defined($ret))
11554359Sroberto	{
11654359Sroberto	    warn "send failed: $!\n";
11754359Sroberto	    return undef;
11854359Sroberto	}
11954359Sroberto	elsif ($ret != length($packet))
12054359Sroberto	{
12154359Sroberto	    warn "send failed: sent only $ret from ".length($packet). "bytes\n";
12254359Sroberto	    return undef;
12354359Sroberto	}
12454359Sroberto	return $sequence unless $data;
12554359Sroberto    }
12654359Sroberto}
12754359Sroberto
12854359Sroberto;#-----------------------------------------------------------------------------
12954359Sroberto;# status interpretation
13054359Sroberto;#
13154359Srobertosub getval
13254359Sroberto{
13354359Sroberto    local($val,*list) = @_;
13454359Sroberto
13554359Sroberto    return $list{$val} if defined($list{$val});
13654359Sroberto    return sprintf("%s#%d",$list{"-"},$val) if defined($list{"-"});
13754359Sroberto    return "unknown-$val";
13854359Sroberto}
13954359Sroberto
14054359Sroberto;#---------------------------------
14154359Sroberto;# system status
14254359Sroberto;#
14354359Sroberto;# format: |LI|CS|SECnt|SECode| LI=2bit CS=6bit SECnt=4bit SECode=4bit
14454359Srobertosub ssw_LI     { return ($_[$[] >> 14) & 0x3; }
14554359Srobertosub ssw_CS     { return ($_[$[] >> 8)  & 0x3f; }
14654359Srobertosub ssw_SECnt  { return ($_[$[] >> 4)  & 0xf; }
14754359Srobertosub ssw_SECode { return $_[$[] & 0xf; }
14854359Sroberto
14954359Sroberto%LI = ( 0, "leap_none",  1, "leap_add_sec", 2, "leap_del_sec", 3, "sync_alarm", "-", "leap");
15054359Sroberto%ClockSource = (0, "sync_unspec",
151280849Scy		1, "sync_pps",
152280849Scy		2, "sync_lf_clock",
15354359Sroberto		3, "sync_hf_clock",
154280849Scy		4, "sync_uhf_clock",
155280849Scy		5, "sync_local_proto",
156280849Scy		6, "sync_ntp",
157280849Scy		7, "sync_udp/time",
158280849Scy		8, "sync_wristwatch",
159280849Scy		9, "sync_telephone",
16054359Sroberto		"-", "ClockSource",
16154359Sroberto		);
16254359Sroberto
16354359Sroberto%SystemEvent = (0, "event_unspec",
164280849Scy		1, "event_freq_not_set",
165280849Scy		2, "event_freq_set",
166280849Scy		3, "event_spike_detect",
167280849Scy		4, "event_freq_mode",
168280849Scy		5, "event_clock_sync",
169280849Scy		6, "event_restart",
170280849Scy		7, "event_panic_stop",
171280849Scy		8, "event_no_sys_peer",
172280849Scy		9, "event_leap_armed",
173280849Scy		10, "event_leap_disarmed",
174280849Scy		11, "event_leap_event",
175280849Scy		12, "event_clock_step",
176280849Scy		13, "event_kern",
177280849Scy		14, "event_loaded_leaps",
178280849Scy		15, "event_stale_leaps",
17954359Sroberto		"-", "event",
18054359Sroberto		);
18154359Srobertosub LI
18254359Sroberto{
18354359Sroberto    &getval(&ssw_LI($_[$[]),*LI);
18454359Sroberto}
18554359Srobertosub ClockSource
18654359Sroberto{
18754359Sroberto    &getval(&ssw_CS($_[$[]),*ClockSource);
18854359Sroberto}
18954359Sroberto
19054359Srobertosub SystemEvent
19154359Sroberto{
19254359Sroberto    &getval(&ssw_SECode($_[$[]),*SystemEvent);
19354359Sroberto}
19454359Sroberto
19554359Srobertosub system_status
19654359Sroberto{
19754359Sroberto    return sprintf("%s, %s, %d event%s, %s", &LI($_[$[]), &ClockSource($_[$[]),
19854359Sroberto		   &ssw_SECnt($_[$[]), ((&ssw_SECnt($_[$[])==1) ? "" : "s"),
19954359Sroberto		   &SystemEvent($_[$[]));
20054359Sroberto}
20154359Sroberto;#---------------------------------
20254359Sroberto;# peer status
20354359Sroberto;#
20454359Sroberto;# format: |PStat|PSel|PCnt|PCode| Pstat=6bit PSel=2bit PCnt=4bit PCode=4bit
20554359Srobertosub psw_PStat_config     { return ($_[$[] & 0x8000) == 0x8000; }
20654359Srobertosub psw_PStat_authenable { return ($_[$[] & 0x4000) == 0x4000; }
20754359Srobertosub psw_PStat_authentic  { return ($_[$[] & 0x2000) == 0x2000; }
20854359Srobertosub psw_PStat_reach      { return ($_[$[] & 0x1000) == 0x1000; }
209280849Scysub psw_PStat_bcast      { return ($_[$[] & 0x0800) == 0x0800; }
21054359Srobertosub psw_PStat { return ($_[$[] >> 10) & 0x3f; }
21154359Srobertosub psw_PSel  { return ($_[$[] >> 8)  & 0x3;  }
21254359Srobertosub psw_PCnt  { return ($_[$[] >> 4)  & 0xf; }
21354359Srobertosub psw_PCode { return $_[$[] & 0xf; }
21454359Sroberto
21554359Sroberto%PeerSelection = (0, "sel_reject",
216280849Scy		  1, "sel_falsetick",
217280849Scy		  2, "sel_excess",
218280849Scy		  3, "sel_outlier",
219280849Scy		  4, "sel_candidate",
220280849Scy		  5, "sel_backup",
221280849Scy		  6, "sel_sys.peer",
222280849Scy		  6, "sel_pps.peer",
22354359Sroberto		  "-", "PeerSel",
22454359Sroberto		  );
22554359Sroberto%PeerEvent = (0, "event_unspec",
226280849Scy	      1, "event_mobilize",
227280849Scy	      2, "event_demobilize",
22854359Sroberto	      3, "event_unreach",
22954359Sroberto	      4, "event_reach",
230280849Scy	      5, "event_restart",
231280849Scy	      6, "event_no_reply",
232280849Scy	      7, "event_rate_exceed",
233280849Scy	      8, "event_denied",
234280849Scy	      9, "event_leap_armed",
235280849Scy	      10, "event_sys_peer",
236280849Scy	      11, "event_clock_event",
237280849Scy	      12, "event_bad_auth",
238280849Scy	      13, "event_popcorn",
239280849Scy	      14, "event_intlv_mode",
240280849Scy	      15, "event_intlv_err",
24154359Sroberto	      "-", "event",
24254359Sroberto	      );
24354359Sroberto
24454359Srobertosub PeerSelection
24554359Sroberto{
24654359Sroberto    &getval(&psw_PSel($_[$[]),*PeerSelection);
24754359Sroberto}
24882498Sroberto
24954359Srobertosub PeerEvent
25054359Sroberto{
25154359Sroberto    &getval(&psw_PCode($_[$[]),*PeerEvent);
25254359Sroberto}
25354359Sroberto
25454359Srobertosub peer_status
25554359Sroberto{
25654359Sroberto    local($x) = ("");
25754359Sroberto    $x .= "config,"     if &psw_PStat_config($_[$[]);
25854359Sroberto    $x .= "authenable," if &psw_PStat_authenable($_[$[]);
25954359Sroberto    $x .= "authentic,"  if &psw_PStat_authentic($_[$[]);
26054359Sroberto    $x .= "reach,"      if &psw_PStat_reach($_[$[]);
261280849Scy    $x .= "bcast,"      if &psw_PStat_bcast($_[$[]);
26254359Sroberto
26354359Sroberto    $x .= sprintf(" %s, %d event%s, %s", &PeerSelection($_[$[]),
26454359Sroberto		  &psw_PCnt($_[$[]), ((&psw_PCnt($_[$[]) == 1) ? "" : "s"),
26554359Sroberto		  &PeerEvent($_[$[]));
26654359Sroberto    return $x;
26754359Sroberto}
26854359Sroberto
26954359Sroberto;#---------------------------------
27054359Sroberto;# clock status
27154359Sroberto;#
27254359Sroberto;# format: |CStat|CEvnt| CStat=8bit CEvnt=8bit
27354359Srobertosub csw_CStat { return ($_[$[] >> 8) & 0xff; }
27454359Srobertosub csw_CEvnt { return $_[$[] & 0xff; }
27554359Sroberto
27654359Sroberto%ClockStatus = (0, "clk_nominal",
27754359Sroberto		1, "clk_timeout",
27854359Sroberto		2, "clk_badreply",
27954359Sroberto		3, "clk_fault",
280280849Scy		4, "clk_badsig",
28154359Sroberto		5, "clk_baddate",
28254359Sroberto		6, "clk_badtime",
28354359Sroberto		"-", "clk",
28454359Sroberto	       );
28554359Sroberto
28654359Srobertosub clock_status
28754359Sroberto{
28854359Sroberto    return sprintf("%s, last %s",
28954359Sroberto		   &getval(&csw_CStat($_[$[]),*ClockStatus),
29054359Sroberto		   &getval(&csw_CEvnt($_[$[]),*ClockStatus));
29154359Sroberto}
29254359Sroberto
29354359Sroberto;#---------------------------------
29454359Sroberto;# error status
29554359Sroberto;#
29654359Sroberto;# format: |Err|reserved|  Err=8bit
29754359Sroberto;#
29854359Srobertosub esw_Err { return ($_[$[] >> 8) & 0xff; }
29954359Sroberto
30054359Sroberto%ErrorStatus = (0, "err_unspec",
30154359Sroberto		1, "err_auth_fail",
30254359Sroberto		2, "err_invalid_fmt",
30354359Sroberto		3, "err_invalid_opcode",
30454359Sroberto		4, "err_unknown_assoc",
30554359Sroberto		5, "err_unknown_var",
30654359Sroberto		6, "err_invalid_value",
30754359Sroberto		7, "err_adm_prohibit",
30854359Sroberto		);
30954359Sroberto
31054359Srobertosub error_status
31154359Sroberto{
31254359Sroberto    return sprintf("%s", &getval(&esw_Err($_[$[]),*ErrorStatus));
31354359Sroberto}
31454359Sroberto
31554359Sroberto;#-----------------------------------------------------------------------------
31654359Sroberto;#
31754359Sroberto;# cntrl op name translation
31854359Sroberto
319280849Scy%CntrlOpName = (0, "reserved",
320280849Scy		1, "read_status",
32154359Sroberto		2, "read_variables",
32254359Sroberto		3, "write_variables",
32354359Sroberto		4, "read_clock_variables",
32454359Sroberto		5, "write_clock_variables",
32554359Sroberto		6, "set_trap",
32654359Sroberto		7, "trap_response",
327280849Scy		8, "configure",
328280849Scy		9, "saveconf",
329280849Scy		10, "read_mru",
330280849Scy		11, "read_ordlist",
331280849Scy		12, "rqst_nonce",
33254359Sroberto		31, "unset_trap", # !!! unofficial !!!
33354359Sroberto		"-", "cntrlop",
33454359Sroberto		);
33554359Sroberto
33654359Srobertosub cntrlop_name
33754359Sroberto{
33854359Sroberto    return &getval($_[$[],*CntrlOpName);
33954359Sroberto}
34054359Sroberto
34154359Sroberto;#-----------------------------------------------------------------------------
34254359Sroberto
34354359Sroberto$STAT_short_pkt = 0;
34454359Sroberto$STAT_pkt = 0;
34554359Sroberto
34654359Sroberto;# process a NTP control message (response) packet
34754359Sroberto;# returns a list ($ret,$data,$status,$associd,$op,$seq,$auth_keyid)
34854359Sroberto;#      $ret: undef     --> not yet complete
34954359Sroberto;#            ""        --> complete packet received
35054359Sroberto;#            "ERROR"   --> error during receive, bad packet, ...
35154359Sroberto;#          else        --> error packet - list may contain useful info
35254359Sroberto
35354359Sroberto
35454359Srobertosub handle_packet
35554359Sroberto{
35654359Sroberto    local($pkt,$from) = @_;	# parameters
35754359Sroberto    local($len_pkt) = (length($pkt));
35854359Sroberto;#    local(*FRAGS,*lastseen);
35954359Sroberto    local($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data);
36054359Sroberto    local($autch_keyid,$auth_cksum);
36154359Sroberto
36254359Sroberto    $STAT_pkt++;
36354359Sroberto    if ($len_pkt < 12)
36454359Sroberto    {
36554359Sroberto	$STAT_short_pkt++;
36654359Sroberto	return ("ERROR","short packet received");
36754359Sroberto    }
36854359Sroberto
36954359Sroberto    ;# now break packet apart
37054359Sroberto    ($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data) =
37154359Sroberto	unpack("C2n5a".($len_pkt-12),$pkt);
37254359Sroberto    $data=substr($data,$[,$count);
37354359Sroberto    if ((($len_pkt - 12) - &pad($count,4)) >= 12)
37454359Sroberto    {
37554359Sroberto	;# looks like an authenticator
37654359Sroberto	($auth_keyid,$auth_cksum) =
37754359Sroberto	    unpack("Na8",substr($pkt,$len_pkt-12+$[,12));
37854359Sroberto	$STAT_auth++;
37954359Sroberto	;# no checking of auth_cksum (yet ?)
38054359Sroberto    }
38154359Sroberto
38254359Sroberto    if (&pkt_VN($li_vn_mode) != $NTP_version)
38354359Sroberto    {
38454359Sroberto	$STAT_bad_version++;
38554359Sroberto	return ("ERROR","version ".&pkt_VN($li_vn_mode)."packet ignored");
38654359Sroberto    }
38754359Sroberto
38854359Sroberto    if (&pkt_MODE($li_vn_mode) != $ctrl_mode)
38954359Sroberto    {
39054359Sroberto	$STAT_bad_mode++;
39154359Sroberto	return ("ERROR", "mode ".&pkt_MODE($li_vn_mode)." packet ignored");
39254359Sroberto    }
39354359Sroberto
39454359Sroberto    ;# handle single fragment fast
39554359Sroberto    if ($offset == 0 && &pkt_M($r_e_m_op) == 0)
39654359Sroberto    {
39754359Sroberto	$STAT_single_frag++;
39854359Sroberto	if (&pkt_E($r_e_m_op))
39954359Sroberto	{
40054359Sroberto	    $STAT_err_pkt++;
40154359Sroberto	    return (&error_status($status),
40254359Sroberto		    $data,$status,$associd,&pkt_OP($r_e_m_op),$seq,
40354359Sroberto		    $auth_keyid);
40454359Sroberto	}
40554359Sroberto	else
40654359Sroberto	{
40754359Sroberto	    return ("",
40854359Sroberto		    $data,$status,$associd,&pkt_OP($r_e_m_op),$seq,
40954359Sroberto		    $auth_keyid);
41054359Sroberto	}
41154359Sroberto    }
41254359Sroberto    else
41354359Sroberto    {
41454359Sroberto	;# fragment - set up local name space
41554359Sroberto	$id = "$from$seq".&pkt_OP($r_e_m_op);
41654359Sroberto	$ID{$id} = 1;
41754359Sroberto	*FRAGS = "$id FRAGS";
41854359Sroberto	*lastseen = "$id lastseen";
41954359Sroberto
42054359Sroberto	$STAT_frag++;
42154359Sroberto
42254359Sroberto	$lastseen = 1 if !&pkt_M($r_e_m_op);
423280849Scy	if (!%FRAGS)
42454359Sroberto	{
42582498Sroberto	    print((&pkt_M($r_e_m_op) ? " more" : "")."\n");
42654359Sroberto	    $FRAGS{$offset} = $data;
42754359Sroberto	    ;# save other info
42854359Sroberto	    @FRAGS = ($status,$associd,&pkt_OP($r_e_m_op),$seq,$auth_keyid,$r_e_m_op);
42954359Sroberto	}
43054359Sroberto	else
43154359Sroberto	{
43282498Sroberto	    print((&pkt_M($r_e_m_op) ? " more" : "")."\n");
43354359Sroberto	    ;# add frag to previous - combine on the fly
43454359Sroberto	    if (defined($FRAGS{$offset}))
43554359Sroberto	    {
43654359Sroberto		$STAT_dup_frag++;
43754359Sroberto		return ("ERROR","duplicate fragment at $offset seq=$seq");
43854359Sroberto	    }
43954359Sroberto
44054359Sroberto	    $FRAGS{$offset} = $data;
44154359Sroberto
44254359Sroberto	    undef($loff);
44354359Sroberto	    foreach $off (sort numerical keys(%FRAGS))
44454359Sroberto	    {
44554359Sroberto		next unless defined($FRAGS{$off});
44654359Sroberto		if (defined($loff) &&
44754359Sroberto		    ($loff + length($FRAGS{$loff})) == $off)
44854359Sroberto		{
44954359Sroberto		    $FRAGS{$loff} .= $FRAGS{$off};
45054359Sroberto		    delete $FRAGS{$off};
45154359Sroberto		    last;
45254359Sroberto		}
45354359Sroberto		$loff = $off;
45454359Sroberto	    }
45554359Sroberto
45654359Sroberto	    ;# return packet if all frags arrived
45754359Sroberto	    ;# at most two frags with possible padding ???
45854359Sroberto	    if ($lastseen && defined($FRAGS{0}) &&
45954359Sroberto		(((scalar(@x=sort numerical keys(%FRAGS)) == 2) &&
46054359Sroberto		  (length($FRAGS{0}) + 8) > $x[$[+1]) ||
46154359Sroberto		  (scalar(@x=sort numerical keys(%FRAGS)) < 2)))
46254359Sroberto	    {
46354359Sroberto		@x=((&pkt_E($r_e_m_op) ? &error_status($status) : ""),
46454359Sroberto		    $FRAGS{0},@FRAGS);
46554359Sroberto		&pkt_E($r_e_m_op) ? $STAT_err_frag++ : $STAT_frag_all++;
46654359Sroberto		undef(%FRAGS);
46754359Sroberto		undef(@FRAGS);
46854359Sroberto		undef($lastseen);
46954359Sroberto		delete $ID{$id};
47054359Sroberto		&main'clear_timeout($id);
47154359Sroberto		return @x;
47254359Sroberto	    }
47354359Sroberto	    else
47454359Sroberto	    {
47554359Sroberto		&main'set_timeout($id,time+$timeout,"&ntp'handle_packet_timeout(\"".unpack("H*",$id)."\");"); #'";
47654359Sroberto	    }
47754359Sroberto	}
47854359Sroberto	return (undef);
47954359Sroberto    }
48054359Sroberto}
48154359Sroberto
48254359Srobertosub handle_packet_timeout
48354359Sroberto{
48454359Sroberto    local($id) = @_;
48554359Sroberto    local($r_e_m_op,*FRAGS,*lastseen,@x) = (@FRAGS[$[+5]);
48654359Sroberto
48754359Sroberto    *FRAGS = "$id FRAGS";
48854359Sroberto    *lastseen = "$id lastseen";
48954359Sroberto
49054359Sroberto    @x=((&pkt_E($r_e_m_op) ? &error_status($status) : "TIMEOUT"),
49154359Sroberto	$FRAGS{0},@FRAGS[$[ .. $[+4]);
49254359Sroberto    $STAT_frag_timeout++;
49354359Sroberto    undef(%FRAGS);
49454359Sroberto    undef(@FRAGS);
49554359Sroberto    undef($lastseen);
49654359Sroberto    delete $ID{$id};
49754359Sroberto    return @x;
49854359Sroberto}
49954359Sroberto
50054359Sroberto
50154359Srobertosub pad
50254359Sroberto{
50354359Sroberto    return $_[$[+1] * int(($_[$[] + $_[$[+1] - 1) / $_[$[+1]);
50454359Sroberto}
50554359Sroberto
50654359Sroberto1;
507