1#!/usr/bin/perl
2
3my $debug = 0;
4# 0: off
5# 1: specific debug
6# 2: full debug
7
8#
9# verify that display filter names correspond with the PROTABBREV of
10# of the dissector.  Enforces the dissector to have a source
11# filename of format packet-PROTABBREV.c
12#
13# Usage: checkfiltername.pl <file or files>
14
15#
16# Copyright 2011 Michael Mann (see AUTHORS file)
17#
18# Wireshark - Network traffic analyzer
19# By Gerald Combs <gerald@wireshark.org>
20# Copyright 1998 Gerald Combs
21#
22# SPDX-License-Identifier: GPL-2.0-or-later
23
24#
25# Example:
26# ~/work/wireshark/trunk/epan/dissectors> ../../tools/checkfiltername.pl packet-3com-xns.c
27# packet-3com-xns.c (2 (of 2) fields)
28# 102 3comxns.type doesn't match PROTOABBREV of 3com-xns
29# 106 3comxns.type doesn't match PROTOABBREV of 3com-xns
30#
31# or checkfiltername.pl packet-*.c, which will check all the dissector files.
32#
33#
34
35use warnings;
36use strict;
37use Getopt::Long;
38
39my @elements;
40my @elements_dup;
41my @protocols;
42my %filters;
43my %expert_filters;
44my @acceptedprefixes = ("dcerpc-");
45my @asn1automatedfilelist;
46my @dcerpcautomatedfilelist;
47my @idl2wrsautomatedfilelist;
48my @filemanipulationfilelist;
49my @prefixfilelist;
50my @nofieldfilelist;
51my %unique;
52my @uniquefilelist;
53my @noregprotocolfilelist;
54my @periodinfilternamefilelist;
55
56my $showlinenoFlag = '';
57my $showautomatedFlag = '';
58
59my $state = "";
60# "s_unknown",
61# "s_start",
62# "s_in_hf_register_info",
63# "s_hf_register_info_entry",
64# "s_header_field_info_entry",
65# "s_header_field_info_entry_start",
66# "s_header_field_info_entry_name",
67# "s_header_field_info_entry_abbrev",
68# "s_header_field_info_entry_abbrev_end",
69# "s_start_expert",
70# "s_in_ei_register_info",
71# "s_ei_register_info_entry",
72# "s_ei_register_info_entry_start",
73# "s_ei_register_info_entry_abbrev_end",
74# "s_nofields"
75
76my $restofline;
77my $filecount = 0;
78my $currfile = "";
79my $protabbrev = "";
80my $protabbrev_index;
81my $PFNAME_value = "";
82my $linenumber = 1;
83my $totalerrorcount = 0;
84my $errorfilecount = 0;
85my $onefield = 0;
86my $nofields = 0;
87my $noperiod = 0;
88my $noregprotocol = 1;
89my $automated = 0;
90my $more_tokens;
91my $showall = 0;
92
93my $comment = 0;
94
95sub checkprotoabbrev {
96	my $abbrev = "";
97	my $abbrevpos;
98	my $proto_abbrevpos1;
99	my $proto_abbrevpos2;
100	my $afterabbrev = "";
101	my $check_dup_abbrev = "";
102	my $modprotabbrev = "";
103	my $errorline = 0;
104	my $prefix;
105
106	if (($automated == 0) || ($showall == 1)) {
107		$abbrevpos = index($_[0], ".");
108		if ($abbrevpos == -1) {
109			$abbrev = $_[0];
110		}
111		else {
112			$abbrev = substr($_[0], 0, $abbrevpos);
113			$afterabbrev = substr($_[0], $abbrevpos+1, length($_[0])-$abbrevpos);
114			$check_dup_abbrev = $afterabbrev;
115			$afterabbrev = substr($afterabbrev, 0, length($abbrev));
116		}
117
118		if ($abbrev ne $protabbrev) {
119			$errorline = 1;
120
121			#check if there is a supported protocol that matches the abbrev.
122			#This may be a case of filename != PROTOABBREV
123			foreach (@protocols) {
124				if ($abbrev eq $_) {
125					$errorline = 0;
126				} elsif (index($_, ".") != -1) {
127
128					#compare from start of string for each period found
129					$proto_abbrevpos1 = 0;
130					while ((($proto_abbrevpos2 = index($_, ".", $proto_abbrevpos1)) != -1) &&
131							($errorline == 1)) {
132						if ($abbrev eq substr($_, 0, $proto_abbrevpos2)) {
133							$errorline = 0;
134						}
135
136						$proto_abbrevpos1 = $proto_abbrevpos2+1;
137					}
138				}
139			}
140		}
141
142		# find any underscores that preface or follow a period
143		if (((index($_[0], "._") >= 0) || (index($_[0], "_.") >= 0)) &&
144			#ASN.1 dissectors can intentionally generating this field name, so don't fault the dissector
145			(index($_[0], "_untag_item_element") < 0)) {
146			if ($showlinenoFlag) {
147				push(@elements, "$_[1] $_[0] contains an unnecessary \'_\'\n");
148			} else {
149				push(@elements, "$_[0] contains an unnecessary \'_\'\n");
150			}
151		}
152
153		if (($errorline == 1) && ($showall == 0)) {
154			#try some "accepted" variations of PROTOABBREV
155
156			#replace '-' with '_'
157			$modprotabbrev = $protabbrev;
158			$modprotabbrev =~ s/-/_/g;
159			if ($abbrev eq $modprotabbrev) {
160				$errorline = 0;
161			}
162
163			#remove '-'
164			if ($errorline == 1) {
165				$modprotabbrev = $protabbrev;
166				$modprotabbrev =~ s/-//g;
167				if ($abbrev eq $modprotabbrev) {
168					$errorline = 0;
169				}
170			}
171
172			#remove '_'
173			if ($errorline == 1) {
174				$modprotabbrev = $protabbrev;
175				$modprotabbrev =~ s/_//g;
176				if ($abbrev eq $modprotabbrev) {
177					$errorline = 0;
178				}
179			}
180
181			if ($errorline == 1) {
182				#remove any "accepted" prefix to see if there is still a problem
183				foreach (@acceptedprefixes) {
184					if ($protabbrev =~ /^$_/) {
185						$modprotabbrev = substr($protabbrev, length($_));
186						if ($abbrev eq $modprotabbrev) {
187							push(@prefixfilelist, "$currfile\n");
188							$errorline = 0;
189						}
190					}
191				}
192			}
193			else {
194				push(@filemanipulationfilelist, "$currfile\n");
195			}
196
197			#now check the acceptable "fields from a different protocol"
198			if ($errorline == 1) {
199				if (is_from_other_protocol_allowed($_[0], $currfile) == 1) {
200					$errorline = 0;
201				}
202			}
203
204			#now check the acceptable "fields that include a version number"
205			if ($errorline == 1) {
206				if (is_protocol_version_allowed($_[0], $currfile) == 1) {
207					$errorline = 0;
208				}
209			}
210		}
211
212		if ($errorline == 1) {
213			$debug>1 && print "$_[1] $_[0] doesn't match PROTOABBREV of $protabbrev\n";
214			if ($showlinenoFlag) {
215				push(@elements, "$_[1] $_[0] doesn't match PROTOABBREV of $protabbrev\n");
216			} else {
217				push(@elements, "$_[0] doesn't match PROTOABBREV of $protabbrev\n");
218			}
219		}
220
221		if (($abbrev ne "") && (lc($abbrev) eq lc($afterabbrev))) {
222			# Allow ASN.1 generated files to duplicate part of proto name
223			if ((!(grep {$currfile eq $_ } @asn1automatedfilelist))   &&
224				# Check allowed list
225				(is_proto_dup_allowed($abbrev, $check_dup_abbrev) == 0)) {
226				if ($showlinenoFlag) {
227					push(@elements_dup, "$_[1] $_[0] duplicates PROTOABBREV of $abbrev\n");
228				} else {
229					push(@elements_dup, "$_[0] duplicates PROTOABBREV of $abbrev\n");
230				}
231			}
232		}
233	}
234}
235
236sub printprevfile {
237	my $totalfields = keys(%filters);
238	my $count_ele;
239	my $count_dup;
240	my $total_count;
241
242	foreach (sort keys %filters) {
243		checkprotoabbrev ($filters{$_}, $_);
244	}
245
246	foreach (sort keys %expert_filters) {
247		checkprotoabbrev ($expert_filters{$_}, $_);
248	}
249
250	$count_ele = @elements;
251	$count_dup = @elements_dup;
252	$total_count = $count_ele+$count_dup;
253
254	if ($noregprotocol == 1) {
255		#if no protocol is registered, only worry about duplicates
256		if ($currfile ne "") {
257			push(@noregprotocolfilelist, "$currfile\n");
258		}
259
260		if ($count_dup > 0) {
261			$errorfilecount++;
262			$totalerrorcount += $count_dup;
263		}
264
265		if (($showall == 1) || ($count_dup > 0))  {
266			print "\n\n$currfile  - NO PROTOCOL REGISTERED\n";
267			if ($showall == 1) {
268				#everything is included, so count all errors
269				$totalerrorcount += $count_ele;
270				if (($count_ele > 0) && ($count_dup == 0)) {
271					$errorfilecount++;
272				}
273
274				foreach (@elements) {
275					print $_;
276				}
277			}
278			foreach (@elements_dup) {
279				print $_;
280			}
281		}
282	} else {
283		if ($total_count > 0) {
284			$errorfilecount++;
285			$totalerrorcount += $total_count;
286		}
287
288		if (($automated == 0) || ($showall == 1)) {
289			if ($total_count > 0) {
290				if ($automated == 1) {
291					if ($showall == 1) {
292						print "\n\n$currfile - AUTOMATED ($total_count (of $totalfields) fields)\n";
293					}
294				} else {
295					print "\n\n$currfile ($total_count (of $totalfields) fields)\n";
296				}
297
298				foreach (@elements) {
299					print $_;
300				}
301				foreach (@elements_dup) {
302					print $_;
303				}
304			}
305
306			if ((($nofields) || ($totalfields == 0)) && ($currfile ne "")) {
307				if ($showall == 1) {
308					print "\n\n$currfile  - NO FIELDS\n";
309				}
310				push(@nofieldfilelist, "$currfile\n");
311			}
312		}
313	}
314}
315
316#--------------------------------------------------------------------
317# This is a list of dissectors that intentionally have filter names
318# where the second segment duplicates (at least partially) the name
319# of the first.  The most common case is in ASN.1 dissectors, but
320# those can be dealt with by looking at the first few lines of the
321# dissector. This list has been vetted and justification will need
322# to be provided to add to it. Acknowledge these dissectors aren't
323# a problem for the pre-commit script
324#--------------------------------------------------------------------
325sub is_proto_dup_allowed {
326	if (($_[0] eq "amf") && (index($_[1], "amf0") >= 0)) {return 1;}
327	if (($_[0] eq "amf") && (index($_[1], "amf3") >= 0)) {return 1;}
328	if (($_[0] eq "amqp") && (index($_[1], "amqp") >= 0)) {return 1;}
329	if (($_[0] eq "bat") && (index($_[1], "batman") >= 0)) {return 1;}
330	if (($_[0] eq "browser") && (index($_[1], "browser_") >= 0)) {return 1;}
331	if (($_[0] eq "dlsw") && (index($_[1], "dlsw_version") >= 0)) {return 1;}
332	if (($_[0] eq "dns") && (index($_[1], "dnskey") >= 0)) {return 1;}
333	if (($_[0] eq "ecmp") && (index($_[1], "ecmp_") >= 0)) {return 1;}
334	if (($_[0] eq "exported_pdu") && (index($_[1], "exported_pdu") >= 0)) {return 1;}
335	if (($_[0] eq "fc") && (index($_[1], "fctl") >= 0)) {return 1;}
336	if (($_[0] eq "fcs") && (index($_[1], "fcsmask") >= 0)) {return 1;}
337	if (($_[0] eq "fmp") && (index($_[1], "fmp") >= 0)) {return 1;}
338	if (($_[0] eq "fr") && (index($_[1], "frame_relay") >= 0)) {return 1;}
339	if (($_[0] eq "lustre") && (index($_[1], "lustre_") >= 0)) {return 1;}
340	if (($_[0] eq "mac") && (index($_[1], "macd") >= 0)) {return 1;}
341	if (($_[0] eq "mac") && (index($_[1], "macis") >= 0)) {return 1;}
342	if (($_[0] eq "mih") && (index($_[1], "mihf") >= 0)) {return 1;}
343	if (($_[0] eq "mih") && (index($_[1], "mihcap") >= 0)) {return 1;}
344	if (($_[0] eq "ncp") && (index($_[1], "ncp") >= 0)) {return 1;}
345	if (($_[0] eq "nfs") && (index($_[1], "nfs") >= 0)) {return 1;}
346	if (($_[0] eq "oxid") && (index($_[1], "oxid") >= 0)) {return 1;}
347	if (($_[0] eq "rquota") && (index($_[1], "rquota") >= 0)) {return 1;}
348	if (($_[0] eq "pfcp") && (index($_[1], "pfcp") >= 0)) {return 1;}
349	if (($_[0] eq "sm") && (index($_[1], "sm_") >= 0)) {return 1;}
350	if (($_[0] eq "smpp") && (index($_[1], "smppplus") >= 0)) {return 1;}
351	if (($_[0] eq "spray") && (index($_[1], "sprayarr") >= 0)) {return 1;}
352	if (($_[0] eq "tds") && (index($_[1], "tds_") >= 0)) {return 1;}
353	if (($_[0] eq "time") && (index($_[1], "time") >= 0)) {return 1;}
354	if (($_[0] eq "tn3270") && (index($_[1], "tn3270e") >= 0)) {return 1;}
355	if (($_[0] eq "usb") && (index($_[1], "usb") >= 0)) {return 1;}
356	if (($_[0] eq "xml") && (index($_[1], "xml") >= 0)) {return 1;}
357
358	return 0;
359}
360
361#--------------------------------------------------------------------
362# This is a list of dissectors that intentionally have filter names
363# shared with other dissectors.  This list has been vetted and
364# justification will need to be provided to add to it.
365# Acknowledge these dissectors aren't a problem for the pre-commit script
366#--------------------------------------------------------------------
367sub is_from_other_protocol_allowed {
368	my $proto_filename;
369	my $dir_index = rindex($_[1], "\\");
370
371	#handle directory names on all platforms
372	if ($dir_index < 0) {
373		$dir_index = rindex($_[1], "/");
374	}
375
376	if ($dir_index < 0) {
377		$proto_filename = $_[1];
378	}
379	else {
380		$proto_filename = substr($_[1], $dir_index+1);
381	}
382
383	# XXX - may be faster to hash this (note 1-many relationship)?
384	if (($proto_filename eq "packet-atalk.c") && (index($_[0], "llc") >= 0)) {return 1;}
385	if (($proto_filename eq "packet-awdl.c") && (index($_[0], "llc") >= 0)) {return 1;}
386	if (($proto_filename eq "packet-bpdu.c") && (index($_[0], "mstp") >= 0)) {return 1;}
387	if (($proto_filename eq "packet-bssap.c") && (index($_[0], "bsap") >= 0)) {return 1;}
388	if (($proto_filename eq "packet-caneth.c") && (index($_[0], "can") >= 0)) {return 1;}
389	if (($proto_filename eq "packet-cimetrics.c") && (index($_[0], "llc") >= 0)) {return 1;}
390	if (($proto_filename eq "packet-cipsafety.c") && (index($_[0], "cip") >= 0)) {return 1;}
391	if (($proto_filename eq "packet-cipsafety.c") && (index($_[0], "enip") >= 0)) {return 1;}
392	if (($proto_filename eq "packet-dcerpc-netlogon.c") && (index($_[0], "ntlmssp") >= 0)) {return 1;}
393	if (($proto_filename eq "packet-dcom-oxid.c") && (index($_[0], "dcom") >= 0)) {return 1;}
394	if (($proto_filename eq "packet-dvb-data-mpe.c") && (index($_[0], "mpeg_sect") >= 0)) {return 1;}
395	if (($proto_filename eq "packet-dvb-ipdc.c") && (index($_[0], "ipdc") >= 0)) {return 1;}
396	if (($proto_filename eq "packet-enip.c") && (index($_[0], "cip") >= 0)) {return 1;}
397	if (($proto_filename eq "packet-extreme.c") && (index($_[0], "llc") >= 0)) {return 1;}
398	if (($proto_filename eq "packet-fmp_notify.c") && (index($_[0], "fmp") >= 0)) {return 1;}
399	if (($proto_filename eq "packet-foundry.c") && (index($_[0], "llc") >= 0)) {return 1;}
400	if (($proto_filename eq "packet-glusterfs.c") && (index($_[0], "gluster") >= 0)) {return 1;}
401	if (($proto_filename eq "packet-h248_annex_e.c") && (index($_[0], "h248") >= 0)) {return 1;}
402	if (($proto_filename eq "packet-h248_q1950.c") && (index($_[0], "h248") >= 0)) {return 1;}
403	if (($proto_filename eq "packet-ieee1722.c") && (index($_[0], "can") >= 0)) {return 1;}
404	if (($proto_filename eq "packet-ieee80211.c") && (index($_[0], "eapol") >= 0)) {return 1;}
405	if (($proto_filename eq "packet-ieee80211-radio.c") && (index($_[0], "wlan") >= 0)) {return 1;}
406	if (($proto_filename eq "packet-ieee80211-wlancap.c") && (index($_[0], "wlan") >= 0)) {return 1;}
407	if (($proto_filename eq "packet-ieee802154.c") && (index($_[0], "wpan") >= 0)) {return 1;}
408	if (($proto_filename eq "packet-isup.c") && (index($_[0], "ansi_isup") >= 0)) {return 1;}
409	if (($proto_filename eq "packet-isup.c") && (index($_[0], "bat_ase") >= 0)) {return 1;}
410	if (($proto_filename eq "packet-isup.c") && (index($_[0], "nsap") >= 0)) {return 1;}
411	if (($proto_filename eq "packet-isup.c") && (index($_[0], "x213") >= 0)) {return 1;}
412	if (($proto_filename eq "packet-iwarp-ddp-rdmap.c") && (index($_[0], "iwarp_ddp") >= 0)) {return 1;}
413	if (($proto_filename eq "packet-iwarp-ddp-rdmap.c") && (index($_[0], "iwarp_rdma") >= 0)) {return 1;}
414	if (($proto_filename eq "packet-k12.c") && (index($_[0], "aal2") >= 0)) {return 1;}
415	if (($proto_filename eq "packet-k12.c") && (index($_[0], "atm") >= 0)) {return 1;}
416	if (($proto_filename eq "packet-m3ua.c") && (index($_[0], "mtp3") >= 0)) {return 1;}
417	if (($proto_filename eq "packet-mle.c") && (index($_[0], "wpan") >= 0)) {return 1;}
418	if (($proto_filename eq "packet-mpeg-dsmcc.c") && (index($_[0], "mpeg_sect") >= 0)) {return 1;}
419	if (($proto_filename eq "packet-mpeg-dsmcc.c") && (index($_[0], "etv.dsmcc") >= 0)) {return 1;}
420	if (($proto_filename eq "packet-mpeg1.c") && (index($_[0], "rtp.payload_mpeg_") >= 0)) {return 1;}
421	if (($proto_filename eq "packet-mysql.c") && (index($_[0], "mariadb") >= 0)) {return 1;}
422	if (($proto_filename eq "packet-ndps.c") && (index($_[0], "spx.ndps_") >= 0)) {return 1;}
423	if (($proto_filename eq "packet-pw-atm.c") && (index($_[0], "atm") >= 0)) {return 1;}
424	if (($proto_filename eq "packet-pw-atm.c") && (index($_[0], "pw") >= 0)) {return 1;}
425	if (($proto_filename eq "packet-scsi.c") && (index($_[0], "scsi_sbc") >= 0)) {return 1;}
426	if (($proto_filename eq "packet-sndcp-xid.c") && (index($_[0], "llcgprs") >= 0)) {return 1;}
427	if (($proto_filename eq "packet-wlccp.c") && (index($_[0], "llc") >= 0)) {return 1;}
428	if (($proto_filename eq "packet-wps.c") && (index($_[0], "eap") >= 0)) {return 1;}
429	if (($proto_filename eq "packet-wsp.c") && (index($_[0], "wap") >= 0)) {return 1;}
430	if (($proto_filename eq "packet-xot.c") && (index($_[0], "x25") >= 0)) {return 1;}
431	if (($proto_filename eq "packet-zbee-zcl-misc.c") && (index($_[0], "zbee_zcl_hvac") >= 0)) {return 1;}
432	if (($proto_filename eq "packet-zbee-zcl-misc.c") && (index($_[0], "zbee_zcl_ias") >= 0)) {return 1;}
433
434	#Understand why, but I think it could be prefixed with "dissector"
435	#prefix (which isn't necessarily "protocol")
436	if (($proto_filename eq "packet-rtcp.c") && (index($_[0], "srtcp") >= 0)) {return 1;}
437	if (($proto_filename eq "packet-rtp.c") && (index($_[0], "srtp") >= 0)) {return 1;}
438	if (($proto_filename eq "packet-dcom-cba-acco.c") && (index($_[0], "cba") >= 0)) {return 1;}
439	if (($proto_filename eq "packet-dcom-cba.c") && (index($_[0], "cba") >= 0)) {return 1;}
440
441	#XXX - HACK to get around nested "s in field name
442	if (($proto_filename eq "packet-gsm_sim.c") && (index($_[0], "e\\") >= 0)) {return 1;}
443
444	return 0;
445}
446
447#--------------------------------------------------------------------
448# This is a list of dissectors that use their (protocol) version number
449# as part of the first display filter segment, which checkfiltername
450# usually complains about. Manually allow them so that they can pass
451# pre-commit script
452#--------------------------------------------------------------------
453sub is_protocol_version_allowed {
454	my $proto_filename;
455	my $dir_index = rindex($_[1], "\\");
456
457	#handle directory names on all platforms
458	if ($dir_index < 0) {
459		$dir_index = rindex($_[1], "/");
460	}
461
462	if ($dir_index < 0) {
463		$proto_filename = $_[1];
464	}
465	else {
466		$proto_filename = substr($_[1], $dir_index+1);
467	}
468
469	# XXX - may be faster to hash this?
470	if (($proto_filename eq "packet-ehs.c") && (index($_[0], "ehs2") >= 0)) {return 1;}
471	if (($proto_filename eq "packet-hsrp.c") && (index($_[0], "hsrp2") >= 0)) {return 1;}
472	if (($proto_filename eq "packet-ipv6.c") && (index($_[0], "ip") >= 0)) {return 1;}
473	if (($proto_filename eq "packet-openflow_v1.c") && (index($_[0], "openflow") >= 0)) {return 1;}
474	if (($proto_filename eq "packet-rtnet.c") && (index($_[0], "tdma-v1") >= 0)) {return 1;}
475	if (($proto_filename eq "packet-scsi-osd.c") && (index($_[0], "scsi_osd2") >= 0)) {return 1;}
476	if (($proto_filename eq "packet-sflow.c") && (index($_[0], "sflow_5") >= 0)) {return 1;}
477	if (($proto_filename eq "packet-sflow.c") && (index($_[0], "sflow_245") >= 0)) {return 1;}
478	if (($proto_filename eq "packet-tipc.c") && (index($_[0], "tipcv2") >= 0)) {return 1;}
479	if (($proto_filename eq "packet-bluetooth.c") && (index($_[0], "llc.bluetooth_pid") >= 0)) {return 1;}
480
481	return 0;
482}
483
484# ---------------------------------------------------------------------
485#
486# MAIN
487#
488GetOptions(
489		   'showlineno'    => \$showlinenoFlag,
490		   'showautomated' => \$showautomatedFlag,
491		  );
492
493while (<>) {
494	if ($currfile !~ /$ARGV/) {
495		&printprevfile();
496
497		# New file - reset array and state
498		$filecount++;
499		$currfile = $ARGV;
500
501		#determine PROTABBREV for dissector based on file name format of (dirs)/packet-PROTABBREV.c or (dirs)/file-PROTABBREV.c
502		$protabbrev_index = rindex($currfile, "packet-");
503		if ($protabbrev_index == -1) {
504			$protabbrev_index = rindex($currfile, "file-");
505			if ($protabbrev_index == -1) {
506				#ignore "non-dissector" files
507				next;
508			}
509
510			$protabbrev = substr($currfile, $protabbrev_index+length("file-"));
511			$protabbrev_index = rindex($protabbrev, ".");
512			if ($protabbrev_index == -1) {
513				print "$currfile doesn't fit format of file-PROTABBREV.c\n";
514				next;
515			}
516		} else {
517			$protabbrev = substr($currfile, $protabbrev_index+length("packet-"));
518			$protabbrev_index = rindex($protabbrev, ".");
519			if ($protabbrev_index == -1) {
520				print "$currfile doesn't fit format of packet-PROTABBREV.c\n";
521				next;
522			}
523		}
524		$protabbrev = substr($protabbrev, 0, $protabbrev_index);
525
526		$PFNAME_value = "";
527		$noregprotocol = 1;
528		$automated = 0;
529		$nofields = 0;
530		$onefield = 0;
531		$noperiod = 0;
532		$linenumber = 1;
533		%filters = ( );
534		%expert_filters = ( );
535		@protocols = ( );
536		@elements = ( );
537		@elements_dup = ( );
538		$state = "s_unknown";
539	}
540
541	if (($automated == 0) && ($showautomatedFlag eq "")) {
542		#DCERPC automated files
543		if ($_ =~ "DO NOT EDIT") {
544			push(@dcerpcautomatedfilelist, "$currfile\n");
545			$automated = 1;
546			next;
547		}
548		#ASN.1 automated files
549		elsif ($_ =~ "Generated automatically by the ASN.1 to Wireshark dissector compiler") {
550			push(@asn1automatedfilelist, "$currfile\n");
551			$automated = 1;
552			next;
553		}
554		#idl2wrs automated files
555		elsif ($_ =~ "Autogenerated from idl2wrs") {
556			push(@idl2wrsautomatedfilelist, "$currfile\n");
557			$automated = 1;
558			next;
559		}
560	}
561
562	# opening then closing comment
563	if (/(.*?)\/\*.*\*\/(.*)/) {
564		$comment = 0;
565		$_ = "$1$2";
566	# closing then opening comment
567	} elsif (/.*?\*\/(.*?)\/\*/) {
568		$comment = 1;
569		$_ = "$1";
570	# opening comment
571	} elsif (/(.*?)\/\*/) {
572		$comment = 1;
573		$_ = "$1";
574	# closing comment
575	} elsif (/\*\/(.*?)/) {
576		$comment = 0;
577		$_ = "$1";
578	} elsif ($comment == 1) {
579		$linenumber++;
580		next;
581	}
582	# unhandled: more than one complete comment per line
583
584	chomp;
585
586	#proto_register_protocol state machine
587	$restofline = $_;
588	$more_tokens = 1;
589
590	#PFNAME is a popular #define for the proto filter name, so use it for testing
591	if ($restofline =~ /#define\s*PFNAME\s*\"([^\"]*)\"/) {
592		$PFNAME_value = $1;
593		$debug>1 && print "PFNAME: '$1'\n";
594	}
595
596	until ($more_tokens == 0) {
597		if (($restofline =~ /proto_register_protocol\s*\((.*)/) ||
598			($restofline =~ /proto_register_protocol_in_name_only\s*\((.*)/)) {
599			$noregprotocol = 0;
600			$restofline = $1;
601			$state = "s_proto_start";
602		} elsif (($state eq "s_proto_start") && ($restofline =~ /^(\s*\"([^\"]*)\"\s*,)\s*(.*)/)) {
603			$restofline = $3;
604			$state = "s_proto_long_name";
605			$debug>1 && print "proto long name: '$2'\n";
606		} elsif (($state eq "s_proto_start") && ($restofline =~ /^(\s*(([\w\d])+)\s*,)\s*(.*)/)) {
607			$restofline = $4;
608			$state = "s_proto_long_name";
609			$debug>1 && print "proto long name: '$2'\n";
610		} elsif (($state eq "s_proto_long_name") && ($restofline =~ /^(\s*\"([^\"]*)\"\s*,)\s*(.*)/)) {
611			$restofline = $3;
612			$state = "s_proto_short_name";
613			$debug>1 && print "proto short name: '$2'\n";
614		} elsif (($state eq "s_proto_long_name") && ($restofline =~ /^(\s*(([\w\d])+)\s*,)\s*(.*)/)) {
615			$restofline = $4;
616			$state = "s_proto_short_name";
617			$debug>1 && print "proto short name: '$2'\n";
618		} elsif (($state eq "s_proto_short_name") && ($restofline =~ /\s*PFNAME\s*(.*)/)) {
619			$more_tokens = 0;
620			$state = "s_proto_filter_name";
621			if ((index($PFNAME_value, ".") != -1) && ($noperiod == 0)) {
622				push(@periodinfilternamefilelist, "$currfile\n");
623				$noperiod = 1;
624			}
625			push(@protocols, $PFNAME_value);
626			$debug>1 && print "proto filter name: '$PFNAME_value'\n";
627		} elsif (($state eq "s_proto_short_name") && ($restofline =~ /\s*\"([^\"]*)\"\s*(.*)/)) {
628			$more_tokens = 0;
629			$state = "s_proto_filter_name";
630			if ((index($1, ".") != -1) && ($noperiod == 0)) {
631				push(@periodinfilternamefilelist, "$currfile\n");
632				$noperiod = 1;
633			}
634			push(@protocols, $1);
635			$debug>1 && print "proto filter name: '$1'\n";
636		} elsif (($state eq "s_proto_short_name") && ($restofline =~ /\s*(([\w\d])+)\s*(.*)/)) {
637			$more_tokens = 0;
638			$state = "s_proto_filter_name";
639			$debug>1 && print "proto filter name: '$1'\n";
640		} else {
641			$more_tokens = 0;
642		}
643	}
644
645	#retrieving display filters state machine
646	$restofline = $_;
647	$more_tokens = 1;
648	until ($more_tokens == 0) {
649		if ($restofline =~ /\s*static\s*hf_register_info\s*(\w+)\[\](.*)/) {
650			$restofline = $2;
651			$state = "s_start";
652			$debug>1 && print "$linenumber $state\n";
653		} elsif ($restofline =~ /\s*static\s*ei_register_info\s*(\w+)\[\](.*)/) {
654			$restofline = $2;
655			$state = "s_start_expert";
656			$debug>1 && print "$linenumber $state\n";
657		} elsif (($state eq "s_start") && ($restofline =~ /\W+{(.*)/)) {
658			$restofline = $1;
659			$state = "s_in_hf_register_info";
660			$debug>1 && print "$linenumber $state\n";
661		} elsif (($state eq "s_in_hf_register_info") && ($restofline =~ /\W+{(.*)/)) {
662			$restofline = $1;
663			$state = "s_hf_register_info_entry";
664			$debug>1 && print "$linenumber $state\n";
665			$onefield = 1;
666		} elsif (($state eq "s_in_hf_register_info") && ($restofline =~ /\s*};(.*)/)) {
667			$restofline = $1;
668			if ($onefield == 0) {
669				$debug && print "$linenumber NO FIELDS!!!\n";
670				$nofields =	1;
671				$state = "s_nofields";
672				$more_tokens = 0;
673			} else {
674				$state = "s_unknown";
675			}
676		} elsif (($state eq "s_hf_register_info_entry") && ($restofline =~ /\s*&\s*(hf_\w*(\[w*\])?)\s*,?(.*)/)) {
677			$restofline = $3;
678			$debug>1 && print "$linenumber hf_register_info_entry: $1\n";
679			$state = "s_header_field_info_entry";
680		} elsif (($state eq "s_header_field_info_entry") && ($restofline =~ /\s*{(.*)/)) {
681			$restofline = $1;
682			$state = "s_header_field_info_entry_start";
683			$debug>1 && print "$linenumber $state\n";
684		} elsif (($state eq "s_header_field_info_entry_start") && ($restofline =~ /((\"([^\"]*)\")|(\w+))\s*,(.*)/)) {
685			$restofline = $5;
686			$debug>1 && print "$linenumber header_field_info_entry_name: $1\n";
687			$state = "s_header_field_info_entry_name";
688		} elsif (($state eq "s_header_field_info_entry_name") && ($restofline =~ /\"([^\"]*)\"\s*,?(.*)/)) {
689			$restofline = $2;
690			$debug>1 && print "$linenumber header_field_info_entry_abbrev: $1\n";
691			$state = "s_header_field_info_entry_abbrev";
692			$filters{$linenumber} = $1;
693		} elsif (($state eq "s_header_field_info_entry_abbrev") && ($restofline =~ /[^}]*}(.*)/)) {
694			$restofline = $1;
695			$state = "s_header_field_info_entry_abbrev_end";
696			$debug>1 && print "$linenumber $state\n";
697		} elsif (($state eq "s_header_field_info_entry_abbrev_end") && ($restofline =~ /[^}]*}(.*)/)) {
698			$restofline = $1;
699			$state = "s_in_hf_register_info";
700			$debug>1 && print "$linenumber $state\n";
701		} elsif (($state eq "s_start_expert") && ($restofline =~ /\W+{(.*)/)) {
702			$restofline = $1;
703			$state = "s_in_ei_register_info";
704			$debug>1 && print "$linenumber $state\n";
705		} elsif (($state eq "s_in_ei_register_info") && ($restofline =~ /\W+{(.*)/)) {
706			$restofline = $1;
707			$state = "s_ei_register_info_entry";
708			$debug>1 && print "$linenumber $state\n";
709		} elsif (($state eq "s_in_ei_register_info") && ($restofline =~ /\s*};(.*)/)) {
710			$restofline = $1;
711			$state = "s_unknown";
712		} elsif (($state eq "s_ei_register_info_entry") && ($restofline =~ /\s*{(.*)/)) {
713			$restofline = $1;
714			$state = "s_ei_register_info_entry_start";
715			$debug>1 && print "$linenumber $state\n";
716		} elsif (($state eq "s_ei_register_info_entry_start") && ($restofline =~ /\"([^\"]*)\"\s*,(.*)/)) {
717			$restofline = $2;
718			$debug>1 && print "$linenumber ei_register_info_entry_abbrev: $1\n";
719			$expert_filters{$linenumber} = $1;
720			$state = "s_ei_register_info_entry_abbrev_end";
721		} elsif (($state eq "s_ei_register_info_entry_abbrev_end") && ($restofline =~ /[^}]*}(.*)/)) {
722			$restofline = $1;
723			$state = "s_in_ei_register_info";
724			$debug>1 && print "$linenumber $state\n";
725		} else {
726			$more_tokens = 0;
727		}
728	}
729
730	$linenumber++;
731}
732
733&printprevfile();
734
735if ($totalerrorcount > 0) {
736	print "\n\nTOTAL ERRORS: $totalerrorcount";
737
738	if ($filecount > 1) {
739		print " ($errorfilecount files)\n";
740
741		print "NO FIELDS: " . scalar(@nofieldfilelist) . "\n";
742		print "AUTOMATED: " . (scalar(@asn1automatedfilelist) + scalar(@dcerpcautomatedfilelist) + scalar(@idl2wrsautomatedfilelist)) . "\n";
743		print "NO PROTOCOL: " . scalar(@noregprotocolfilelist) . "\n";
744
745		print "\nASN.1 AUTOMATED FILE LIST\n";
746		foreach (@asn1automatedfilelist) {
747			print $_;
748		}
749		print "\nDCE/RPC AUTOMATED FILE LIST\n";
750		foreach (@dcerpcautomatedfilelist) {
751			print $_;
752		}
753		print "\nIDL2WRS AUTOMATED FILE LIST\n";
754		foreach (@idl2wrsautomatedfilelist) {
755			print $_;
756		}
757		print "\n\"FILE MANIPULATION\" FILE LIST\n";
758		@uniquefilelist = grep{ not $unique{$_}++} @filemanipulationfilelist;
759		foreach (@uniquefilelist) {
760			print $_;
761		}
762		print "\nREMOVE PREFIX FILE LIST\n";
763		@uniquefilelist = grep{ not $unique{$_}++} @prefixfilelist;
764		foreach (@uniquefilelist) {
765			print $_;
766		}
767		print "\nNO PROTOCOL REGISTERED FILE LIST\n";
768		foreach (@noregprotocolfilelist) {
769			print $_;
770		}
771		print "\nNO FIELDS FILE LIST\n";
772		foreach (@nofieldfilelist) {
773			print $_;
774		}
775
776		print "\nPERIOD IN PROTO FILTER NAME FILE LIST\n";
777		foreach (@periodinfilternamefilelist) {
778			print $_;
779		}
780	} else {
781		print "\n";
782	}
783
784	exit(1); # exit 1 if ERROR
785}
786
787__END__
788