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