aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2003-10-28 07:02:38 +0000
committerGuy Harris <guy@alum.mit.edu>2003-10-28 07:02:38 +0000
commitc68a7d7cb15b8fede442eef7b1ec19d616ecc10e (patch)
treec65b6a8e5d259e5de569f007d9a5277eac657269
parent9c3e2720dac9d37a97ba9aa7067a4a3e9a46add8 (diff)
From Matthias Melchior: plugin to decode BER-encoded ASN.1 messages,
given a type-table from "snacc" as a protocol description. svn path=/trunk/; revision=8799
-rw-r--r--AUTHORS1
-rw-r--r--Makefile.am6
-rw-r--r--configure.in3
-rw-r--r--packaging/nsis/Makefile.nmake3
-rw-r--r--packaging/nsis/ethereal.nsi3
-rw-r--r--plugins/Makefile.am4
-rw-r--r--plugins/Makefile.nmake11
-rw-r--r--plugins/asn1/.cvsignore19
-rw-r--r--plugins/asn1/AUTHORS2
-rw-r--r--plugins/asn1/COPYING340
-rw-r--r--plugins/asn1/ChangeLog0
-rw-r--r--plugins/asn1/INSTALL0
-rw-r--r--plugins/asn1/Makefile.am44
-rw-r--r--plugins/asn1/Makefile.nmake21
-rw-r--r--plugins/asn1/NEWS0
-rw-r--r--plugins/asn1/moduleinfo.h17
-rw-r--r--plugins/asn1/packet-asn1.c4800
17 files changed, 5266 insertions, 8 deletions
diff --git a/AUTHORS b/AUTHORS
index fc5de8b0f5..fcc4930172 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1730,6 +1730,7 @@ Matthijs Melchior <mmelchior [AT] xs4all.nl> {
definitions for plugin ABI from a single file
Support for registering fields after all the protocol
registration routines are called
+ Generic ASN.1 dissection plugin
}
Garth Bushell <gbushell [AT] elipsan.com> {
diff --git a/Makefile.am b/Makefile.am
index 31fcb2e863..e5b9a430b5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
-# $Id: Makefile.am,v 1.646 2003/10/28 06:44:21 guy Exp $
+# $Id: Makefile.am,v 1.647 2003/10/28 07:02:35 guy Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
@@ -465,6 +465,7 @@ if HAVE_PLUGINS
plugin_libs = \
plugins/acn/acn.la \
plugins/artnet/artnet.la \
+ plugins/asn1/asn1.la \
plugins/docsis/docsis.la \
plugins/giop/cosnaming.la \
plugins/giop/coseventcomm.la \
@@ -479,6 +480,7 @@ if ENABLE_STATIC
plugin_ldadd = \
plugins/acn/packet-acn.o \
plugins/artnet/packet-artnet.o \
+ plugins/asn1/packet-asn1.o \
plugins/docsis/packet-bpkmattr.o \
plugins/docsis/packet-bpkmreq.o \
plugins/docsis/packet-bpkmrsp.o \
@@ -514,6 +516,7 @@ plugin_ldadd = \
plugin_src = \
plugins/acn/packet-acn.c \
plugins/artnet/packet-artnet.c \
+ plugins/asn1/packet-asn1.c \
plugins/docsis/packet-bpkmattr.c \
plugins/docsis/packet-bpkmreq.c \
plugins/docsis/packet-bpkmrsp.c \
@@ -551,6 +554,7 @@ plugin_ldadd = \
"-dlopen" self \
"-dlopen" plugins/acn/acn.la \
"-dlopen" plugins/artnet/artnet.la \
+ "-dlopen" plugins/asn1/asn1.la \
"-dlopen" plugins/docsis/docsis.la \
"-dlopen" plugins/giop/cosnaming.la \
"-dlopen" plugins/giop/coseventcomm.la \
diff --git a/configure.in b/configure.in
index 4a8673cbdb..9da4904618 100644
--- a/configure.in
+++ b/configure.in
@@ -1,4 +1,4 @@
-# $Id: configure.in,v 1.226 2003/10/14 01:18:09 guy Exp $
+# $Id: configure.in,v 1.227 2003/10/28 07:02:35 guy Exp $
dnl
dnl Process this file with autoconf 2.13 or later to produce a
dnl configure script; 2.12 doesn't generate a "configure" script that
@@ -807,6 +807,7 @@ AC_OUTPUT(
plugins/Makefile
plugins/acn/Makefile
plugins/artnet/Makefile
+ plugins/asn1/Makefile
plugins/docsis/Makefile
plugins/giop/Makefile
plugins/gryphon/Makefile
diff --git a/packaging/nsis/Makefile.nmake b/packaging/nsis/Makefile.nmake
index 100d3b3ecc..e5702ba79b 100644
--- a/packaging/nsis/Makefile.nmake
+++ b/packaging/nsis/Makefile.nmake
@@ -1,5 +1,5 @@
#
-# $Id: Makefile.nmake,v 1.24 2003/10/27 22:29:52 guy Exp $
+# $Id: Makefile.nmake,v 1.25 2003/10/28 07:02:36 guy Exp $
#
# NSIS is a free packager/installer/uninstaller program for Win32.
# It was originally written for the Winamp package, but various
@@ -25,6 +25,7 @@ GPL=GPL.txt
PLUGINS=../../plugins/acn/acn.dll \
../../plugins/artnet/artnet.dll \
+ ../../plugins/asn1/asn1.dll \
../../plugins/docsis/docsis.dll \
../../plugins/giop/coseventcomm.dll \
../../plugins/giop/cosnaming.dll \
diff --git a/packaging/nsis/ethereal.nsi b/packaging/nsis/ethereal.nsi
index 076ce7f6b5..522a0cd472 100644
--- a/packaging/nsis/ethereal.nsi
+++ b/packaging/nsis/ethereal.nsi
@@ -1,7 +1,7 @@
;
; ethereal.nsi
;
-; $Id: ethereal.nsi,v 1.20 2003/10/14 01:18:10 guy Exp $
+; $Id: ethereal.nsi,v 1.21 2003/10/28 07:02:36 guy Exp $
; ============================================================================
; Header configuration
@@ -177,6 +177,7 @@ Section "Plugins"
SetOutPath $INSTDIR\plugins\${VERSION}
File "..\..\plugins\acn\acn.dll"
File "..\..\plugins\artnet\artnet.dll"
+File "..\..\plugins\asn1\asn1.dll"
File "..\..\plugins\docsis\docsis.dll"
File "..\..\plugins\giop\coseventcomm.dll"
File "..\..\plugins\giop\cosnaming.dll"
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 28847e361e..0e3c806152 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
-# $Id: Makefile.am,v 1.23 2003/10/14 01:18:10 guy Exp $
+# $Id: Makefile.am,v 1.24 2003/10/28 07:02:37 guy Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
@@ -21,7 +21,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-SUBDIRS = acn artnet docsis giop gryphon lwres megaco mgcp pcli rtnet
+SUBDIRS = acn asn1 artnet docsis giop gryphon lwres megaco mgcp pcli rtnet
plugindir = @plugindir@
diff --git a/plugins/Makefile.nmake b/plugins/Makefile.nmake
index 4b7caa91cc..6b67781b44 100644
--- a/plugins/Makefile.nmake
+++ b/plugins/Makefile.nmake
@@ -1,5 +1,5 @@
#
-# $Id: Makefile.nmake,v 1.26 2003/10/14 01:18:10 guy Exp $
+# $Id: Makefile.nmake,v 1.27 2003/10/28 07:02:37 guy Exp $
#
include ..\config.nmake
@@ -11,7 +11,7 @@ CFLAGS=/DHAVE_CONFIG_H /I.. /I../wiretap /I. $(GLIB_CFLAGS) \
OBJECTS=plugin_api.obj
-all: $(OBJECTS) acn artnet docsis giop gryphon lwres megaco mgcp pcli rtnet
+all: $(OBJECTS) acn artnet asn1 docsis giop gryphon lwres megaco mgcp pcli rtnet
Xplugin_api.c: plugin_gen.py plugin_api_list.c
@echo **** Plugin api may be out of date, please generate new files:
@@ -34,6 +34,11 @@ artnet::
$(MAKE) /$(MAKEFLAGS) -f Makefile.nmake
cd ..
+asn1::
+ cd asn1
+ $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake
+ cd ..
+
docsis::
cd docsis
$(MAKE) /$(MAKEFLAGS) -f Makefile.nmake
@@ -80,6 +85,8 @@ clean:
$(MAKE) /$(MAKEFLAGS) -f Makefile.nmake clean
cd ../artnet
$(MAKE) /$(MAKEFLAGS) -f Makefile.nmake clean
+ cd ../asn1
+ $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake clean
cd ../docsis
$(MAKE) /$(MAKEFLAGS) -f Makefile.nmake clean
cd ../giop
diff --git a/plugins/asn1/.cvsignore b/plugins/asn1/.cvsignore
new file mode 100644
index 0000000000..ad85783847
--- /dev/null
+++ b/plugins/asn1/.cvsignore
@@ -0,0 +1,19 @@
+.deps
+.libs
+Makefile
+Makefile.in
+config.cache
+config.h
+config.h.in
+config.log
+config.status
+configure
+asn1.la
+packet-asn1.lo
+packet-asn1-static.lo
+stamp-h
+*.obj
+*.dll
+*.exp
+*.lib
+*.pdb
diff --git a/plugins/asn1/AUTHORS b/plugins/asn1/AUTHORS
new file mode 100644
index 0000000000..a8e414799e
--- /dev/null
+++ b/plugins/asn1/AUTHORS
@@ -0,0 +1,2 @@
+Author:
+Matthijs Melchior <matthijs.melchior@xs4all.nl>
diff --git a/plugins/asn1/COPYING b/plugins/asn1/COPYING
new file mode 100644
index 0000000000..d60c31a97a
--- /dev/null
+++ b/plugins/asn1/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/plugins/asn1/ChangeLog b/plugins/asn1/ChangeLog
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/plugins/asn1/ChangeLog
diff --git a/plugins/asn1/INSTALL b/plugins/asn1/INSTALL
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/plugins/asn1/INSTALL
diff --git a/plugins/asn1/Makefile.am b/plugins/asn1/Makefile.am
new file mode 100644
index 0000000000..3decfa87fc
--- /dev/null
+++ b/plugins/asn1/Makefile.am
@@ -0,0 +1,44 @@
+# Makefile.am
+# Automake file for Ethereal/asn1
+#
+# $Id: Makefile.am,v 1.1 2003/10/28 07:02:38 guy Exp $
+#
+# Ethereal - Network traffic analyzer
+# By Steve Limkemann <stevelim@dgtech.com>
+# Copyright 1998 Steve Limkemann
+#
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+INCLUDES = -I$(top_srcdir)
+
+plugindir = @plugindir@
+
+plugin_LTLIBRARIES = asn1.la
+asn1_la_SOURCES = packet-asn1.c moduleinfo.h
+asn1_la_LDFLAGS = -module -avoid-version
+
+# Libs must be cleared, or else libtool won't create a shared module.
+# If your module needs to be linked against any particular libraries,
+# add them here.
+LIBS =
+
+packet-asn1-static.o: packet-asn1.c moduleinfo.h
+ $(LTCOMPILE) -c -o packet-asn1-static.o -D__ETHEREAL_STATIC__ $(srcdir)/packet-asn1.c
+
+CLEANFILES = asn1 *~
+
+EXTRA_DIST = Makefile.nmake
diff --git a/plugins/asn1/Makefile.nmake b/plugins/asn1/Makefile.nmake
new file mode 100644
index 0000000000..4512ba66bd
--- /dev/null
+++ b/plugins/asn1/Makefile.nmake
@@ -0,0 +1,21 @@
+#
+# $Id: Makefile.nmake,v 1.1 2003/10/28 07:02:38 guy Exp $
+#
+
+include ..\..\config.nmake
+
+############### no need to modify below this line #########
+
+CFLAGS=/DHAVE_CONFIG_H /I../.. /I../../wiretap \
+ /I$(GLIB_DIR) /I$(GTK_DIR) /I$(GLIB_DIR)/gmodule \
+ /I$(GTK_DIR)\gdk /I$(GTK_DIR)\gdk\win32 \
+ /I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS)
+
+OBJECTS=packet-asn1.obj
+
+asn1.dll asn1.exp asn1.lib : packet-asn1.obj ..\plugin_api.obj
+ link -dll /out:asn1.dll packet-asn1.obj ..\plugin_api.obj \
+ $(GLIB_DIR)\glib-$(GLIB_VERSION).lib
+
+clean:
+ rm -f $(OBJECTS) asn1.dll asn1.exp asn1.lib $(PDB_FILE)
diff --git a/plugins/asn1/NEWS b/plugins/asn1/NEWS
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/plugins/asn1/NEWS
diff --git a/plugins/asn1/moduleinfo.h b/plugins/asn1/moduleinfo.h
new file mode 100644
index 0000000000..b1b22fe488
--- /dev/null
+++ b/plugins/asn1/moduleinfo.h
@@ -0,0 +1,17 @@
+/* Included *after* config.h, in order to re-define these macros */
+
+#ifdef PACKAGE
+#undef PACKAGE
+#endif
+
+/* Name of package */
+#define PACKAGE "asn1"
+
+
+#ifdef VERSION
+#undef VERSION
+#endif
+
+/* Version number of package */
+#define VERSION "0.5.0"
+
diff --git a/plugins/asn1/packet-asn1.c b/plugins/asn1/packet-asn1.c
new file mode 100644
index 0000000000..12064fe045
--- /dev/null
+++ b/plugins/asn1/packet-asn1.c
@@ -0,0 +1,4800 @@
+/******************************************************************************************************/
+/* packet-asn1.c
+ *
+ * Copyright (c) 2003 by Matthijs Melchior <matthijs.melchior@xs4all.nl>
+ *
+ * $Id: packet-asn1.c,v 1.1 2003/10/28 07:02:38 guy Exp $
+ *
+ * A plugin for:
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1999 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+/**************************************************************************
+ * This plugin will dissect BER encoded ASN.1 messages in UDP packets or in
+ * a TCP stream. It relies on ethereal to do defragmentation and re-assembly
+ * to construct complete messages.
+ *
+ * To produce packet display with good annotations it needs to know about
+ * the ASN.1 definition of the messages it reads. To this end, it can read
+ * the 'type-table' output file of the ASN.1 to C compiler 'snacc'. The
+ * version I have used came from: http://packages.debian.org/testing/devel/snacc.html
+ *
+ * The type-table files produced by snacc are themselves ASN.1 BER encoded
+ * data structures. Knowledge of the structure of that table, as specified
+ * in the tbl.asn1 file in the snacc distribution, is hand coded in some
+ * functions in this plugin.
+ *
+ * This also means that this dissector can show its own specification.
+ * On a unix machine, do the following to see this in action:
+ * - cd /tmp
+ * - snacc -u /usr/include/snacc/asn1/asn-useful.asn1 -T tbl.tt /usr/include/snacc/asn1/tbl.asn1
+ * - od -Ax -tx1 tbl.tt | text2pcap -T 801,801 - tbl.tt.pcap
+ * - ethereal tbl.tt.pcap
+ * GUI: Edit->Preferences->Protocols->ASN1
+ * type table file: /tmp/tbl.tt
+ * PDU name: TBL
+ * [OK]
+ * you can now browse the tbl.tt definition.
+ *
+ */
+
+
+/* Include files */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "plugins/plugin_api.h"
+
+#include "moduleinfo.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gmodule.h>
+#include <ctype.h>
+#include <time.h>
+#include <string.h>
+#include <epan/packet.h>
+#include <epan/resolv.h>
+#include "prefs.h"
+#include <epan/strutil.h>
+#include <epan/filesystem.h>
+#include "asn1.h"
+#include "simple_dialog.h"
+
+#include "plugins/plugin_api_defs.h"
+
+#include <gtk/gtk.h>
+
+#include <ipproto.h>
+
+/* Define version if we are not building ethereal statically */
+
+#ifndef __ETHEREAL_STATIC__
+G_MODULE_EXPORT const gchar version[] = VERSION;
+#endif
+
+/* buffer lengths */
+#define BUFLS 32
+#define BUFLM 64
+#define BUFLL 128
+
+/* Define default ports */
+
+#define TCP_PORT_ASN1 801
+#define UDP_PORT_ASN1 801
+
+void proto_reg_handoff_asn1(void);
+
+/* Define the asn1 proto */
+
+static int proto_asn1 = -1;
+
+/* Define the tree for asn1*/
+
+static int ett_asn1 = -1;
+
+#define MAXPDU 64 /* max # PDU's in one packet */
+static int ett_pdu[MAXPDU];
+
+#define MAX_NEST 32 /* max nesting level for ASN.1 elements */
+static int ett_seq[MAX_NEST];
+
+/*
+ * Global variables associated with the preferences for asn1
+ */
+
+static guint global_tcp_port_asn1 = TCP_PORT_ASN1;
+static guint global_udp_port_asn1 = UDP_PORT_ASN1;
+static guint tcp_port_asn1 = TCP_PORT_ASN1;
+static guint udp_port_asn1 = UDP_PORT_ASN1;
+
+static gboolean asn1_desegment = TRUE;
+static char *asn1_filename = 0;
+#define ASN1FILE "asn1/default.tt"
+static char *current_asn1 = 0;
+static char *asn1_pduname = 0;
+static char *current_pduname = 0;
+static gboolean asn1_debug = FALSE;
+static guint first_pdu_offset = 0;
+static gboolean asn1_message_win = FALSE;
+static gboolean asn1_verbose = FALSE; /* change to TRUE for logging the startup phase */
+static gboolean asn1_full = FALSE; /* show full names */
+static guint type_recursion_level = 1; /* eliminate 1 level of references */
+static char *asn1_logfile = 0;
+#ifdef WIN32
+#define ASN1LOGFILE "C:\\temp\\ethereal.log"
+#else
+#define ASN1LOGFILE "/tmp/ethereal.log"
+#endif
+
+/* PDU counter, for correlation between GUI display and log file in debug mode */
+static int pcount = 0;
+
+static tvbuff_t *asn1_desc; /* the PDU description */
+static GNode *asn1_nodes = 0; /* GNode tree pointing to every asn1 data element */
+static GNode *data_nodes = 0; /* GNode tree describing the syntax data */
+static GNode *PDUtree = 0; /* GNode tree describing the expected PDU format */
+
+static guint PDUerrcount = 0; /* count of parse errors in one ASN.1 message */
+
+#define NEL(x) (sizeof(x)/sizeof(*x)) /* # elements in static array */
+
+
+char pabbrev[] = "asn1"; /* field prefix */
+
+char fieldname[512]; /* for constructing full names */
+guint pabbrev_pdu_len; /* length initial part of fieldname with 'abbrev.asn1pdu.' */
+
+/*
+ * Text strings describing the standard, universal, ASN.1 names.
+ */
+
+#define ASN1_EOI 4 /* this is in the class number space... */
+#define ASN1_BEG 2 /* to be merged with constructed flag, first entry in sequence */
+
+char tag_class[] = "UACPX";
+
+char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
+
+char *asn1_con[] = { "Primitive", "Constructed" };
+
+char *asn1_tag[] = {
+ /* 0 */ "EOC", "Boolean", "Integer", "BitString",
+ /* 4 */ "OctetString", "Null", "ObjectIdentifier", "ObjectDescriptor",
+ /* 8 */ "External", "Real", "Enumerated", "tag11",
+ /* 12 */ "UTF8String", "tag13", "tag14", "tag15",
+ /* 16 */ "Sequence", "Set", "NumericString", "PrintableString",
+ /* 20 */ "TeletexString", "VideotexString", "IA5String", "UTCTime",
+ /* 24 */ "GeneralTime", "GraphicString", "ISO646String", "GeneralString",
+ /* 28 */ "UniversalString", "tag29", "BMPString", "Long tag prefix"
+/* TT61 == TELETEX */
+/* ISO646 == VISIBLE*/
+};
+
+/* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
+gboolean tbl_types_verified = FALSE;
+
+typedef enum { /* copied from .../snacc/c-lib/boot/tbl.h */
+ TBL_BOOLEAN = 0,
+ TBL_INTEGER = 1,
+ TBL_BITSTRING = 2,
+ TBL_OCTETSTRING = 3,
+ TBL_NULL = 4,
+ TBL_OID = 5,
+ TBL_REAL = 6,
+ TBL_ENUMERATED = 7,
+ TBL__SIMPLE = 8, /* values smaller than this can have a value */
+ TBL_SEQUENCE = 8,
+ TBL_SET = 9,
+ TBL_SEQUENCEOF = 10,
+ TBL_SETOF = 11,
+ TBL_CHOICE = 12,
+ TBL_TYPEREF = 13,
+
+ TBL_SEQUENCEOF_start, /* to mark potential sequence-of repeat */
+ TBL_TYPEREF_nopop, /* typeref has been handled immediately */
+ TBL_CHOICE_done, /* choice is finished */
+ TBL_reserved, /* this sequence has been visited */
+ TBL_CHOICE_immediate, /* immediate choice, no next */
+
+ TBL_INVALID, /* incorrect value for this enum */
+} TBLTypeId;
+
+/* Universal tags mapped to snacc ASN.1 table types */
+int asn1_uni_type[] = {
+ /* 0 */ TBL_INVALID, TBL_BOOLEAN, TBL_INTEGER, TBL_BITSTRING,
+ /* 4 */ TBL_OCTETSTRING, TBL_NULL, TBL_OID, TBL_INVALID,
+ /* 8 */ TBL_INVALID, TBL_REAL, TBL_ENUMERATED, TBL_INVALID,
+ /* 12 */ TBL_OCTETSTRING, TBL_INVALID, TBL_INVALID, TBL_INVALID,
+ /* 16 */ TBL_SEQUENCE, TBL_SET, TBL_OCTETSTRING, TBL_OCTETSTRING,
+ /* 20 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
+ /* 24 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
+ /* 28 */ TBL_OCTETSTRING, TBL_INVALID, TBL_OCTETSTRING, TBL_INVALID,
+};
+
+
+#define TBL_REPEAT 0x00010000 /* This type may be repeated, a flag in word TBLTypeId */
+#define TBL_REPEAT_choice 0x00020000 /* repeating a choice */
+#define TBL_CHOICE_made 0x00040000 /* This was a choice entry */
+#define TBL_SEQUENCE_done 0x00080000 /* children have been processed */
+#define TBL_CHOICE_repeat 0x00100000 /* a repeating choice */
+#define TBL_REFERENCE 0x00200000 /* This entry is result of a typeref */
+#define TBL_REFERENCE_pop 0x00400000 /* reference handled, do pop i.s.o. next */
+#define TBL_SEQUENCE_choice 0x00800000 /* this sequence is a first of a repeating choice */
+#define TBL_CONSTRUCTED 0x01000000 /* unexpectedly constructed entry */
+#define TBL_TYPEmask 0x0000FFFF /* Mask just the type */
+
+
+#define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
+
+/* text tables for debugging and GUI */
+char *tbl_types[] = { /* 0 */ "tbl-boolean",
+ /* 1 */ "tbl-integer",
+ /* 2 */ "tbl-bitstring",
+ /* 2 */ "tbl-octetstring",
+ /* 4 */ "tbl-null",
+ /* 5 */ "tbl-oid",
+ /* 6 */ "tbl-real",
+ /* 7 */ "tbl-enumerated",
+ /* 8 */ "tbl-sequence",
+ /* 9 */ "tbl-set",
+ /* 10 */ "tbl-sequenceof",
+ /* 11 */ "tbl-setof",
+ /* 12 */ "tbl-choice",
+ /* 13 */ "tbl-typeref",
+
+ /* 14 */ "tbl-sequenceof-start",
+ /* 15 */ "tbl-typeref-nopop",
+ /* 16 */ "tbl-choice-done",
+ /* 17 */ "tbl-reserved",
+ /* 18 */ "tbl-choice-immediate",
+
+ /* 19 */ "tbl-invalid",
+};
+char *tbl_types_asn1[] = {
+ /* 0 */ "BOOLEAN",
+ /* 1 */ "INTEGER",
+ /* 2 */ "BITSTRING",
+ /* 2 */ "OCTET STRING",
+ /* 4 */ "NULL",
+ /* 5 */ "OBJECT IDENTIFIER",
+ /* 6 */ "REAL",
+ /* 7 */ "ENUMERATED",
+ /* 8 */ "SEQUENCE",
+ /* 9 */ "SET",
+ /* 10 */ "SEQUENCE OF",
+ /* 11 */ "SET OF",
+ /* 12 */ "CHOICE",
+ /* 13 */ "TYPEREF",
+
+ /* 14 */ "start-SEQUENCE OF",
+ /* 15 */ "TYPEREF nopop",
+ /* 16 */ "CHOICE done",
+ /* 17 */ "Reserved",
+ /* 18 */ "CHOICE immediate",
+
+ /* 19 */ "INVALID entry",
+};
+/* conversion from snacc type to appropriate ethereal type */
+guint tbl_types_ethereal[] = {
+ /* 0 */ FT_BOOLEAN, /* TBL_BOOLEAN */
+ /* 1 */ FT_UINT32, /* TBL_INTEGER */
+ /* 2 */ FT_UINT32, /* TBL_BITSTRING */
+ /* 2 */ FT_STRINGZ, /* TBL_OCTETSTRING */
+ /* 4 */ FT_NONE, /* TBL_NULL */
+ /* 5 */ FT_BYTES, /* TBL_OID */
+ /* 6 */ FT_DOUBLE, /* TBL_REAL */
+ /* 7 */ FT_UINT32, /* TBL_ENUMERATED */
+ /* 8 */ FT_NONE, /* TBL_SEQUENCE */
+ /* 9 */ FT_NONE, /* TBL_SET */
+ /* 10 */ FT_NONE, /* TBL_SEQUENCEOF */
+ /* 11 */ FT_NONE, /* TBL_SETOF */
+ /* 12 */ FT_NONE, /* TBL_CHOICE */
+ /* 13 */ FT_NONE, /* TBL_TYPEREF */
+
+ /* 14 */ FT_NONE, /* TBL_SEQUENCEOF_start */
+ /* 15 */ FT_NONE, /* TBL_TYPEREF_nopop */
+ /* 16 */ FT_NONE, /* TBL_CHOICE_done */
+ /* 17 */ FT_NONE, /* TBL_reserved */
+ /* 18 */ FT_NONE, /* TBL_CHOICE_immediate */
+
+ /* 19 */ FT_NONE, /* TBL_INVALID */
+};
+
+char *tbl_types_ethereal_txt[] = {
+ /* 0 */ "FT_BOOLEAN", /* TBL_BOOLEAN */
+ /* 1 */ "FT_UINT32", /* TBL_INTEGER */
+ /* 2 */ "FT_UINT32", /* TBL_BITSTRING */
+ /* 2 */ "FT_STRINGZ", /* TBL_OCTETSTRING */
+ /* 4 */ "FT_NONE", /* TBL_NULL */
+ /* 5 */ "FT_BYTES", /* TBL_OID */
+ /* 6 */ "FT_DOUBLE", /* TBL_REAL */
+ /* 7 */ "FT_UINT32", /* TBL_ENUMERATED */
+ /* 8 */ "FT_NONE", /* TBL_SEQUENCE */
+ /* 9 */ "FT_NONE", /* TBL_SET */
+ /* 10 */ "FT_NONE", /* TBL_SEQUENCEOF */
+ /* 11 */ "FT_NONE", /* TBL_SETOF */
+ /* 12 */ "FT_NONE", /* TBL_CHOICE */
+ /* 13 */ "FT_NONE", /* TBL_TYPEREF */
+
+ /* 14 */ "FT_NONE", /* TBL_SEQUENCEOF_start */
+ /* 15 */ "FT_NONE", /* TBL_TYPEREF_nopop */
+ /* 16 */ "FT_NONE", /* TBL_CHOICE_done */
+ /* 17 */ "FT_NONE", /* TBL_reserved */
+ /* 18 */ "FT_NONE", /* TBL_CHOICE_immediate */
+
+ /* 19 */ "FT_NONE", /* TBL_INVALID */
+};
+
+/* description of PDU properties as passed from the matching routine
+ * to the decoder and GUI.
+ */
+typedef struct _PDUprops PDUprops;
+struct _PDUprops {
+ guint type; /* value from enum TBLTypeId */
+ char *name;
+ char *typename;
+ char *fullname;
+ guint flags;
+ gpointer data;
+ gint value_id;
+ gint type_id;
+};
+/* flags defined in PDUprops.flags */
+#define OUT_FLAG_type 1
+#define OUT_FLAG_data 2
+#define OUT_FLAG_typename 4
+#define OUT_FLAG_dontshow 8
+#define OUT_FLAG_noname 0x10
+#define OUT_FLAG_constructed 0x20
+
+PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
+char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
+
+char empty[] = ""; /* address of the empt string, avoids many tests for NULL */
+#define MAX_OTSLEN 256 /* max printed size for an octet string */
+
+
+#undef NEST /* show nesting of asn.1 enties */
+
+#ifdef NEST /* only for debugging */
+/* show nesting, only for debugging... */
+#define MAXTAGS MAX_NEST
+struct {
+ guchar cls;
+ guchar tag;
+} taglist[MAXTAGS];
+
+char *showtaglist(guint level)
+{
+ static char tagtxt[BUFLM];
+ char *p = tagtxt;
+ guint i;
+
+#ifdef ALLTAGS
+ for(i=0; i<= level; i++) {
+ switch(taglist[i].cls) {
+ case ASN1_UNI: *p++ = 'U'; break;
+ case ASN1_APL: *p++ = 'A'; break;
+ case ASN1_CTX: *p++ = 'C'; break;
+ case ASN1_PRV: *p++ = 'P'; break;
+ default: *p++ = 'x'; break;
+ }
+ p += sprintf(p, "%d.", taglist[i].tag);
+ }
+#else /* only context tags */
+ *p++ = 'C';
+ for(i=0; i<= level; i++) {
+ if (taglist[i].cls == ASN1_CTX) {
+ p += sprintf(p, "%d.", taglist[i].tag);
+ }
+ }
+#endif
+ *--p = 0; /* remove trailing '.' */
+ return tagtxt;
+}
+
+guint
+get_context(guint level)
+{
+ guint ctx = 0;
+ guint i;
+
+ for(i=0; i<=level; i++) {
+ if (taglist[i].cls == ASN1_CTX)
+ ctx = (ctx << 8) | taglist[i].tag;
+ }
+ return ctx;
+}
+#endif /* NEST, only for debugging */
+
+
+/* Convert a bit string to an ascii representation for printing
+ * -- not thread safe ...
+ */
+char *showbits(guchar *val, guint count)
+{
+ static char str[BUFLM];
+ guint i;
+ char *p = str;
+
+ if (count > 32)
+ return "*too many bits*";
+
+ if (val != 0) {
+ for(i=0; i<count; i++) {
+ if (i && ((i & 7) == 0)) *p++ = ' ';
+ *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
+ }
+ }
+ *p = 0;
+ return str;
+}
+
+/* get bitnames string for bits set */
+char * showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
+{
+ static char str[BUFLL];
+ guint i;
+ char *p = str;
+
+ if (props->flags & OUT_FLAG_noname)
+ return empty;
+
+ if (count > 32)
+ return "*too many bits, no names...*";
+
+ if (val != 0) {
+ for(i=0; i<count; i++) {
+ if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
+ p += sprintf(p,"%s,", getPDUenum(props, offset, 0, 0, i));
+ }
+ }
+ if (p > str)
+ --p; /* remove terminating , */
+ }
+ *p = 0;
+ return str;
+
+
+
+}
+/* Convert an oid to its conventional text representation
+ * -- not thread safe...
+ */
+char *showoid(subid_t *oid, guint len)
+{
+ static char str[BUFLM];
+ guint i;
+ char *p = str;
+
+ if (oid != 0) {
+ for(i=0; i<len; i++) {
+ if (i) *p++ = '.';
+ p += sprintf(p, "%lu", (unsigned long)oid[i]);
+ }
+ }
+ *p = 0;
+ return str;
+}
+
+/* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
+char *showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
+{
+ guint dohex = 0;
+ guint i;
+ char *str, *p;
+ char *endstr = empty;
+
+ if (len == 0) {
+ str = g_malloc(1);
+ str[0] = 0;
+ } else {
+ for (i=0; i<len; i++) {
+ if (!isprint(octets[i])) /* maybe isblank() as well ... */
+ dohex++;
+ }
+ if (len > MAX_OTSLEN) { /* limit the maximum output.... */
+ len = MAX_OTSLEN;
+ endstr = "...."; /* this is 5 bytes !! */
+ }
+ if (dohex) {
+ str = p = g_malloc(len*2 + 5);
+ for (i=0; i<len; i++) {
+ p += sprintf(p, "%2.2X", octets[i]);
+ }
+ strcpy(p, endstr);
+ } else {
+ if (len <= hexlen) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
+ str = p = g_malloc(len*3+2);
+ for (i=0; i<len; i++) {
+ p += sprintf(p, "%2.2X", octets[i]);
+ }
+ *p++ = ' '; /* insert space */
+ strncpy(p, octets, len);
+ p[len] = 0;
+ } else {
+ /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
+ str = g_malloc(len+5);
+ strncpy(str, octets, len);
+ strcpy(&str[len], endstr);
+ }
+ }
+ }
+ return str;
+}
+
+/* allow NULL pointers in strcmp, handle them as empty strings */
+int
+g_strcmp(gconstpointer a, gconstpointer b)
+{
+ if (a == 0) a = empty;
+ if (b == 0) b = empty;
+ return strcmp(a, b);
+}
+
+guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
+void PDUreset(int count, int counr2);
+
+static void
+dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
+
+ ASN1_SCK asn1;
+ guint cls, con, tag, def, len, offset, reassembled;
+ char lenstr[BUFLS];
+ char tagstr[BUFLS];
+ char headstr[BUFLL];
+ char offstr[BUFLS];
+ char *name;
+ volatile guint boffset;
+ volatile int i = 0; /* PDU counter */
+ proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
+ PDUprops props;
+ static guint lastseq;
+
+ pcount++;
+ boffset = 0;
+
+ reassembled = 1; /* UDP is not a stream, and thus always reassembled .... */
+ if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
+ struct tcpinfo *info = (struct tcpinfo *)pinfo->private_data;
+ gint delta = info->seq - lastseq;
+ reassembled = info->is_reassembled;
+ lastseq = info->seq;
+
+ if (asn1_verbose)
+ g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
+ info->seq, delta, reassembled);
+ } else {
+ if (asn1_verbose)
+ g_message("dissect_asn1: udp");
+ }
+
+ /* Set the protocol column */
+ if(check_col(pinfo->cinfo, COL_PROTOCOL)){
+ col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
+ }
+
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_clear(pinfo->cinfo, COL_INFO);
+
+
+ offstr[0] = 0;
+ if ((first_pdu_offset > 0) && !reassembled) {
+ boffset = first_pdu_offset;
+ snprintf(offstr, sizeof(offstr), " at %d", boffset);
+ }
+
+ /* open BER decoding */
+ asn1_open(&asn1, tvb, boffset);
+
+ asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
+
+ asn1_close(&asn1, &offset);
+
+ PDUreset(pcount, 0); /* arguments are just for debugging */
+ getPDUprops(&props, boffset, cls, tag, con);
+ name = props.name;
+
+ if (asn1_debug) {
+ if (def) {
+ snprintf(lenstr, sizeof(lenstr), "%d", len);
+ } else {
+ strncpy(lenstr, "indefinite", sizeof(lenstr) );
+ }
+ snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
+
+ snprintf(headstr, sizeof(headstr), "first%s: %s %d %s, %s, %s, len=%s, off=%d, size=%d ",
+ offstr,
+ name,
+ pcount,
+ asn1_cls[cls],
+ asn1_con[con],
+ ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
+ lenstr,
+ boffset,
+ tvb_length(tvb)
+ );
+ } else {
+ if (props.flags & OUT_FLAG_noname) {
+ snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
+ name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
+ }
+ snprintf(headstr, sizeof(headstr), "first pdu%s: %s ", offstr, name );
+ }
+
+ /* Set the info column */
+ if(check_col(pinfo->cinfo, COL_INFO)){
+ col_add_str(pinfo->cinfo, COL_INFO, headstr );
+ }
+
+ /*
+ * If we have a non-null tree (ie we are building the proto_tree
+ * instead of just filling out the columns ), then add a BER
+ * tree node
+ */
+
+ /* ignore the tree here, must decode BER to know how to reassemble!! */
+/* if(tree) { */
+
+ TRY { /* catch incomplete PDU's */
+
+ ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
+ def? (int) (offset - boffset + len) : -1,
+ "ASN.1 %s", current_pduname);
+
+ tree2 = proto_item_add_subtree(ti, ett_asn1);
+
+ offset = boffset; /* the first packet */
+ while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
+ ti2 = 0;
+ boffset = offset;
+ /* open BER decoding */
+ asn1_open(&asn1, tvb, offset);
+ asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
+ asn1_close(&asn1, &offset);
+
+ PDUreset(pcount, i+1);
+ getPDUprops(&props, boffset, cls, tag, con);
+ name = props.name;
+
+ if (!def)
+ len = tvb_length_remaining(tvb, offset);
+
+ if (asn1_debug) {
+ if (def) {
+ snprintf(lenstr, sizeof(lenstr), "%d", len);
+ } else {
+ strncpy(lenstr, "indefinite", sizeof(lenstr));
+ }
+ snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
+
+ snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
+ asn1_cls[cls],
+ asn1_con[con],
+ ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
+ lenstr,
+ boffset,
+ tvb_length_remaining(tvb, offset) );
+
+ if (props.value_id == -1)
+ ti2 = proto_tree_add_text(tree2, tvb, boffset,
+ def? (int) (offset - boffset + len) : -1,
+ "%s: %s %d-%d %s", current_pduname, name,
+ pcount, i+1, headstr);
+ else {
+ ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
+ def? (int) (offset - boffset + len) : -1,
+ "%s: %s %d-%d %s ~", current_pduname, name,
+ pcount, i+1, headstr);
+
+ if (props.type_id != -1)
+ proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
+ def? (int) (offset - boffset + len) : -1, TRUE);
+
+ }
+ } else {
+ if (props.flags & OUT_FLAG_noname) {
+ snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
+ name = ((cls == ASN1_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
+ }
+ if (props.value_id == -1)
+ ti2 = proto_tree_add_text(tree2, tvb, boffset,
+ def? (int) (offset - boffset + len) : -1,
+ "%s: %s", current_pduname, name);
+ else {
+ ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
+ def? (int) (offset - boffset + len) : -1,
+ "%s: %s ~", current_pduname, name);
+ if (props.type_id != -1)
+ proto_tree_add_item_hidden(tree2, props.type_id, tvb, boffset,
+ def? (int) (offset - boffset + len) : -1, TRUE);
+ }
+ }
+ asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
+
+#ifdef NEST
+ taglist[0].cls = cls;
+ taglist[0].tag = tag;
+#endif /* NEST */
+
+ if (!def) len++; /* make sure we get an exception if we run off the end! */
+ offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
+ proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
+
+ i++; /* one more full message handled */
+
+ if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
+ proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
+ }
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
+ if (ti)
+ proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
+ }
+ CATCH(BoundsError) {
+ RETHROW;
+ }
+ CATCH(ReportedBoundsError) {
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
+ if (ti)
+ proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
+ if (ti2)
+ proto_item_append_text(ti2, " (incomplete)");
+ if (asn1_desegment) {
+ pinfo->desegment_offset = boffset;
+ pinfo->desegment_len = 1;
+ if (asn1_verbose)
+ g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
+ boffset, 1, pinfo->can_desegment);
+ } else {
+ RETHROW;
+ }
+ }
+ ENDTRY;
+/* } */
+ if (asn1_verbose)
+ g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
+ pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
+}
+
+/* decode an ASN.1 sequence, until we have consumed the specified length */
+guint
+decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
+{
+ ASN1_SCK asn1;
+ guint ret, cls, con, tag, def, len, boffset, soffset, eos;
+ guint value;
+ char *clsstr, *constr, *tagstr;
+ char tagbuf[BUFLM];
+ char lenbuf[BUFLM];
+ char nnbuf[BUFLS];
+ proto_tree *ti, *pt2;
+ guchar *octets, *bits, unused;
+ subid_t *oid;
+ /* the debugging formats */
+ static char textfmt_d[] = "off=%d: [%s %s %s] (%s)%s: %d%s"; /* decimal */
+ static char textfmt_e[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s"; /* enum */
+ static char textfmt_s[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s"; /* octet string */
+ static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s"; /* bit field */
+ static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s"; /* constructed */
+ static char matchind[] = " ~"; /* indication of possible match */
+ char *name, *ename, *tname, *oname;
+ PDUprops props;
+
+ ti = 0; /* suppress gcc warning */
+
+ soffset = offset; /* where this sequence starts */
+ eos = offset + tlen;
+ while (offset < eos) { /* while this entity has not ended... */
+ boffset = offset;
+ asn1_open(&asn1, tvb, offset);
+ ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
+ asn1_close(&asn1, &offset); /* mark current position */
+ if (ret != ASN1_ERR_NOERROR) {
+ proto_tree_add_text(pt, tvb, offset, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret) );
+ break;
+ }
+
+ getPDUprops(&props, boffset, cls, tag, con);
+ name = props.name;
+ tname = props.typename;
+ if (asn1_full)
+ name = &props.fullname[pabbrev_pdu_len]; /* no abbrev.pduname */
+ if (asn1_debug) { /* show both names */
+ sprintf(fieldname, "%s[%s]", props.name, props.fullname);
+ name = fieldname;
+ }
+
+ clsstr = asn1_cls[cls];
+ constr = asn1_con[con];
+ if ((cls == ASN1_UNI) && ( tag < 32 )) {
+ tagstr = asn1_tag[tag];
+ } else {
+ snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
+ tagstr = tagbuf;
+ }
+ if (def) {
+ snprintf(lenbuf, sizeof(lenbuf), "%d", len);
+ snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
+ } else {
+ strncpy(lenbuf, "indefinite", sizeof(lenbuf));
+ strncpy(nnbuf, "NN-", sizeof(nnbuf));
+ /* make sure we get an exception if we run off the end! */
+ len = tvb_length_remaining(tvb, offset) + 1;
+ }
+ if ( ( ! asn1_debug) && (props.flags & OUT_FLAG_noname) ) {
+ /* just give type name if we don't know any better */
+ tname = tagstr;
+ name = nnbuf; /* this is better than just empty.... */
+ }
+
+#ifdef NEST
+ taglist[level].cls = cls;
+ taglist[level].tag = tag;
+#endif /* NEST */
+
+ oname = 0;
+ if (level >= MAX_NEST) { /* nesting too deep..., handle as general octet string */
+ cls = ASN1_UNI;
+ tag = ASN1_GENSTR;
+ oname = g_malloc(strlen(name) + 32);
+ sprintf(oname, "%s ** nesting cut off **", name);
+ name = oname;
+ }
+ switch(cls) {
+ case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
+ switch(tag) {
+ case ASN1_INT:
+ ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are now */
+ if (asn1_debug) {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected: just text */
+ proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset, textfmt_d, boffset,
+ clsstr, constr, tagstr, tname, name, value,
+ empty);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, value, textfmt_d, boffset,
+ clsstr, constr, tagstr, tname, name, value,
+ matchind);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, value);
+ }
+ } else {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset,
+ "(%s)%s: %d", tname, name, value);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, value,
+ "(%s)%s: %d ~", tname, name, value);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, value);
+ }
+ }
+ break;
+
+ case ASN1_ENUM:
+ ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are now */
+ ename = getPDUenum(&props, boffset, cls, tag, value);
+ if (asn1_debug) {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset,
+ textfmt_e, boffset, clsstr, constr, tagstr,
+ tname, name, value, ename, empty);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, value,
+ textfmt_e, boffset, clsstr, constr, tagstr,
+ tname, name, value, ename, matchind);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, value);
+ }
+ } else {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset,
+ "(%s)%s: %d:%s", tname, name, value, ename);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, value,
+ "(%s)%s: %d:%s ~", tname, name, value, ename);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, value);
+ }
+ }
+ break;
+
+ case ASN1_BOL:
+ ret = asn1_bool_decode(&asn1, len, &value); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are now */
+ if (asn1_debug) {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset,
+ textfmt_s, boffset, clsstr, constr, tagstr,
+ tname, name, value? "true" : "false", empty);
+ else {
+ proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, value != 0,
+ textfmt_s, boffset, clsstr, constr, tagstr,
+ tname, name, value? "true" : "false", matchind);
+ if (props.type_id != -1)
+ proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, value != 0);
+ }
+ } else {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset,
+ "(%s)%s: %s", tname, name,
+ value? "true" : "false");
+ else {
+ proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, value != 0,
+ "(%s)%s: %s ~", tname, name,
+ value? "true" : "false");
+ if (props.type_id != -1)
+ proto_tree_add_boolean_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, value != 0);
+ }
+ }
+ break;
+
+ case ASN1_OTS:
+ case ASN1_NUMSTR:
+ case ASN1_PRNSTR:
+ case ASN1_TEXSTR:
+ case ASN1_IA5STR:
+ case ASN1_GENSTR:
+ case ASN1_UNITIM:
+ case ASN1_GENTIM:
+ /* read value, \0 terminated */
+ ret = asn1_string_value_decode(&asn1, len, &octets);
+ asn1_close(&asn1, &offset); /* mark where we are now */
+ ename = showoctets(octets, len, (tag == ASN1_OTS) ? 4 : 0 );
+ if (asn1_debug) {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_STRINGZ) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset,
+ textfmt_s, boffset, clsstr, constr, tagstr,
+ tname, name, ename, empty);
+ else {
+ proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, octets, /* \0 termnated */
+ textfmt_s, boffset, clsstr, constr, tagstr,
+ tname, name, ename, matchind);
+ if (props.type_id != -1)
+ proto_tree_add_string_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, octets);
+ }
+ } else {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_STRINGZ) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset,
+ "(%s)%s: %s", tname, name, ename);
+ else {
+ proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, octets, /* \0 terminated */
+ "(%s)%s: %s ~", tname, name, ename);
+ if (props.type_id != -1)
+ proto_tree_add_string_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, octets);
+ }
+ }
+ g_free(octets);
+ g_free(ename);
+ break;
+
+ case ASN1_BTS:
+ ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are now */
+ ename = showbitnames(bits, (con*8)-unused, &props, offset);
+ if (asn1_debug) {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset,
+ textfmt_b, boffset, clsstr, constr, tagstr,
+ tname, name,
+ showbits(bits, (con*8)-unused), ename, empty);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, *bits, /* XXX length ? XXX */
+ textfmt_b, boffset, clsstr, constr, tagstr,
+ tname, name,
+ showbits(bits, (con*8)-unused),ename, matchind);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, *bits);
+ }
+
+ } else {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset,
+ "(%s)%s: %s:%s", tname, name,
+ showbits(bits, (con*8)-unused), ename);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, *bits, /* XXX length ? XXX */
+ "(%s)%s: %s:%s ~", tname, name,
+ showbits(bits, (con*8)-unused), ename);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, *bits);
+ }
+ }
+ g_free(bits);
+ break;
+
+ case ASN1_SET:
+ case ASN1_SEQ:
+ /* show full sequence length */
+ if (asn1_debug) {
+ ename = empty;
+ if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
+ ename = ", noshow";
+ if ( (props.flags & OUT_FLAG_constructed))
+ ename = ", unexpected constructed";
+
+ if (props.value_id == -1)
+ ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
+ textfmt_c, boffset, clsstr, constr, tagstr,
+ tname, name, ename, empty);
+ else {
+ ti = proto_tree_add_item(pt, props.value_id, tvb,
+ boffset, 1, TRUE);
+ /* change te text to to what I really want */
+ proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
+ tagstr, tname, name, ename, matchind);
+ if (props.type_id != -1)
+ proto_tree_add_item_hidden(pt, props.type_id, tvb,
+ boffset, 1, TRUE);
+ }
+ } else {
+ if (props.value_id == -1) {
+ if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
+ ti = proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset + len,
+ "(%s)%s", tname, name);
+ } else {
+ if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
+ ti = proto_tree_add_none_format(pt, props.value_id, tvb,
+ boffset, offset - boffset + len,
+ "(%s)%s ~", tname, name);
+ else {
+ /* don't care about the text */
+ ti = proto_tree_add_item_hidden(pt, props.value_id, tvb,
+ boffset, 1, TRUE);
+ }
+ if (props.type_id != -1)
+ proto_tree_add_item_hidden(pt, props.type_id, tvb,
+ boffset, 1, TRUE);
+ }
+ }
+ if (len == 0) return offset; /* don't recurse if offset isn't going to change */
+
+ if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
+ pt2 = proto_item_add_subtree(ti, ett_seq[level]);
+ else
+ pt2 = pt;
+
+ offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
+
+ if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
+ proto_item_set_len(ti, offset - boffset);
+
+ break;
+
+ case ASN1_EOC:
+ if (asn1_debug) { /* don't show if not debugging */
+ proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
+ boffset, clsstr, constr, tagstr, tname, name,
+ offset - soffset, empty);
+ }
+ getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
+ return offset;
+
+ case ASN1_OJI:
+ ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
+ asn1_close(&asn1, &offset); /* mark where we are now */
+ ename = showoid(oid, con);
+ if (asn1_debug) {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_BYTES) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
+ boffset, clsstr, constr, tagstr, tname, name,
+ ename, empty);
+ else {
+ proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, ename,/* XXX length?*/
+ "(%s)%s: %s ~", tname, name, ename);
+ if (props.type_id != -1)
+ proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, ename);
+ }
+ } else {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_BYTES) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset,
+ "(%s)%s: %s", tname, name, ename);
+ else {
+ proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
+ offset - boffset, ename, /* XXX length ? */
+ "(%s)%s: %s ~", tname, name, ename);
+ if (props.type_id != -1)
+ proto_tree_add_bytes_hidden(pt, props.type_id, tvb,
+ boffset, offset - boffset, ename);
+ }
+ }
+ g_free(oid);
+ break;
+
+ case ASN1_NUL:
+ if (asn1_debug) {
+ proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
+ boffset, clsstr, constr, tagstr, tname, name,
+ "[NULL]", empty);
+ } else {
+ proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
+ "(%s)%s: [NULL]", tname, name);
+ }
+ offset += len; /* skip value ... */
+ break;
+
+ case ASN1_OJD:
+ case ASN1_EXT:
+ case ASN1_REAL:
+ case ASN1_VIDSTR:
+ case ASN1_GRASTR:
+ case ASN1_VISSTR:
+
+ default:
+ if (asn1_debug) {
+ ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
+ textfmt_s, boffset, clsstr, constr, tagstr,
+ tname, name, lenbuf, empty);
+ } else {
+ ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
+ "(%s)%s: %s bytes", tname, name, lenbuf);
+ }
+ proto_item_append_text(ti, " *"); /* indicate default is used */
+ offset += len; /* skip value ... */
+ break;
+ };
+ break;
+
+ case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
+ case ASN1_APL: /* fprintf(stderr, "Application\n"); */
+ case ASN1_PRV: /* fprintf(stderr, "Private\n"); */
+
+ if (def && !con) {
+ if (props.value_id == -1) /* type unknown, handle as string */
+ goto dostring;
+ switch(props.type) {
+ /* this is via the asn1 description, don't trust the length */
+ case TBL_INTEGER:
+ if (len > 4)
+ goto dostring;
+ ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are now */
+ if (asn1_debug) {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb,
+ boffset, offset - boffset,
+ textfmt_d, boffset, clsstr, constr,
+ tagstr, tname, name, value, empty);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb,
+ boffset, offset - boffset, value,
+ textfmt_d, boffset, clsstr, constr,
+ tagstr, tname, name, value, matchind);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id,
+ tvb, boffset, offset - boffset, value);
+ }
+ } else {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb,
+ boffset, offset - boffset,
+ "(%s)%s: %d", tname, name, value);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb,
+ boffset, offset - boffset, value,
+ "(%s)%s: %d ~", tname, name, value);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id,
+ tvb, boffset, offset - boffset, value);
+ }
+ }
+ break;
+
+ case TBL_ENUMERATED:
+ if (len > 4)
+ goto dostring;
+ ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are now */
+ ename = getPDUenum(&props, boffset, cls, tag, value);
+ if (asn1_debug) {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb,
+ boffset, offset - boffset,
+ textfmt_e, boffset, clsstr, constr,
+ tagstr, tname, name, value, ename, empty);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb,
+ boffset, offset - boffset, value,
+ textfmt_e, boffset, clsstr, constr,
+ tagstr, tname, name, value, ename, matchind);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id,
+ tvb, boffset, offset - boffset, value);
+ }
+ } else {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb,
+ boffset, offset - boffset,
+ "(%s)%s: %d:%s", tname, name, value, ename);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb,
+ boffset, offset - boffset, value,
+ "(%s)%s: %d:%s ~", tname, name, value, ename);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id,
+ tvb, boffset, offset - boffset, value);
+ }
+ }
+ break;
+ case TBL_BITSTRING:
+ if (len > (1+4)) /* max 32 bits ...?.. */
+ goto dostring;
+ /* read value */
+ ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
+ asn1_close(&asn1, &offset); /* mark where we are now */
+ ename = showbitnames(bits, (con*8)-unused, &props, offset);
+ if (asn1_debug) {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb,
+ boffset, offset - boffset,
+ textfmt_b, boffset, clsstr, constr,
+ tagstr, tname, name,
+ showbits(bits, (con*8)-unused), ename,
+ empty);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb,
+ boffset, offset - boffset, *bits,
+ textfmt_b, boffset, clsstr, constr,
+ tagstr, tname, name,
+ showbits(bits, (con*8)-unused), ename,
+ matchind);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id,
+ tvb, boffset, offset - boffset, *bits);
+ }
+ } else {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_UINT32) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset, offset - boffset,
+ "(%s)%s: %s:%s", tname, name,
+ showbits(bits, (con*8)-unused), ename);
+ else {
+ proto_tree_add_uint_format(pt, props.value_id, tvb,
+ boffset, offset - boffset, *bits,
+ "(%s)%s: %s:%s ~", tname, name,
+ showbits(bits, (con*8)-unused), ename);
+ if (props.type_id != -1)
+ proto_tree_add_uint_hidden(pt, props.type_id,
+ tvb, boffset, offset - boffset, *bits);
+ }
+ }
+ g_free(bits);
+ break;
+ case TBL_BOOLEAN:
+ if (len > 1)
+ goto dostring;
+ ret = asn1_bool_decode(&asn1, len, &value); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are now */
+ if (asn1_debug) {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb,
+ boffset, offset - boffset,
+ textfmt_s, boffset, clsstr, constr,
+ tagstr, tname, name,
+ value? "true" : "false", empty);
+ else {
+ proto_tree_add_boolean_format(pt, props.value_id, tvb,
+ boffset, offset - boffset, value != 0,
+ textfmt_s, boffset, clsstr, constr,
+ tagstr, tname, name,
+ value? "true" : "false", matchind);
+ if (props.type_id != -1)
+ proto_tree_add_boolean_hidden(pt, props.type_id,
+ tvb, boffset, offset - boffset, value != 0);
+ }
+ } else {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_BOOLEAN) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb,
+ boffset, offset - boffset,
+ "(%s)%s: %s", tname, name,
+ value? "true" : "false");
+ else {
+ proto_tree_add_boolean_format(pt, props.value_id, tvb,
+ boffset, offset - boffset, value != 0,
+ "(%s)%s: %s ~", tname, name,
+ value? "true" : "false");
+ if (props.type_id != -1)
+ proto_tree_add_boolean_hidden(pt, props.type_id,
+ tvb, boffset, offset - boffset, value != 0);
+ }
+ }
+ break;
+ case TBL_NULL:
+ if (len > 0)
+ goto dostring;
+ if (asn1_debug) {
+ proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
+ textfmt_s, boffset, clsstr, constr,
+ tagstr, tname, name, "[NULL]", empty);
+ } else {
+ proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
+ "(%s)%s: [NULL]", tname, name);
+ }
+ offset += len; /* skip value ... */
+ break;
+ default:
+ dostring:
+ props.value_id = -1; /* unlikely this is correct, dont use it */
+ /* fallthrough */
+ case TBL_OCTETSTRING:
+ /* defined length, not constructed, must be a string.... */
+ ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are now */
+ ename = showoctets(octets, len, 2); /* convert octets to printable */
+ if (asn1_debug) {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_STRINGZ) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb,
+ boffset, offset - boffset,
+ textfmt_s, boffset, clsstr, constr,
+ tagstr, tname, name, ename, empty);
+ else {
+ proto_tree_add_string_format(pt, props.value_id, tvb,
+ boffset, offset - boffset, octets, /* XXX */
+ textfmt_s, boffset, clsstr, constr,
+ tagstr, tname, name, ename, matchind);
+ if (props.type_id != -1)
+ proto_tree_add_string_hidden(pt, props.type_id,
+ tvb, boffset, offset - boffset, octets);
+ }
+ } else {
+ if ( (props.value_id == -1) ||
+ (tbl_types_ethereal[props.type] != FT_STRINGZ) )
+ /* unknown or unexpected, just text */
+ proto_tree_add_text(pt, tvb, boffset, offset - boffset,
+ "(%s)%s: %s", tname, name, ename);
+ else {
+ proto_tree_add_string_format(pt, props.value_id, tvb,
+ boffset, offset - boffset, octets, /* XXX */
+ "(%s)%s: %s ~", tname, name, ename);
+ if (props.type_id != -1)
+ proto_tree_add_string_hidden(pt, props.type_id,
+ tvb, boffset, offset - boffset, octets);
+ }
+ }
+ g_free(octets);
+ g_free(ename);
+ break;
+ }
+ } else {
+ /* indefinite length or constructed.... must be a sequence .... */
+ /* show full sequence length */
+ if (asn1_debug) {
+ ename = empty;
+ if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
+ ename = ", noshow";
+ if ( (props.flags & OUT_FLAG_constructed))
+ ename = ", unexpected constructed";
+
+ if (props.value_id == -1)
+ ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
+ textfmt_c, boffset, clsstr, constr,
+ tagstr, tname, name, ename, empty);
+ else {
+ ti = proto_tree_add_item(pt, props.value_id, tvb,
+ boffset, 1, TRUE);
+ /* change te text to to what I really want */
+ if (ti) {
+ proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
+ tagstr, tname, name, ename, matchind);
+ if (props.type_id != -1)
+ proto_tree_add_item_hidden(pt, props.type_id, tvb,
+ boffset, 1, TRUE);
+ } else {
+ ti = proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset + len,
+ textfmt_c, boffset, clsstr, constr,
+ tagstr, tname, name, ename, empty);
+ }
+ }
+ } else {
+ if (props.value_id == -1) {
+ if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
+ ti = proto_tree_add_text(pt, tvb, boffset,
+ offset - boffset + len, "(%s)%s", tname, name);
+ } else {
+ if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
+ ti = proto_tree_add_none_format(pt, props.value_id, tvb,
+ boffset, 1,
+ "(%s)%s ~", tname, name);
+ else {
+ /* don't care about the text */
+ ti = proto_tree_add_item_hidden(pt, props.value_id,
+ tvb, boffset, 1, TRUE);
+ }
+ if (props.type_id != -1)
+ proto_tree_add_item_hidden(pt, props.type_id,
+ tvb, boffset, 1, TRUE);
+ }
+ }
+
+ if (len == 0) return offset; /* don't recurse if offset isn't going to change */
+
+ if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
+ pt2 = proto_item_add_subtree(ti, ett_seq[level]);
+ else
+ pt2 = pt;
+
+ offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
+
+ if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
+ proto_item_set_len(ti, offset - boffset);
+ }
+ break;
+
+ default: /* fprintf(stderr, "Other\n"); */
+ if (asn1_debug) {
+ ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
+ textfmt_s, boffset, clsstr, constr, tagstr,
+ tname, name, lenbuf, empty);
+ } else {
+ ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
+ "(%s)%s: %s bytes %s data", tname, name,
+ lenbuf, clsstr);
+ }
+ proto_item_append_text(ti, " *"); /* indicate default is used */
+ offset += len; /* skip value ... */
+ break;
+ }
+ g_free(oname); /* XXX, memory management ? */
+ }
+ /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
+
+ getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
+
+ return offset;
+}
+#define READSYNTAX
+#ifdef READSYNTAX
+
+/************************************************************************************************/
+/* search throug the ASN.1 description for appropriate names */
+/************************************************************************************************/
+
+guint lev_limit = G_MAXINT;;
+
+int icount = 0; /* item counter */
+
+guint
+parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
+{
+ ASN1_SCK asn1;
+ guint eos, ret, cls, con, tag, def, len, value;
+ guchar *octets, *bits, unused;
+ subid_t *oid;
+ char *clsstr, *constr, *tagstr;
+ char tagbuf[BUFLM];
+ char lenbuf[BUFLM];
+ GNode *cur_node = 0;
+
+ eos = offset + size;
+
+ if (level > lev_limit)
+ return eos;
+
+ while(offset < eos) {
+ if (ptr) /* build pointer tree to all asn1 enteties */
+ cur_node = g_node_append_data(ptr, (void *)offset);
+
+ asn1_open(&asn1, tvb, offset);
+ ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
+ asn1_close(&asn1, &offset); /* mark where we are */
+ icount++;
+ clsstr = asn1_cls[cls];
+ constr = asn1_con[con];
+ if ((cls == ASN1_UNI) && ( tag < 32 )) {
+ tagstr = asn1_tag[tag];
+ } else {
+ snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
+ tagstr = tagbuf;
+ }
+ if (def) {
+ snprintf(lenbuf, sizeof(lenbuf), "%d", len);
+ } else {
+ strncpy(lenbuf, "indefinite", sizeof(lenbuf));
+ len = tvb_length_remaining(tvb, offset);;
+ }
+
+ switch(cls) {
+ case ASN1_UNI: /* fprintf(stderr, "Universal\n"); */
+ switch(tag) {
+ case ASN1_INT:
+ case ASN1_ENUM:
+ ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are */
+ break;
+
+ case ASN1_BOL:
+ ret = asn1_bool_decode(&asn1, len, &value); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are */
+ break;
+
+ case ASN1_OTS:
+ case ASN1_NUMSTR:
+ case ASN1_PRNSTR:
+ case ASN1_TEXSTR:
+ case ASN1_IA5STR:
+ case ASN1_GENSTR:
+ case ASN1_UNITIM:
+ case ASN1_GENTIM:
+ ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are */
+ g_free(octets);
+ break;
+
+ case ASN1_BTS:
+ ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
+ asn1_close(&asn1, &offset); /* mark where we are */
+ g_free(bits);
+ break;
+
+ case ASN1_SET:
+ case ASN1_SEQ:
+ if (len == 0) /* don't recurse if offset isn't going to change */
+ return offset;
+
+ offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
+ break;
+
+ case ASN1_EOC:
+ return offset;
+
+ case ASN1_OJI:
+ ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
+ asn1_close(&asn1, &offset); /* mark where we are */
+ g_free(oid);
+ break;
+
+ case ASN1_NUL:
+ offset += len;
+ break;
+
+ case ASN1_OJD:
+ case ASN1_EXT:
+ case ASN1_REAL:
+ case ASN1_VIDSTR:
+ case ASN1_GRASTR:
+ case ASN1_VISSTR:
+
+ default:
+ if (asn1_verbose) g_message("%d skip1 %d", offset, len);
+ offset += len; /* skip value ... */
+ break;
+ };
+ break;
+
+ case ASN1_CTX: /* fprintf(stderr, "Context\n"); */
+ tagstr = tagbuf;
+ snprintf(tagbuf, sizeof(tagbuf), "TAG%d", tag);
+ if (def && !con) {
+ /* defined length, not constructed, must be a string.... */
+ asn1_string_value_decode(&asn1, len, &octets); /* read value */
+ asn1_close(&asn1, &offset); /* mark where we are */
+ g_free(octets);
+ } else {
+ /* indefinite length or constructed.... must be a sequence .... */
+ if (len == 0) /* don't recurse if offset isn't going to change */
+ return offset;
+
+ offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
+ }
+ break;
+
+ default: /* fprintf(stderr, "Other\n"); */
+ if (asn1_verbose) g_message("%d skip2 %d", offset, len);
+ offset += len; /* skip value ... */
+ break;
+ }
+ }
+ return offset;
+}
+
+void showGNodes(GNode *p, int n);
+
+gboolean
+myLeaf(GNode *node, gpointer data)
+{
+ ASN1_SCK asn1;
+ guint ret, cls, con, tag, def, len;
+ char *clsstr, *constr, *tagstr;
+ char tagbuf[BUFLM];
+ char lenbuf[BUFLM];
+
+ (void) data; /* make a reference */
+ asn1_open(&asn1, asn1_desc, (int)node->data);
+
+ ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
+
+ clsstr = asn1_cls[cls];
+ constr = asn1_con[con];
+ if ((cls == ASN1_UNI) && ( tag < 32 )) {
+ tagstr = asn1_tag[tag];
+ } else {
+ snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
+ tagstr = tagbuf;
+ }
+ if (def) {
+ snprintf(lenbuf, sizeof(lenbuf), "%d", len);
+ } else {
+ strncpy(lenbuf, "indefinite", sizeof(lenbuf));
+ }
+
+ if (asn1_verbose)
+ g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
+
+ return FALSE;
+}
+
+void
+list_modules()
+{
+ if (asn1_verbose) g_message("build GNode tree:");
+ showGNodes(g_node_first_child(asn1_nodes), 0);
+ if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
+ g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
+ g_node_max_height (asn1_nodes),
+ g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
+ g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
+
+ g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
+
+}
+
+void
+tt_build_tree() /* build a GNode tree with all offset's to ASN.1 entities */
+{
+ if (asn1_nodes)
+ g_node_destroy(asn1_nodes);
+ asn1_nodes = g_node_new(0);
+ icount = 0;
+ parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
+}
+
+
+/*****************************************************************************************************/
+
+guint anonCount; /* for naming anonymous types */
+
+typedef struct _TBLModule TBLModule;
+typedef struct _TBLTypeDef TBLTypeDef;
+typedef struct _TBLTag TBLTag;
+typedef struct _TBLType TBLType;
+typedef struct _TBLTypeRef TBLTypeRef;
+typedef struct _TBLNamedNumber TBLNamedNumber;
+typedef struct _TBLRange TBLRange;
+
+typedef enum _tbl_t tbl_t;
+enum _tbl_t {
+ TBLTYPE_Module,
+ TBLTYPE_TypeDef,
+ TBLTYPE_Tag,
+ TBLTYPE_Type,
+ TBLTYPE_TypeRef,
+ TBLTYPE_NamedNumber,
+ TBLTYPE_Range,
+};
+/* text for 'tbl_t' type for debugging */
+char *data_types[] = { "Module",
+ "TypeDef",
+ "Tag",
+ "Type",
+ "TypeRef",
+ "NamedNumber",
+ "Range",
+};
+
+typedef enum _TBLTypeContent_t TBLTypeContent_t;
+enum _TBLTypeContent_t {
+ TBLTYPETYPE_None,
+ TBLTYPETYPE_Primitive,
+ TBLTYPETYPE_Elements,
+ TBLTYPETYPE_TypeRef,
+};
+
+struct _TBLNamedNumber {
+ tbl_t type;
+ guchar *name;
+ guint value;
+};
+
+struct _TBLRange {
+ tbl_t type;
+ guint from;
+ guint to;
+};
+
+struct _TBLTypeRef {
+ tbl_t type;
+ guint typeDefId;
+ gboolean implicit;
+};
+
+struct _TBLTag {
+ tbl_t type;
+ guint tclass;
+ guint code;
+};
+
+struct _TBLType {
+ tbl_t type;
+ guint typeId;
+ gboolean optional;
+ TBLTypeContent_t content;
+ guchar *fieldName;
+ gboolean anonymous;
+ gboolean constraint;
+};
+
+struct _TBLTypeDef {
+ tbl_t type;
+ guint typeDefId;
+ guchar *typeName;
+ guchar isPdu;
+};
+
+struct _TBLModule {
+ tbl_t type;
+ guchar *name;
+ subid_t *id;
+ guint isUseful;
+};
+
+struct _TT {
+ guint totalNumModules;
+ guint totalNumTypeDefs;
+ guint totalNumTypes;
+ guint totalNumTags;
+ guint totalNumStrings;
+ guint totalLenStrings;
+} TT;
+
+#define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
+
+guint
+get_asn1_int(guint want_tag, guint offset)
+{
+ ASN1_SCK asn1;
+ guint ret, cls, con, tag, def, len;
+ guint value;
+
+ /* g_message("%d get_asn1_int", offset); */
+
+ asn1_open(&asn1, asn1_desc, offset);
+
+ ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
+ if (ret == ASN1_ERR_NOERROR) {
+ /* do not check class, both Unversal and Context are OK */
+ if (con == ASN1_PRI && tag == want_tag) {
+ if (def) {
+ asn1_uint32_value_decode(&asn1, len, &value);
+ return value;
+ } else
+ ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
+ } else
+ ret = ASN1_ERR_WRONG_TYPE;
+ }
+ g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
+
+ return 0;
+}
+
+subid_t * /* with prepended length ..... */
+get_asn1_oid(guint want_tag, guint offset)
+{
+ ASN1_SCK asn1;
+ guint ret, cls, con, tag, def, len;
+ subid_t *oid;
+
+ /* g_message("%d get_asn1_oid", offset); */
+
+ asn1_open(&asn1, asn1_desc, offset);
+
+ ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
+ if (ret == ASN1_ERR_NOERROR) {
+ /* do not check class, both Unversal and Context are OK */
+ if ((con == ASN1_PRI) && (tag == want_tag)) {
+ if (def) {
+ asn1_oid_value_decode(&asn1, len, &oid, &con);
+ oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
+ memmove(&oid[1], oid, con*sizeof(guint));
+ oid[0] = con;;
+ return oid;
+ } else
+ ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
+ } else
+ ret = ASN1_ERR_WRONG_TYPE;
+ }
+ g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
+
+ return 0;
+}
+
+guchar * /* 0 terminated string */
+get_asn1_string(guint want_tag, guint offset)
+{
+ ASN1_SCK asn1;
+ guint ret, cls, con, tag, def, len;
+ guchar *octets;
+
+ /* g_message("%d get_asn1_string", offset); */
+
+ asn1_open(&asn1, asn1_desc, offset);
+
+ ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
+ if (ret == ASN1_ERR_NOERROR) {
+ /* do not check class, both Unversal and Context are OK */
+ if ((con == ASN1_PRI) && (tag == want_tag)) {
+ if (def) {
+ asn1_string_value_decode(&asn1, len, &octets);
+ octets = g_realloc(octets, len+1); /* need space for sentinel */
+ octets[len] = 0;
+ return octets;
+ } else
+ ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
+ } else
+ ret = ASN1_ERR_WRONG_TYPE;
+ }
+ g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
+
+ return 0;
+}
+
+guint
+get_asn1_uint(guint offset)
+{
+ ASN1_SCK asn1;
+ guint ret, len, value;
+
+ /* g_message( "%d get_asn1_uint", offset); */
+
+ asn1_open(&asn1, asn1_desc, offset);
+
+ ret = asn1_uint32_decode(&asn1, &value, &len);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
+ value = 0;
+ }
+ return value;
+}
+
+gboolean
+check_tag(guint want_tag, guint offset)
+{
+ ASN1_SCK asn1;
+ guint ret, cls, con, tag, def, len;
+
+ asn1_open(&asn1, asn1_desc, offset);
+
+ ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
+ if (ret == ASN1_ERR_NOERROR) {
+ ret = (tag == want_tag) ? TRUE : FALSE;
+ /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
+ return ret;
+ }
+ g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
+
+ return FALSE;
+}
+
+gboolean
+constructed(guint offset)
+{
+ ASN1_SCK asn1;
+ guint ret, cls, con, tag, def, len;
+
+ /* g_message("%d constructed?", offset); */
+
+ asn1_open(&asn1, asn1_desc, offset);
+
+ ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
+ if (ret == ASN1_ERR_NOERROR) {
+ if (con) {
+ return TRUE;
+ }
+ return FALSE;
+ }
+ /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
+
+ return FALSE;
+}
+
+void
+define_constraint(GNode *p, GNode *q)
+{
+ TBLRange *range = g_malloc(sizeof(TBLRange));
+ g_node_append_data(q, range);
+
+ range->type = TBLTYPE_Range;
+
+ /* g_message("define_constraint %p, %p", p, q); */
+
+ p = g_node_first_child(p);
+
+ range->from = get_asn1_int(0, (guint)p->data);
+ p = g_node_next_sibling(p);
+
+ range->to = get_asn1_int(1, (guint)p->data);
+
+}
+
+void
+define_namednumber(GNode *p, GNode *q)
+{
+ TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
+ g_node_append_data(q, num);
+
+ num->type = TBLTYPE_NamedNumber;
+
+ /* g_message("define_namednumber %p, %p", p, q); */
+
+ p = g_node_first_child(p);
+
+ num->name = get_asn1_string(0, (guint)p->data);
+ p = g_node_next_sibling(p);
+
+ num->value = get_asn1_int(1, (guint)p->data);
+}
+
+void
+define_typeref(GNode *p, GNode *q)
+{
+ TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
+ g_node_append_data(q, ref);
+
+ ref->type = TBLTYPE_TypeRef;
+
+ /* g_message("define_typeref %p, %p", p, q); */
+
+ p = g_node_first_child(p);
+
+ ref->typeDefId = get_asn1_uint((guint)p->data);
+ p = g_node_next_sibling(p);
+
+ ref->implicit = get_asn1_int(ASN1_BOL, (guint)p->data);
+}
+
+void
+define_tag(GNode *p, GNode *q)
+{
+ TBLTag *type = g_malloc(sizeof(TBLTag));
+ g_node_append_data(q, type);
+
+ type->type = TBLTYPE_Tag;
+
+ /* g_message("define_tag %p, %p", p, q); */
+
+ p = g_node_first_child(p);
+
+ type->tclass = get_asn1_int(ASN1_ENUM, (guint)p->data);
+ p = g_node_next_sibling(p);
+
+ type->code = get_asn1_int(ASN1_INT, (guint)p->data);
+
+}
+
+void
+define_type(GNode *p, GNode *q)
+{
+ GNode *r;
+ TBLType *type = g_malloc(sizeof(TBLType));
+
+ GNode *t = g_node_append_data(q, type);
+
+ type->type = TBLTYPE_Type;
+
+ /* g_message("define_type %p, %p", p, q); */
+
+ type->typeId = get_asn1_int(0, (guint)p->data);
+ p = g_node_next_sibling(p);
+
+ type->optional = get_asn1_int(1, (guint)p->data);
+ p = g_node_next_sibling(p);
+
+ if (check_tag(2, (guint)p->data)) { /* optional, need empty node if not there ?*/
+ r = g_node_first_child(p);
+ while (r) {
+ define_tag(r, t);
+ r = g_node_next_sibling(r);
+ }
+ p = g_node_next_sibling(p);
+ }
+
+ if (!check_tag(3, (guint)p->data)) {
+ g_warning("expect tag 3, ERROR");
+ }
+ r = g_node_first_child(p);
+ /* a choice ... */
+ type->content = TBLTYPETYPE_None;
+ if (check_tag(0, (guint)r->data)) type->content = TBLTYPETYPE_Primitive;
+ if (check_tag(1, (guint)r->data)) type->content = TBLTYPETYPE_Elements;
+ if (check_tag(2, (guint)r->data)) type->content = TBLTYPETYPE_TypeRef;
+ switch(type->content) {
+ case TBLTYPETYPE_Primitive:
+ break;
+ case TBLTYPETYPE_Elements:
+ r = g_node_first_child(r);
+ while (r) {
+ define_type(g_node_first_child(r), t);
+ r = g_node_next_sibling(r);
+ }
+ break;
+ case TBLTYPETYPE_TypeRef:
+ define_typeref(r, t);
+ break;
+ case TBLTYPETYPE_None:
+ g_warning("expected a contents choice, error");
+ break;
+ }
+ p = g_node_next_sibling(p);
+
+ type->fieldName = 0;
+ type->anonymous = FALSE;
+ if (p && check_tag(4, (guint)p->data)) {
+ type->fieldName = get_asn1_string(4, (guint)p->data);
+ p = g_node_next_sibling(p);
+ } else {
+ type->anonymous = TRUE;
+ }
+
+ type->constraint = FALSE;
+ if (p && check_tag(5, (guint)p->data)) {
+ type->constraint = TRUE;
+ define_constraint(p, t);
+ p = g_node_next_sibling(p);
+ }
+
+ if (p && check_tag(6, (guint)p->data)) {
+ r = g_node_first_child(p);
+ while(r) {
+ define_namednumber(r, t);
+ r = g_node_next_sibling(r);
+ }
+ }
+}
+
+void
+define_typedef(GNode *p, GNode *q)
+{
+ TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
+
+ GNode *t = g_node_append_data(q, type_def);
+
+ /* g_message("define_typedef %p, %p", p, q); */
+
+ type_def->type = TBLTYPE_TypeDef;
+
+ p = g_node_first_child(p);
+
+ type_def->typeDefId = get_asn1_uint((guint)p->data);
+ p = g_node_next_sibling(p);
+
+ type_def->typeName = get_asn1_string(ASN1_PRNSTR, (guint)p->data);
+ p = g_node_next_sibling(p);
+
+ define_type(g_node_first_child(p), t);
+ p = g_node_next_sibling(p);
+
+ type_def->isPdu = (p != 0); /* true if it exists, value ignored */
+}
+
+void
+define_module(GNode *p, GNode *q)
+{
+ TBLModule *module = g_malloc(sizeof(TBLModule));
+
+ GNode *m = g_node_append_data(q, module);
+
+ /* g_message("define_module %p %p", p, q); */
+
+ module->type = TBLTYPE_Module;
+
+ p = g_node_first_child(p);
+
+ module->name = get_asn1_string(0, (guint)p->data);
+ p = g_node_next_sibling(p);
+
+ module->id = 0;
+ if (check_tag(1, (guint)p->data)) { /* optional */
+ module->id = get_asn1_oid(1, (guint)p->data);
+ p = g_node_next_sibling(p);
+ }
+
+ module->isUseful = get_asn1_int(2, (guint)p->data);
+ p = g_node_next_sibling(p);
+
+ p = g_node_first_child(p);
+ while (p) {
+ define_typedef(p, m);
+ p = g_node_next_sibling(p);
+ }
+}
+
+typedef struct _SearchDef SearchDef;
+struct _SearchDef {
+ char *key;
+ GNode *here;
+};
+
+gboolean
+is_typedef(GNode *node, gpointer data)
+{
+ TBLTypeDef *d = (TBLTypeDef *)node->data;
+ SearchDef *s = (SearchDef *)data;
+
+ if (d == 0) return FALSE;
+ if (d->type != TBLTYPE_TypeDef) return FALSE;
+ if (strcmp(s->key, d->typeName) == 0) {
+ s->here = node;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+typedef struct _TypeRef TypeRef;
+struct _TypeRef {
+ GNode *type;
+ char *name;
+ guchar defclass;
+ guint deftag;
+ GNode *pdu; /* location in PDU descriptor tree */
+ guint level; /* recursion counter */
+ GNode *typetree;
+ GPtrArray *refs; /* pointers to PDUinfo structures teferencing this entry */
+};
+
+typedef struct _NameDefs NameDefs;
+struct _NameDefs {
+ guint max;
+ guint used;
+ TypeRef *info;
+};
+#define ALLOC_INCR 4
+#define CLASSREF (ASN1_PRV+1)
+
+gboolean
+is_named(GNode *node, gpointer data)
+{
+ TBLNamedNumber *num = (TBLNamedNumber *)node->data;
+ NameDefs *n = (NameDefs *)data;
+ guint oldmax;
+
+ if (num == 0) return FALSE;
+ if (num->type != TBLTYPE_NamedNumber) return FALSE;
+
+ if (num->value >= n->max) { /* need larger array */
+ oldmax = n->max;
+ n->max = num->value + ALLOC_INCR;
+ n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
+ memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
+ }
+ if (num->value > n->used) /* track max used value, there may be holes... */
+ n->used = num->value;
+
+ n->info[num->value].name = num->name;
+
+ return FALSE;
+}
+
+gboolean
+index_typedef(GNode *node, gpointer data)
+{
+ TBLTypeDef *d = (TBLTypeDef *)node->data;
+ NameDefs *n = (NameDefs *)data;
+ TypeRef *t;
+ TBLTag *tag;
+ guint oldmax;
+
+ if (d == 0) return FALSE;
+ if (d->type != TBLTYPE_TypeDef) return FALSE;
+
+ if (d->typeDefId >= n->max) { /* need larger array */
+ oldmax = n->max;
+ n->max = d->typeDefId + ALLOC_INCR;
+ n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
+ memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
+ }
+ if (d->typeDefId > n->used) /* track max used value, there may be holes... */
+ n->used = d->typeDefId;
+
+ t = &(n->info[d->typeDefId]);
+ t->name = d->typeName;
+ t->type = node;
+ t->refs = g_ptr_array_new(); /* collect references here */
+ node = g_node_first_child(node); /* the real type */
+ tag = (TBLTag *)node->data;
+ if ((tag->type == TBLTYPE_Type) && (((TBLType *)tag)->typeId == TBL_CHOICE)) {
+ /* no reasonable default... ! */
+ t->defclass = 3; /* Private .... */
+ t->deftag= 9999; /* a random value */
+ } else {
+ node = g_node_first_child(node); /* the default tag */
+ tag = (TBLTag *)node->data;
+ switch(tag->type) {
+ case TBLTYPE_Tag:
+ t->defclass = tag->tclass;
+ t->deftag = tag->code;
+ break;
+ case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
+ t->defclass = CLASSREF; /* invalid class.. */
+ t->deftag = ((TBLTypeRef *)tag)->typeDefId;
+ break;
+ default:
+ g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
+ data_types[tag->type]);
+ t->defclass = 3; /* Private .... */
+ t->deftag= 9998; /* another random value */
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+TypeRef *typeDef_names = 0;
+guint numTypedefs = 0;
+
+void
+get_values() /* collect values from ASN.1 tree */
+ /* coded according to the tbl.asn1 description of snacc output */
+{ /* This routine does not leave references to the tvbuff or */
+ /* to the asn1_nodes, both can be freed by the caller of this.*/
+ GNode *p;
+ SearchDef sd;
+ NameDefs nd;
+ guint i;
+ char X, *t, *s, *E;
+ static char missing[] = " **missing** ";
+
+ if (asn1_verbose) g_message("interpreting tree");
+ typeDef_names = 0; /* just forget allocated any data .... */
+
+ if (data_nodes)
+ g_node_destroy(data_nodes);
+
+ data_nodes = g_node_new(0);
+
+ p = g_node_first_child(asn1_nodes); /* top of the data tree */
+
+ p = g_node_first_child(p);
+ TT.totalNumModules = get_asn1_uint((guint)p->data);
+ p = g_node_next_sibling(p);
+ TT.totalNumTypeDefs = get_asn1_uint((guint)p->data);
+ p = g_node_next_sibling(p);
+ TT.totalNumTypes = get_asn1_uint((guint)p->data);
+ p = g_node_next_sibling(p);
+ TT.totalNumTags = get_asn1_uint((guint)p->data);
+ p = g_node_next_sibling(p);
+ TT.totalNumStrings = get_asn1_uint((guint)p->data);
+ p = g_node_next_sibling(p);
+ TT.totalLenStrings = get_asn1_uint((guint)p->data);
+ p = g_node_next_sibling(p);
+
+ p = g_node_first_child(p);
+ while (p) {
+ define_module(p, data_nodes);
+ p = g_node_next_sibling(p);
+ }
+
+ /* g_message("finished with tree"); */
+
+ if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
+ sd.key = "TBLTypeId";
+ sd.here = 0;
+ g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
+ if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", sd.here);
+ if (sd.here) {
+ nd.max = 8;
+ nd.used = 0;
+ nd.info = g_malloc0(nd.max * sizeof(TypeRef));
+ g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
+ (gpointer)&nd);
+ if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, nd.info);
+ E = empty;
+ for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
+ X = 'X';
+ t = TBLTYPE(i);
+ s = nd.info[i].name;
+ if (s == 0) s = missing;
+ if (g_strcmp(t, s) == 0) { /* OK ! */
+ X = ' ';
+ t = empty;
+ } else {
+ E = ", X with errors X";
+ }
+ if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
+ }
+ if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
+ }
+ tbl_types_verified = TRUE;
+ }
+ /* build table with typedef names */
+ nd.max = 8;
+ nd.used = 0;
+ nd.info = g_malloc0(nd.max * sizeof(TypeRef));
+ g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
+ if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, nd.info);
+
+ for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
+ TypeRef *ref = &(nd.info[i]);
+ t = ref->name;
+ if (t == 0) {
+ t = ref->name = missing;
+ if (asn1_verbose) g_message(" %3d %s", i, t);
+ } else {
+ if (asn1_verbose) g_message(" %3d %s, %c%d", i, t,
+ tag_class[ref->defclass], ref->deftag);
+ }
+ if (ref->pdu) { /* should be 0 */
+ if (asn1_verbose) g_message("* %3d %s pdu=%p", i, t, ref->pdu);
+ }
+ }
+ typeDef_names = nd.info;
+ numTypedefs = i;
+ if (asn1_verbose) g_message("OK, %d TBLTypeDef's index set up", numTypedefs);
+
+}
+
+void
+showGNode(GNode *p, int n)
+{
+ if (p == 0) return;
+ n *=2; /* 2 spaces per level */
+ if (p->data) { /* show value ... */
+ /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
+ switch (((TBLTag *)p->data)->type) {
+ case TBLTYPE_Module: {
+ TBLModule *m = (TBLModule *)p->data;
+ if (asn1_verbose)
+ g_message("%*smodule %s%s", n, empty, m->name,
+ m->isUseful ? ", useful" : empty);
+ };
+ break;
+ case TBLTYPE_TypeDef: {
+ TBLTypeDef *t = (TBLTypeDef *)p->data;
+ if (asn1_verbose)
+ g_message("%*stypedef %d %s%s", n, empty, t->typeDefId, t->typeName,
+ t->isPdu ? ", isPDU" : empty);
+ };
+ break;
+ case TBLTYPE_Type: {
+ TBLType *t = (TBLType *)p->data;
+ char *fn, *s = empty;
+ if (t->fieldName)
+ s = t->fieldName;
+ /* typeId is a value from enum TBLTypeId */
+ fn = TBLTYPE(t->typeId);
+ if (asn1_verbose) g_message("%*stype %d[%s]%s [%s]", n, empty, t->typeId, fn,
+ t->optional ? " opt" : empty, s );
+ };
+ break;
+ case TBLTYPE_Tag: {
+ TBLTag *t = (TBLTag *)p->data;
+ char *s = empty;
+ if ((t->tclass == ASN1_UNI) && (t->code < 32))
+ s = asn1_tag[t->code];
+ if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
+ tag_class[t->tclass], t->code, s);
+ };
+ break;
+ case TBLTYPE_NamedNumber: {
+ TBLNamedNumber *nn = (TBLNamedNumber *)p->data;
+ if (asn1_verbose) g_message("%*snamednumber %2d %s", n, empty,
+ nn->value, nn->name);
+ };
+ break;
+ case TBLTYPE_Range: {
+ TBLRange *r = (TBLRange *)p->data;
+ if (asn1_verbose) g_message("%*srange %d .. %d", n, empty,
+ r->from, r->to );
+ };
+ break;
+ case TBLTYPE_TypeRef: {
+ TBLTypeRef *r = (TBLTypeRef *)p->data;
+ char *s = empty;
+ if (typeDef_names)
+ s = typeDef_names[r->typeDefId].name;
+ if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
+ r->typeDefId, s, r->implicit ? ", implicit" : empty );
+ };
+ break;
+ default: {
+ TBLTag *x = (TBLTag *)p->data;
+ if (asn1_verbose) g_message("%*s--default-- type=%d", n, empty, x->type);
+ };
+ break;
+ }
+ } else { /* just show tree */
+ if (asn1_verbose)
+ g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
+ n, empty, p, p->data, p->next, p->prev, p->parent, p->children);
+ }
+}
+
+void
+showGNodes(GNode *p, int n)
+{
+ if (p == 0) return;
+ showGNode(p, n);
+ showGNodes(p->children, n+1);
+ showGNodes(p->next, n);
+}
+
+void showGenv(GNode *p, int n, int m)
+{
+ int i;
+
+ if (p == 0) return;
+ if (n > m) {
+ if (asn1_verbose) g_message("%*s.....", n*2, empty);
+ return;
+ }
+
+ for(i=0; p && (i < 3); p = p->next, i++) {
+ showGNode(p, n);
+ showGenv(p->children, n+1, m);
+ }
+ if (p && asn1_verbose) g_message("%*s.....", n*2, empty);
+
+}
+
+void
+debug_dump_TT() /* dump contents of TT struct, for debugging */
+{
+ if (asn1_verbose)
+ g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
+ TT.totalNumModules,
+ TT.totalNumTypeDefs,
+ TT.totalNumTypes,
+ TT.totalNumTags,
+ TT.totalNumStrings,
+ TT.totalLenStrings);
+}
+
+void
+my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
+ const gchar *message, gpointer user_data)
+{
+static FILE* logf = 0;
+static char eol[] = "\r\n";
+
+ (void) log_domain; (void) log_level; (void) user_data; /* make references */
+
+ if (logf == 0) {
+ logf = fopen(asn1_logfile, "w");
+ }
+ fputs(message, logf);
+ fputs(eol, logf);
+}
+
+void
+read_asn1_type_table(char *filename)
+{
+ FILE *f;
+ guint size;
+ guchar *data;
+ struct stat stat;
+
+ f = fopen(filename, "rb");
+ if (f == 0) {
+ g_warning("error opening %s, %s", filename, strerror(errno));
+ return;
+ }
+ fstat(fileno(f), &stat);
+ size = (int)stat.st_size;
+ if (size == 0) {
+ if (asn1_verbose) g_message("file %s is empty, ignored", filename);
+ fclose(f);
+ return;
+ }
+ if (asn1_verbose) g_message("reading %d bytes from %s", size, filename);
+
+ data = g_malloc(size);
+ if (fread(data, size, 1, f) < 1) {
+ g_warning("error reading %s, %s", filename, strerror(errno));
+ }
+ fclose(f);
+
+ if (asn1_verbose) {
+ /* ***** from the time when logging was just in a console... *****
+ * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
+ * " Sleep 5 sec...");
+ * Sleep(5 * 1000);
+ */
+
+ static guint mylogh = 0;
+
+ g_message("logging to file %s", asn1_logfile);
+
+ if (mylogh == 0) {
+ mylogh = g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
+ | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
+ }
+ }
+
+ asn1_desc = tvb_new_real_data(data, size, size);
+
+ tt_build_tree();
+ if (asn1_verbose) g_message("read %d items from %s", icount, filename);
+
+ /* list_modules(); */
+
+ get_values();
+
+ g_node_destroy(asn1_nodes); asn1_nodes = 0;
+#ifndef WIN32 /* tvb_free not yet exported to plugins... */
+ tvb_free(asn1_desc);
+#endif
+ asn1_desc = 0;
+ g_free(data); data = 0;
+
+ showGNodes(data_nodes, 0);
+
+ debug_dump_TT();
+}
+
+typedef struct _PDUinfo PDUinfo;
+struct _PDUinfo {
+ guint type;
+ char *name;
+ char *typename;
+ char *fullname;
+ guchar tclass;
+ guint tag;
+ guint flags;
+ GNode *reference;
+ gint typenum;
+ gint basetype; /* parent type */
+ gint mytype; /* original type number, typenum may have gone through a reference */
+ gint value_id; /* ethereal field id for the value in this PDU */
+ gint type_id; /* ethereal field id for the type of this PDU */
+ hf_register_info value_hf; /* ethereal field info for this value */
+};
+
+
+/* bits in the flags collection */
+#define PDU_OPTIONAL 1
+#define PDU_IMPLICIT 2
+#define PDU_NAMEDNUM 4
+#define PDU_REFERENCE 8
+#define PDU_TYPEDEF 0x10
+#define PDU_ANONYMOUS 0x20
+#define PDU_TYPETREE 0x40
+
+#define PDU_CHOICE 0x08000000 /* manipulated by the PDUname routine */
+
+guint PDUinfo_initflags = 0; /* default flags for newly allocated PDUinfo structs */
+
+#define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
+ g_warning("**** unexpected type %s, want %s, at line %d", \
+ data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
+
+
+void
+save_reference(PDUinfo *p)
+{
+ gint i = p->mytype;
+
+ if (i == -1)
+ i = p->basetype;
+
+ g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
+}
+
+void
+tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex);
+
+
+
+ /* evaluate typeref, pointer to current pdu node and typedef */
+void
+tbl_typeref(guint n, GNode *pdu, GNode *tree, guint fullindex)
+{
+ GNode *q;
+ PDUinfo *p = (PDUinfo *)pdu->data, *p1;
+ guint nvals;
+ value_string *v;
+
+ CHECKTYPE(tree, TBLTYPE_TypeDef);
+
+ if (asn1_verbose) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n*2, empty,
+ p->name, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
+
+ p->typenum = ((TBLTypeDef *)tree->data)->typeDefId; /* name of current type */
+ p->flags |= PDU_TYPEDEF;
+
+ tree = g_node_first_child(tree); /* move to its underlying type */
+ CHECKTYPE(tree, TBLTYPE_Type);
+ p->type = ((TBLType *)tree->data)->typeId;
+
+ q = g_node_first_child(tree); /* the tag of this type entry ... is optional... */
+ if (((TBLTag *)q->data)->type == TBLTYPE_Tag) {
+ if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
+ guint xcls, xtag;
+ xcls = p->tclass;
+ xtag = p->tag;
+ /* XXX -- hack -- hack -- hack -- hack -- hack --
+ * only change tag when class+tag == EOC,
+ * or class is a reference,
+ * or new class is not universal.
+ */
+ if ( ((xcls|xtag) == 0) || (xcls == CLASSREF) ||
+ (((TBLTag *)q->data)->tclass != ASN1_UNI) ) {
+ p->tclass = ((TBLTag *)q->data)->tclass;
+ p->tag = ((TBLTag *)q->data)->code;
+ if (asn1_verbose)
+ g_message("%*s*change typeref tag from %c%d to %c%d",
+ n*2, empty,
+ tag_class[xcls],
+ xtag,
+ tag_class[p->tclass],
+ p->tag);
+ } else {
+ if (asn1_verbose)
+ g_message("%*sNOT changing tag from %c%d to %c%d",
+ n*2, empty,
+ tag_class[xcls],
+ xtag,
+ tag_class[((TBLTag *)q->data)->tclass],
+ ((TBLTag *)q->data)->code);
+
+ }
+ }
+ } else {
+ char ss[128];
+
+ ss[0] = 0;
+ if (p->tclass==CLASSREF)
+ snprintf(ss, 128, ", CLASSREF %d", p->tag);
+ if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
+
+ if (p->tclass==CLASSREF) {
+ TypeRef *tr;
+ /* CLASSREF....., get it defined using type of the reference */
+
+ tr = &typeDef_names[p->tag];
+ if (asn1_verbose)
+ g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
+ p->tag, tr->name, tr->pdu);
+
+ tbl_typeref(n+1, pdu, tr->type, fullindex);
+
+ return;
+ }
+ }
+
+ if (asn1_verbose)
+ g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n*2, empty, p->typenum,
+ p->name, p->typename, p, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
+
+ switch(p->type) {
+ case TBL_BITSTRING:
+ case TBL_ENUMERATED:
+ /* names do not have a fullname */
+ if (asn1_verbose) g_message("%*s*collection T %s", n*2, empty, p->name);
+ /* read the enumeration [save min-max somewhere ?] */
+ p->value_hf.hfinfo.type = tbl_types_ethereal[p->type]; /* XXX change field type... */
+
+ proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
+
+ save_reference(p);
+
+ if (asn1_verbose)
+ g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
+ p->mytype, p->typenum, p->basetype, p->flags, p->typename,
+ p->name, p->fullname,
+ tbl_types_ethereal_txt[p->type], p->value_id);
+ p1 = p;
+ nvals = 0;
+ while((q = g_node_next_sibling(q))) {
+ CHECKTYPE(q, TBLTYPE_NamedNumber);
+ p = g_malloc0(sizeof(PDUinfo));
+ nvals++;
+ p->type = TBL_ENUMERATED;
+ p->name = (((TBLNamedNumber *)q->data)->name);
+ p->tag = (((TBLNamedNumber *)q->data)->value);
+ p->flags = PDU_NAMEDNUM;
+ if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
+ g_node_append_data(pdu, p);
+ }
+
+ /* list all enum values in the field structure for matching */
+ p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
+ q = g_node_first_child(pdu);
+ nvals = 0;
+ while(q) {
+ p = (PDUinfo *)q->data;
+ v[nvals].value = p->tag;
+ v[nvals].strptr = p->name;
+/* g_message("enumval2: %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
+ nvals++;
+ q = g_node_next_sibling(q);
+ }
+ /* last entry is already initialized to { 0, NULL } */
+
+ break;
+
+ case TBL_CHOICE:
+ if (p->value_id == -1) { /* not yet registered ..... */
+ p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
+ proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
+
+ save_reference(p);
+
+ if (asn1_verbose)
+ g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
+ p->mytype, p->typenum, p->basetype, p->flags, p->typename,
+ p->name, p->fullname,
+ tbl_types_ethereal_txt[p->type], p->value_id);
+ }
+ tbl_type(n, pdu, q, fullindex);
+ break;
+
+ default:
+ if (p->value_id == -1) { /* not yet registered ..... */
+ p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
+ proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
+
+ save_reference(p);
+
+ if (asn1_verbose)
+ g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
+ p->mytype, p->typenum, p->basetype, p->flags, p->typename,
+ p->name, p->fullname,
+ tbl_types_ethereal_txt[p->type], p->value_id);
+ }
+ tbl_type(n, pdu, g_node_next_sibling(q), fullindex);
+ }
+}
+
+void
+tbl_type(guint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
+{
+ GNode *q, *pdu1;
+ PDUinfo *p, *p1;
+ guint ni;
+ guint nvals;
+ value_string *v;
+
+ if (n > 40) { /* don't believe this....! ...... stop recursion ...... */
+ g_warning("**** n>40, return [recursion too deep] ****************");
+ return;
+ }
+
+ /* showGenv(list, n, n+1); */
+
+ ni = fullindex;
+ pdu1 = pdu; /* save start location for append */
+ while (list) { /* handle all entries */
+ if (asn1_verbose)
+ g_message("%*s+handle a %s", n*2, empty,
+ data_types[((TBLTag *)list->data)->type]);
+
+ if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
+ list = g_node_next_sibling(list);
+ if (asn1_verbose) g_message("%*s*skip range", n*2, empty);
+ if (list == 0)
+ break;
+ }
+
+ if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
+ CHECKTYPE(list, TBLTYPE_Type);
+
+ p = g_malloc0(sizeof(PDUinfo));
+ pdu = g_node_append_data(pdu1, p);
+
+ p->type = ((TBLType *)list->data)->typeId;
+ p->typename = tbl_types_asn1[p->type]; /* the default type */
+ p->typenum = -1;
+ p->mytype = -1;
+ p->basetype = ((PDUinfo *)pdu1->data)->typenum;
+ p->flags = PDUinfo_initflags;
+ p->flags |= (((TBLType *)list->data)->anonymous ? PDU_ANONYMOUS : 0);
+ p->flags |= (((TBLType *)list->data)->optional ? PDU_OPTIONAL : 0);
+
+ if (((TBLType *)list->data)->fieldName == 0) { /* no name assigned */
+ /* assign an anonymous name [XXX refer to parent typename...] */
+ ((TBLType *)list->data)->fieldName =
+ g_strdup_printf("anon%d", anonCount++);
+ }
+ p->name = ((TBLType *)list->data)->fieldName;
+
+ ni = fullindex;
+ ni += sprintf(&fieldname[ni], ".%s", p->name);
+ p->fullname = g_strdup(fieldname);
+
+ /* initialize field info */
+ p->value_id = -1;
+ p->type_id = -1;
+ p->value_hf.p_id = &(p->value_id);
+ p->value_hf.hfinfo.name = p->fullname;
+ p->value_hf.hfinfo.abbrev = p->fullname;
+ p->value_hf.hfinfo.type = tbl_types_ethereal[p->type];
+ p->value_hf.hfinfo.display = BASE_DEC;
+ p->value_hf.hfinfo.blurb = p->fullname;
+ /* all the other fields are already 0 ! */
+
+ if (p->type < TBL__SIMPLE) {
+ /* only register fields with a value here, postpone others */
+ proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
+
+ save_reference(p);
+
+ if (asn1_verbose)
+ g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
+ p->mytype, p->typenum, p->basetype, p->flags,
+ p->typename, p->name, p->fullname,
+ tbl_types_ethereal_txt[p->type], p->value_id);
+ }
+
+ q = g_node_first_child(list);
+ } else {
+ p = (PDUinfo *)pdu->data;
+ q = list;
+ }
+
+
+ if (asn1_verbose) g_message("%*s*switch %s %s", n*2, empty, p->name, TBLTYPE(p->type));
+
+ switch (p->type) {
+ case TBL_BOOLEAN:
+ case TBL_INTEGER:
+ case TBL_OCTETSTRING:
+ case TBL_NULL:
+ case TBL_OID:
+ case TBL_REAL:
+ CHECKTYPE(q, TBLTYPE_Tag);
+ p->tclass = ((TBLTag *)q->data)->tclass;
+ p->tag = ((TBLTag *)q->data)->code;
+ break;
+
+ case TBL_BITSTRING:
+ case TBL_ENUMERATED:
+ CHECKTYPE(q, TBLTYPE_Tag);
+ p->tclass = ((TBLTag *)q->data)->tclass;
+ p->tag = ((TBLTag *)q->data)->code;
+ if (asn1_verbose) g_message("%*s*collection %s", n*2, empty, p->name);
+ /* read the enumeration [save min-max somewhere ?] */
+ nvals = 0;
+ p1 = p;
+ while((q = g_node_next_sibling(q))) {
+ CHECKTYPE(q, TBLTYPE_NamedNumber);
+ p = g_malloc0(sizeof(PDUinfo));
+ nvals++;
+ p->type = TBL_ENUMERATED;
+ p->name = (((TBLNamedNumber *)q->data)->name);
+ p->tag = (((TBLNamedNumber *)q->data)->value);
+ p->flags = PDU_NAMEDNUM;
+ if (asn1_verbose) g_message("%*s %3d %s", n*2, empty, p->tag, p->name);
+ g_node_append_data(pdu, p);
+ }
+
+ /* list all enum values in the field structure for matching */
+ p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
+ q = g_node_first_child(pdu);
+ nvals = 0;
+ while(q) {
+ p = (PDUinfo *)q->data;
+ v[nvals].value = p->tag;
+ v[nvals].strptr = p->name;
+ /* g_message("enumval1: %d %s %d %s", nvals, p1->name, p->tag, p->name); */
+ nvals++;
+ q = g_node_next_sibling(q);
+ }
+ /* last entry is already initialized to { 0, NULL } */
+
+ break;
+
+ case TBL_SEQUENCE:
+ case TBL_SET:
+ case TBL_SEQUENCEOF:
+ case TBL_SETOF:
+ case TBL_CHOICE:
+ CHECKTYPE(q, TBLTYPE_Tag);
+ tbl_type(n+1, pdu, q, ni);
+ break;
+
+ case TBL_TYPEREF: { /* may have a tag ... */
+ TypeRef *tr;
+ guint i;
+ if ( q && (((TBLTag *)q->data)->type == TBLTYPE_Tag)) {
+ if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
+ p->tclass = ((TBLTag *)q->data)->tclass;
+ p->tag = ((TBLTag *)q->data)->code;
+ if (asn1_verbose)
+ g_message("%*s*insert type tag %c%d", n*2, empty,
+ tag_class[p->tclass], p->tag);
+ }
+ q = g_node_next_sibling(q);
+ } else { /* use default tag for this type */
+ tr = &typeDef_names[((TBLTypeRef *)q->data)->typeDefId];
+ if ((((p->flags & PDU_IMPLICIT) == 0) && (tr->defclass != ASN1_UNI)) ||
+ ((p->tclass | p->tag) == 0 )) {
+ /* not implicit, use this tag */
+ p->tclass = tr->defclass;
+ p->tag = tr->deftag;
+ if (asn1_verbose) g_message("%*s*set tag %c%d", n*2, empty,
+ tag_class[p->tclass], p->tag);
+ }
+ }
+ CHECKTYPE(q, TBLTYPE_TypeRef);
+ i = ((TBLTypeRef *)q->data)->typeDefId;
+ p->mytype = i;
+ tr = &typeDef_names[i];
+ if (asn1_verbose)
+ g_message("%*s*type#%d %s, %p", n*2, empty, i, tr->name, tr->pdu);
+ p->typename = tr->name;
+
+ if (tr->defclass == CLASSREF) {
+ if (tr->pdu == 0)
+ tr->pdu = pdu; /* remember this reference */
+ i = tr->deftag;
+ tr = &typeDef_names[i];
+ if (asn1_verbose)
+ g_message("%*s*refer to type#%d %s, %p", n*2, empty,
+ i, tr->name, tr->pdu);
+ }
+ /* evaluate reference if not done before or when below recursion limit */
+ if ((tr->pdu == 0) || (tr->level < type_recursion_level)) {
+ tr->level++;
+ if (tr->pdu == 0) {
+ tr->pdu = pdu; /* save for references we leave */
+ }
+ p->flags |= ((TBLTypeRef *)q->data)->implicit? PDU_IMPLICIT : 0;
+ if (asn1_verbose)
+ g_message("%*s*typeref %s > %s%s at %p", n*2, empty,
+ p->name,
+ ((TBLTypeRef *)q->data)->implicit?"implicit ":empty,
+ tr->name,
+ pdu);
+ tbl_typeref(n+1, pdu, tr->type, ni);
+ tr->level--;
+ } else {
+ if (asn1_verbose)
+ g_message("%*s*typeref %s > %s already at %p", n*2, empty,
+ p->name, tr->name, tr->pdu);
+ p->flags |= PDU_REFERENCE;
+ p->reference = tr->pdu;
+ }
+ };
+ break;
+ default:
+ g_warning("**** unknown tbl-type %d at line %d", p->type, __LINE__);
+ break;
+ }
+
+ if (asn1_verbose)
+ g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
+ n*2, empty, p->name, p->typename, p, TBLTYPE(p->type),
+ tag_class[p->tclass], p->tag);
+
+ if (p->value_id == -1) { /* not registered before, do it now */
+ proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
+
+ save_reference(p);
+
+ if (asn1_verbose)
+ g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
+ p->mytype, p->typenum, p->basetype, p->flags, p->typename,
+ p->name, p->fullname,
+ tbl_types_ethereal_txt[p->type], p->value_id);
+ }
+ list = g_node_next_sibling(list);
+ }
+}
+
+void
+PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
+{
+ PDUinfo *rinfo;
+ char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
+
+ if (info) {
+ tt = TBLTYPE(info->type);
+ nn = info->name;
+ tn = info->typename;
+ fn = info->fullname;
+ if (info->flags & PDU_NAMEDNUM)
+ txt += sprintf(txt, "name: %2d %s", info->tag, nn);
+ else {
+ if (info->flags & PDU_TYPEDEF)
+ txt += sprintf(txt, "def %d: ", info->typenum);
+ else
+ txt += sprintf(txt, " ");
+ ty = (info->flags & PDU_TYPETREE) ? "typ" : "val";
+ txt += sprintf(txt, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty,tt, tn, nn, fn,
+ tag_class[info->tclass], info->tag, info->value_id, info->type_id);
+ txt += sprintf(txt, ", mt=%d, bt=%d", info->mytype, info->basetype);
+ oo = (info->flags & PDU_OPTIONAL) ? ", optional" : empty;
+ ii = (info->flags & PDU_IMPLICIT) ? ", implicit" : empty;
+ nn = (info->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
+ an = (info->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
+ txt += sprintf(txt, "%s%s%s%s", oo, ii, nn, an);
+ if (info->flags & PDU_REFERENCE) {
+ rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
+ tt = TBLTYPE(rinfo->type);
+ nn = rinfo->name;
+ tn = rinfo->typename;
+ fn = rinfo->fullname;
+ txt += sprintf(txt, ", reference to %s (%s)%s [%s]", tt, tn, nn, fn);
+ if (rinfo->flags & PDU_TYPEDEF)
+ txt += sprintf(txt, " T%d", rinfo->typenum);
+ txt += sprintf(txt, " tag %c%d", tag_class[rinfo->tclass], rinfo->tag);
+ oo = (rinfo->flags & PDU_OPTIONAL) ? ", optional" : empty;
+ ii = (rinfo->flags & PDU_IMPLICIT) ? ", implicit" : empty;
+ nn = (rinfo->flags & PDU_NAMEDNUM) ? ", namednum" : empty;
+ tn = (rinfo->flags & PDU_REFERENCE) ? ", reference" : empty;
+ tt = (rinfo->flags & PDU_TYPEDEF) ? ", typedef" : empty;
+ an = (rinfo->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
+ tr = (rinfo->flags & PDU_TYPETREE) ? ", typetree" : empty;
+ txt += sprintf(txt, "%s%s%s%s%s%s%s", oo, ii, nn, tn, tt, an, tr);
+ }
+ }
+ } else {
+ strcpy(txt, "no info available");
+ }
+
+ return;
+}
+
+
+void
+showPDUtree(GNode *p, int n)
+{
+ PDUinfo *info;
+ char text[400];
+
+ while (p != 0) {
+ info = (PDUinfo *)p->data;
+
+ PDUtext(text, info);
+
+ if (asn1_verbose) g_message("%*s%s", n*2, empty, text);
+
+ showPDUtree(g_node_first_child(p), n+1);
+
+ p = g_node_next_sibling(p);
+ }
+
+ return;
+}
+
+gboolean
+build_pdu_tree(char *pduname)
+{
+ SearchDef sd;
+ guint pdudef, i, tcount;
+ guint sav_len;
+ PDUinfo *info;
+
+ if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
+
+ sd.key = pduname;
+ sd.here = 0;
+ g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
+ if (sd.here) {
+ pdudef = ((TBLTypeDef *)(sd.here->data))->typeDefId;
+ if (asn1_verbose) g_message("%s found, %p, typedef %d", sd.key, sd.here, pdudef);
+ } else {
+ if (asn1_verbose) g_message("%s not found, ignored", sd.key);
+ return FALSE;
+ }
+
+ /* initialize the PDU tree, hand craft the root entry */
+
+ info = g_malloc0(sizeof(PDUinfo));
+ info->name = pduname;
+ info->typename = pduname;
+ info->type = TBL_SEQUENCEOF;
+ info->fullname = g_strdup_printf("%s.%s", pabbrev, pduname);
+ info->flags = PDUinfo_initflags = 0;
+ info->value_id = -1;
+ info->type_id = -1;
+ info->basetype = -1;
+ info->mytype = pdudef;
+
+ info->value_hf.p_id = &(info->value_id);
+ info->value_hf.hfinfo.name = info->fullname;
+ info->value_hf.hfinfo.abbrev = info->fullname;
+ info->value_hf.hfinfo.type = tbl_types_ethereal[info->type];
+ info->value_hf.hfinfo.display = BASE_DEC;
+ info->value_hf.hfinfo.blurb = info->fullname;
+
+ anonCount = 0; /* anonymous types counter */
+
+ PDUtree = g_node_new(info);
+ pabbrev_pdu_len = sprintf(fieldname, "%s.%s.", pabbrev, pduname);
+ sav_len = pabbrev_pdu_len;
+
+ /* Now build the tree for this top level PDU */
+ if (asn1_verbose)
+ g_message("******** Define main type %d, %s", pdudef, pduname);
+ tbl_typeref(0, PDUtree, sd.here, pabbrev_pdu_len-1); /* strip initial . for new names */
+
+ if (asn1_verbose)
+ g_message("%d anonymous types", anonCount);
+
+ /* Now make all types used available for matching */
+ if (asn1_verbose)
+ g_message("Define the types that are actually referenced through the top level PDU");
+ for (i=0, tcount=0; i<numTypedefs; i++) {
+ TypeRef *tr = &(typeDef_names[i]);
+
+ if (tr->pdu) { /* ignore if not used in main pdu */
+ tcount++;
+ if (i == pdudef)
+ g_warning("pdu %d %s defined twice, TopLevel & type", pdudef, pduname);
+ if (asn1_verbose)
+ g_message("******** Define type %d, %s", i, tr->name);
+
+ /* .... do definition ..... */
+ info = g_malloc0(sizeof(PDUinfo));
+ info->name = tr->name;
+ info->typename = tr->name;
+ info->tclass = tr->defclass;
+ info->tag = tr->deftag;
+ info->type = TBL_TYPEREF;
+ info->fullname = g_strdup_printf("%s.--.%s", pabbrev, tr->name);
+ info->flags = PDUinfo_initflags = PDU_TYPETREE;
+ info->value_id = -1;
+ info->type_id = -1;
+ info->basetype = -1;
+ info->mytype = i;
+
+ info->value_hf.p_id = &(info->value_id);
+ info->value_hf.hfinfo.name = info->fullname;
+ info->value_hf.hfinfo.abbrev = info->fullname;
+ info->value_hf.hfinfo.type = tbl_types_ethereal[info->type];
+ info->value_hf.hfinfo.display = BASE_DEC;
+ info->value_hf.hfinfo.blurb = info->fullname;
+
+ tr->typetree = g_node_new(info);
+ pabbrev_pdu_len = sprintf(fieldname, "%s.--.%s.", pabbrev, tr->name);
+ tbl_typeref(0, tr->typetree, tr->type, pabbrev_pdu_len-1);
+ }
+ }
+ if (asn1_verbose)
+ g_message("%d types used", tcount);
+
+ pabbrev_pdu_len = sav_len;
+
+ /* and show the result */
+ if (asn1_verbose)
+ g_message("Type index:");
+ for (i=0; i<numTypedefs; i++) {
+ TypeRef *tr = &(typeDef_names[i]);
+ guint j, k;
+ gint defid;
+ PDUinfo *p, *q;
+ char text[400];
+
+ if (tr->pdu == 0) /* skip if not used */
+ continue;
+
+ if (asn1_verbose)
+ g_message(" %3d %s, %c%d, refs: %d",
+ i, tr->name, tag_class[tr->defclass], tr->deftag,
+ g_ptr_array_len(tr->refs));
+
+ /* get defining node for this type */
+ defid = -1;
+ if (tr->typetree) {
+ p = (PDUinfo *)(tr->typetree->data);
+ defid = p->value_id;
+ if (asn1_verbose)
+ g_message(" -- defining id=%d", defid);
+ }
+ for(j=0; j < g_ptr_array_len(tr->refs); j++) { /* show refs, and set type_id */
+ p = (PDUinfo *)g_ptr_array_index(tr->refs, j);
+ if (p->mytype == (gint)i)
+ p->type_id = defid; /* normal reference */
+ else {
+ if ((p->flags & PDU_TYPETREE) == 0) {
+ /* we have a primitive value, find its real type */
+ for(k=0; k < g_ptr_array_len(tr->refs); k++) {
+ /* look at all refs */
+ q = (PDUinfo *)g_ptr_array_index(tr->refs, k);
+ if ((q->flags & PDU_TYPETREE) == 0)
+ continue; /* only type trees are interresting */
+ if (q->type != p->type)
+ continue; /* must be same types */
+ if (strcmp(q->name, p->name) == 0) {
+ /* OK, take the first we find, not entirely
+ * correct, it may be from a different
+ * base-base type...... XXX */
+ p->type_id = q->value_id;
+ break;
+ }
+ }
+ }
+ }
+
+ if (asn1_verbose) {
+ PDUtext(text, p);
+ g_message(" %s", text);
+ }
+ }
+ }
+
+ if (asn1_verbose)
+ g_message("The resulting PDU tree:");
+ showPDUtree(PDUtree, 0);
+
+ return TRUE;
+}
+
+
+#if GTK_MAJOR_VERSION >= 2
+#define SHOWPDU /* this needs GTK2, which is not yet on Win32 .............. */
+#endif
+#ifdef SHOWPDU
+
+static GtkWidget *window = NULL;
+
+/* the columns in the tree view */
+enum
+{
+ TITLE_COLUMN, /* text in this row */
+ DEF_COLUMN, /* definition in this row, if any */
+ REF_COLUMN, /* referennce from this column, if any */
+ VALUE_COLUMN, /* indicate this is a value */
+ NAME_COLUMN, /* name of this row */
+ N_COLUMNS
+};
+
+FILE *namelist = 0;
+
+void
+build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
+{
+ GtkTreeIter iter2;
+ PDUinfo *info, *rinfo;
+ gint def, ref;
+ guchar *pb;
+
+ char text[400];
+
+ while (p != 0) {
+ info = (PDUinfo *)p->data;
+
+ gtk_tree_store_append (store, &iter2, iter); /* Acquire iterator */
+
+ PDUtext(text, info);
+
+ def = ref = -1;
+ if (info->flags & PDU_TYPEDEF)
+ def = info->typenum;
+
+ if (info->flags & PDU_REFERENCE) {
+ rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
+ ref = rinfo->typenum;
+ }
+ pb = GTK_STOCK_CANCEL;
+ if (G_NODE_IS_LEAF(p)) {
+ if (info->flags & PDU_NAMEDNUM)
+ pb = GTK_STOCK_BOLD;
+ else {
+ pb = GTK_STOCK_YES;
+ if (namelist)
+ fprintf(namelist, "%16s %s\n",
+ &(TBLTYPE(info->type)[4]), info->fullname);
+ }
+ } else {
+ switch (info->type) {
+ case TBL_ENUMERATED:
+ case TBL_BITSTRING:
+ pb = GTK_STOCK_ADD;
+ if (namelist)
+ fprintf(namelist, "%16s %s\n",
+ &(TBLTYPE(info->type)[4]), info->fullname);
+ break;
+ default:
+ break;
+ }
+ }
+
+ gtk_tree_store_set (store, &iter2,
+ TITLE_COLUMN, text,
+ DEF_COLUMN, def,
+ REF_COLUMN, ref,
+ VALUE_COLUMN, pb,
+ NAME_COLUMN, info->fullname,
+ -1);
+
+ build_tree_view(store, g_node_first_child(p), &iter2);
+
+ p = g_node_next_sibling(p);
+ }
+
+ return;
+}
+
+
+struct DefFind {
+ gint def;
+ GtkTreePath *path;
+};
+
+#define PATHSTACKMAX 10
+GtkTreePath *pathstack[PATHSTACKMAX];
+gint pathstackp = 0;
+
+void add_path(GtkTreePath *p)
+{
+ if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
+ gtk_tree_path_free(pathstack[0]); /* we forget about this one */
+ memmove(&pathstack[0], &pathstack[1], (PATHSTACKMAX-1)*sizeof(GtkTreePath *));
+ pathstackp--;
+ }
+ pathstack[pathstackp++] = p;
+}
+
+GtkTreePath *pop_path() {
+ if (pathstackp > 0)
+ return pathstack[--pathstackp];
+ return 0;
+}
+
+gboolean find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+ gint def;
+
+ struct DefFind *df = (struct DefFind *)data;
+
+ gtk_tree_model_get (model, iter, DEF_COLUMN, &def, -1);
+
+ if (def == df->def) {
+ df->path = gtk_tree_path_copy (path);
+ return TRUE;
+ }
+ return FALSE;
+
+}
+
+void
+my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path, *path2;
+ gchar *text, *oldpath, *newpath;
+ gint def, ref;
+ struct DefFind df;
+
+ (void) arg2;
+
+ path = gtk_tree_path_copy (spath);
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref, -1);
+
+ oldpath = gtk_tree_path_to_string(path);
+ path2 = gtk_tree_path_copy (path);
+
+ add_path(gtk_tree_path_copy(path));
+
+ if (ref != -1) { /* this is a reference, find matching definition */
+ df.def = ref;
+ df.path = 0;
+ gtk_tree_model_foreach (model, find_definition, &df);
+ if (df.path) {
+ gtk_tree_path_free(path);
+ path = df.path;
+ }
+ } else { /* just move to the next entry, if it exists */
+ gtk_tree_path_next(path2);
+
+ if (gtk_tree_model_get_iter (model, &iter, path2)) {
+ gtk_tree_path_free(path);
+ path = path2; /* OK */
+ } else {
+ if (gtk_tree_path_get_depth (path) > 1)
+ gtk_tree_path_up (path);
+ }
+ }
+
+ if (path != path2)
+ gtk_tree_path_free (path2);
+
+ gtk_tree_view_expand_to_path (treeview, path);
+ gtk_tree_view_expand_row (treeview, path, FALSE);
+
+ gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
+
+ gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
+
+ newpath = gtk_tree_path_to_string(path);
+
+ if (asn1_debug)
+ g_message("my_signal_handler: treeview=%p, moveing from %s to %s",
+ treeview, oldpath, newpath);
+
+ g_free(text);
+ g_free(oldpath);
+ g_free(newpath);
+ /* if (df.path) */
+ /* gtk_tree_path_free(df.path); */
+}
+
+
+static void
+menuitem_cb (gpointer callback_data,
+ guint callback_action,
+ GtkWidget *widget)
+{
+ GtkWidget *dialog;
+ GtkTreeModel *model;
+ GtkTreeView *treeview = gtk_item_factory_popup_data_from_widget(widget);
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ gchar *text, *name;
+ gint def, ref;
+ GtkTreePath *path;
+ gchar *oldpath, *newpath;
+ GtkTreeViewColumn *focus_column;
+
+ selection = gtk_tree_view_get_selection(treeview);
+
+ model = gtk_tree_view_get_model(treeview);
+ gtk_tree_view_get_cursor (treeview, &path, &focus_column);
+
+ if (gtk_tree_model_get_iter (model, &iter, path)) {
+
+ gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref,
+ NAME_COLUMN, &name, -1);
+ oldpath = gtk_tree_path_to_string(path);
+ newpath = empty;
+
+ switch (callback_action) {
+ case 0: /* Select */
+ gtk_tree_selection_select_path (selection, path);
+ break;
+ case 1: /* back */
+ path = pop_path();
+ if (path) {
+ gtk_tree_view_expand_to_path (treeview, path);
+ gtk_tree_view_expand_row (treeview, path, FALSE);
+
+ gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
+
+ gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
+
+ newpath = gtk_tree_path_to_string(path);
+
+ gtk_tree_path_free(path);
+ } else
+ newpath = g_strdup("** no path **");
+ if (asn1_debug)
+ g_message("menueitem_cb: treeview=%p, moveing from %s to %s",
+ treeview, oldpath, newpath);
+ break;
+
+ case 2: /* Find */
+ /* get all non anonymous names to the root */
+
+ default:
+ dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE,
+ "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
+ gtk_item_factory_path_from_widget (widget),
+ callback_action, text, oldpath, newpath, name);
+
+ /* Close dialog on user response */
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+
+ gtk_widget_show (dialog);
+ break;
+ }
+ g_free(text);
+ g_free(name);
+ if (newpath != empty)
+ g_free(newpath);
+ g_free(oldpath);
+ } else
+ g_message("menuitem_cb: no iterator...");
+}
+
+static GtkItemFactoryEntry menu_items[] = {
+ { "/Select", NULL, menuitem_cb, 0, NULL, 0 },
+ { "/Back", "<control>B", menuitem_cb, 1, NULL, 0 },
+ { "/Find", "<control>F", menuitem_cb, 2, NULL, 0 },
+ { "/Save", "<control>S", menuitem_cb, 3, NULL, 0 },
+};
+
+static gint button_press_callback( GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data )
+{
+ GtkTreeView *treeview = GTK_TREE_VIEW(widget);
+
+ /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
+ * " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
+ * event->y_root );
+ */
+ if (event->button == 3) {
+ gtk_item_factory_popup_with_data ((GtkItemFactory *)data, treeview, NULL,
+ event->x_root,
+ event->y_root,
+ event->button,
+ event->time);
+ return TRUE;
+ }
+ return FALSE; /* continue handling this event */
+}
+
+
+void
+create_message_window()
+{
+ GtkCellRenderer *renderer;
+ GtkTreeStore *model;
+ GtkWidget *vbox;
+ GtkWidget *sw;
+ GtkWidget *treeview;
+ gchar *text;
+ GtkItemFactory *item_factory;
+ GtkAccelGroup *accel_group;
+ gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
+
+ if ( ! window) {
+
+ /* create window, etc */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), current_pduname);
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gtk_widget_destroyed), &window);
+
+ vbox = gtk_vbox_new (FALSE, 8);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ text = g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1, current_pduname);
+
+ gtk_box_pack_start (GTK_BOX (vbox),
+ gtk_label_new (text),
+ FALSE, FALSE, 0);
+ g_free(text);
+
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
+ GTK_SHADOW_ETCHED_IN);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
+
+ model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
+ G_TYPE_STRING, G_TYPE_STRING);
+
+ namelist = fopen("namelist.txt", "w");
+ build_tree_view(model, PDUtree, NULL);
+ fclose(namelist);
+ namelist = 0;
+
+ /* create tree view */
+ treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
+ g_object_unref (model);
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
+ gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
+ GTK_SELECTION_MULTIPLE);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+#if 0 /* testing pango attributes */
+{
+ PangoAttribute* bg;
+ PangoAttrList* attr;
+
+ attr = pango_attr_list_new();
+ bg = pango_attr_background_new(50000,55000,50000);
+ bg->start_index = 0;
+ bg->end_index = 10000;
+ pango_attr_list_insert(attr, bg);
+
+ g_object_set(renderer, "attributes", attr, NULL);
+}
+#endif /* testing pango attributes */
+
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
+ TITLE_COLUMN, "asn1 entities", renderer,
+ "text", TITLE_COLUMN, NULL );
+
+ /* renderer = gtk_cell_renderer_text_new ();
+ * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
+ * DEF_COLUMN, "type definition", renderer,
+ * "text", DEF_COLUMN, NULL );
+ *
+ * renderer = gtk_cell_renderer_text_new ();
+ * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
+ * REF_COLUMN, "reference", renderer,
+ * "text", REF_COLUMN, NULL );
+ */
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
+ VALUE_COLUMN, "value", renderer,
+ "stock_id", VALUE_COLUMN, NULL );
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
+ NAME_COLUMN, "fieldname", renderer,
+ "text", NAME_COLUMN, NULL );
+
+ gtk_container_add (GTK_CONTAINER (sw), treeview);
+
+ /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
+
+ /* create menu */
+
+ accel_group = gtk_accel_group_new ();
+
+ /* This function initializes the item factory.
+ * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
+ * or GTK_TYPE_OPTION_MENU.
+ * Param 2: The path of the menu.
+ * Param 3: A pointer to a gtk_accel_group. The item factory sets up
+ * the accelerator table while generating menus.
+ */
+
+ item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<menu>", accel_group);
+
+ /* This function generates the menu items. Pass the item factory,
+ the number of items in the array, the array itself, and any
+ callback data for the the menu items. */
+ gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
+
+ /* Attach the new accelerator group to the window. */
+ gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+
+
+ /* expand all rows after the treeview widget has been realized */
+ g_signal_connect (treeview, "realize",
+ G_CALLBACK (gtk_tree_view_expand_all), NULL);
+ g_signal_connect (treeview, "row-activated",
+ G_CALLBACK (my_signal_handler), (gpointer)model);
+
+ g_signal_connect (treeview, "button_press_event",
+ G_CALLBACK (button_press_callback), item_factory);
+
+ /* g_signal_connect_swapped (treeview, "event",
+ * G_CALLBACK (button_press_handler),
+ * menu);
+ */
+ gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ gtk_widget_show_all (window);
+ else
+ {
+ gtk_widget_destroy (window);
+ window = NULL;
+ }
+}
+#endif /* SHOWPDU */
+
+/************************************************************************************************
+ * routines to find names to go with the decoded data stream *
+ ************************************************************************************************/
+typedef struct _statestack statestack;
+struct _statestack {
+ GNode *node;
+ guint type;
+ guint offset;
+ char *name;
+} PDUstate[1024];
+gint PDUstatec = 0;
+
+#define PUSHNODE(x) { PDUstate[PDUstatec++] = (x); }
+#define STORENODE(x) { PDUstate[PDUstatec-1] = (x); }
+#define POPSTATE PDUstate[--PDUstatec]
+#define GETSTATE PDUstate[PDUstatec-1]
+#define GETNAME (((PDUinfo *)pos.node->data)->name)
+#define TYPENAME (((PDUinfo *)pos.node->data)->typename)
+#define GETTYPE (((PDUinfo *)pos.node->data)->type & TBL_TYPEmask)
+#define GETFLAGS (((PDUinfo *)pos.node->data)->flags)
+#define GETINFO ((PDUinfo *)pos.node->data)
+#define NEXT {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
+#define CHILD {pos.node = g_node_first_child(pos.node);pos.type=0;}
+#define MATCH ((class == info->tclass) && (tag == info->tag))
+#define ISOPTIONAL (info && (info->flags & PDU_OPTIONAL))
+#define ISIMPLICIT (info && (info->flags & PDU_IMPLICIT))
+#define ISREFERENCE (info && (info->flags & PDU_REFERENCE))
+#define ISCHOICE (info && (info->flags & PDU_CHOICE))
+#define ISANONYMOUS (info && (info->flags & PDU_ANONYMOUS))
+
+#undef CHECKP
+#define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
+ pos.node=0;PUSHNODE(pos);return ret;}}
+
+
+void
+showstack(statestack *pos, char *txt, int n)
+{
+ char buf[1024], *name, *type, *stype;
+ char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
+ int i, j;
+ GNode *g;
+ statestack *p;
+ guint typef;
+
+ if ( ! asn1_verbose)
+ return;
+
+ if (n>PDUstatec)
+ n = PDUstatec;
+ if (n<0) {
+ g_message("==underflow");
+ return;
+ }
+ rep = chs = done = ref = pop = chr = rch = sch = con = empty;
+
+ g = pos->node;
+ if (g) {
+ name = ((PDUinfo *)g->data)->name;
+ type = TBLTYPE(((PDUinfo *)g->data)->type);
+ } else {
+ name = "node<null>";
+ type = "?";
+ }
+ typef = pos->type;
+ stype = TBLTYPE(typef);
+ if (typef & TBL_REPEAT) rep = "[repeat]";
+ if (typef & TBL_CHOICE_made) chs = "[choice]";
+ if (typef & TBL_SEQUENCE_done) done = "[done]";
+ if (typef & TBL_REFERENCE) ref = "[ref]";
+ if (typef & TBL_REFERENCE_pop) pop = "[ref-pop]";
+ if (typef & TBL_CHOICE_repeat) chr = "[chs-rep]";
+ if (typef & TBL_REPEAT_choice) rch = "[rep-chs]";
+ if (typef & TBL_SEQUENCE_choice)sch = "[seq-chs]";
+ if (typef & TBL_CONSTRUCTED) con = "[constr]";
+
+ i = sprintf(buf, "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt, PDUstatec,
+ pos->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
+ pos->name, pos->offset);
+
+ for(j=1, n--; n>0; j++, n--) {
+ p = &PDUstate[PDUstatec-j];
+ typef = p->type;
+ stype = TBLTYPE(typef);
+ rep = (typef & TBL_REPEAT) ? "[repeat]" : empty;
+ chs = (typef & TBL_CHOICE_made) ? "[choice]" : empty;
+ done = (typef & TBL_SEQUENCE_done) ? "[done]" : empty;
+ ref = (typef & TBL_REFERENCE) ? "[ref]" : empty;
+ pop = (typef & TBL_REFERENCE_pop) ? "[ref-pop]" : empty;
+ chr = (typef & TBL_CHOICE_repeat) ? "[chs-rep]" : empty;
+ rch = (typef & TBL_REPEAT_choice) ? "[rep-chs]" : empty;
+ sch = (typef & TBL_SEQUENCE_choice)? "[seq-chs]" : empty;
+ con = (typef & TBL_CONSTRUCTED) ? "[constr]" : empty;
+
+ i += sprintf(&buf[i], "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec-j,
+ p->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
+ p->name, p->offset);
+ }
+ g_message(buf);
+}
+
+void
+showrefNode(GNode *node, int n)
+{
+ char *name = empty, *type = empty, *tname = empty;
+ int cls = 0, tag = 0;
+ PDUinfo *info;
+ GNode *ref = 0;
+
+ if (n > 10) {
+ g_message("%*sstop, nesting too deep", 2*n, empty);
+ return;
+ }
+ if (node->data) {
+ info = (PDUinfo *)(node->data);
+ type = TBLTYPE(info->type);
+ name = info->name;
+ tname = info->typename;
+ ref = info->reference;
+ cls = info->tclass;
+ tag = info->tag;
+ }
+ g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
+ 2*n, empty, tname, type, name, node, node->data,
+ ref, tag_class[cls], tag);
+
+ if (ref)
+ showrefNode(ref, n+1);
+}
+
+void
+showNode(GNode *node, int n, int m)
+{
+ char *name = empty, *type = empty;
+ GNode *ref = 0;
+
+ if (n > m)
+ return;
+
+ if (node->data) {
+ type = TBLTYPE(((PDUinfo *)(node->data))->type);
+ name = ((PDUinfo *)(node->data))->name;
+ ref = ((PDUinfo *)(node->data))->reference;
+ }
+ g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
+ 2*n, empty, type, name, node, node->data, node->next, node->prev,
+ node->parent, node->children);
+
+ if (m > 10) {
+ g_message("%*sstop, nesting too deep", 2*n, empty);
+ return;
+ }
+
+ if (ref) showrefNode(ref, n+2);
+
+ if (node->children) showNode(node->children, n+1, m);
+ if (node->next) showNode(node->next, n, m);
+}
+
+void
+PDUreset(int count, int count2)
+{
+ statestack pos;
+
+ if (asn1_verbose) g_message("PDUreset %d-%d", count, count2);
+
+ PDUstatec = 0; /* stackpointer */
+ PDUerrcount = 0; /* error counter per asn.1 message */
+
+ pos.node = 0; /* sentinel */
+ pos.name = "sentinel";
+ pos.type = TBL_SEQUENCEOF;
+ pos.offset = 0;
+ PUSHNODE(pos);
+
+ if (PDUtree) {
+ pos.node = PDUtree; /* root of the tree */
+ pos.name = GETNAME;;
+ pos.type = GETTYPE | TBL_REPEAT;
+ pos.offset = 0;
+ PUSHNODE(pos);
+ }
+}
+
+GNode * /* find GNode for a choice element, 0 if none */
+makechoice(GNode *p, guint class, guint tag)
+{
+ GNode *q;
+ PDUinfo *info;
+
+ p = g_node_first_child(p); /* the list of choices */
+ info = 0; /* avoid gcc warning */
+
+ while (p) {
+ info = ((PDUinfo *)p->data);
+
+ if (info->type == TBL_CHOICE) {
+ if (asn1_verbose)
+ g_message(" using sub choice (%s)%s", info->typename, info->name);
+
+ q = makechoice(p, class, tag);
+ if (q) { /* found it */
+ p = q;
+ info = ((PDUinfo *)p->data);
+ break;
+ } /* continue with this level */
+
+ } else {
+ if (asn1_verbose)
+ g_message(" have %c%d, found %c%d, %s", tag_class[class], tag,
+ tag_class[info->tclass], info->tag, info->name);
+
+ if ((class == info->tclass) && (tag == info->tag))
+ break; /* found it */
+ }
+
+ p = g_node_next_sibling(p);
+ }
+ if (asn1_verbose) {
+ if (p) g_message(" OK, '%s:(%s)%s' chosen", tbl_types[info->type], info->typename,
+ info->name);
+ else g_message(" ...no matching choice...");
+ }
+ return p;
+}
+
+ /* offset is for debugging only, a reference to output on screen */
+PDUprops *
+getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
+{
+ statestack pos, pos2, save_pos;
+ PDUinfo *info;
+ char *ret, *tmp;
+ int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
+ static char namestr[64]; /* enough ? */
+ static char posstr[40];
+ static char noname[] = "*noname*";
+ static PDUprops constructed_save; /* for unexpectedly constructed enteties */
+
+ if (PDUstatec > 0) /* don't read from below the stack */
+ pos = POPSTATE;
+ /* pos refers to the last asn1 node handled */
+
+ /* a very simple, too simple??, way to handle constructed entities */
+ if ((PDUstatec > 0) && (pos.type & TBL_CONSTRUCTED)) {
+ /* unexpectedly constructed, return same info as last time */
+ sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
+ showstack(&pos, posstr, 3);
+ pos.offset = offset;
+ pos.type &= ~TBL_CONSTRUCTED; /* remove the flag */
+ PUSHNODE(pos); /* push extra, to match with a EOI operation */
+ PUSHNODE(pos); /* restore the stack */
+ *out = constructed_save;
+ if (asn1_verbose)
+ g_message(" return for constructed %s (%s)%s",
+ TBLTYPE(out->type), out->typename, out->name);
+ return out;
+ }
+
+ save_pos = pos; /* may need it again */
+
+ out->type = 0;
+ out->name = 0;
+ out->typename = "*error*";
+ out->fullname = 0;
+ out->flags = 0;
+ out->data = 0;
+ out->value_id = -1;
+ out->type_id = -1;
+
+ if (PDUstatec <= 0) {
+ if (PDUstatec > -10) {
+ if (asn1_verbose)
+ g_message(">>off=%d stack underflow, return", offset);
+ }
+ if (PDUstatec == -10) {
+ if (asn1_verbose)
+ g_message(">>off=%d stack underflow, return, no more messages", offset);
+ }
+ out->name = "*underflow*";
+ out->flags |= OUT_FLAG_noname;
+ PDUerrcount++;
+ return out;
+ }
+ sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
+
+ showstack(&pos, posstr, 3);
+
+ ret = noname;
+
+ if (class == ASN1_EOI) { /* end of this input sequence */
+
+ if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
+ if (asn1_verbose) g_message(" EOI: reference pop");
+ pos = POPSTATE;
+ } else
+ switch(pos.type & TBL_TYPEmask) {
+ case TBL_TYPEREF:
+ if (asn1_verbose) g_message(" EOI: pop typeref");
+ pos = POPSTATE; /* remove typeref */
+ break;
+ case TBL_CHOICE_done:
+ if (asn1_verbose) g_message(" EOI: mark choice");
+ pos = POPSTATE;
+ pos.type |= TBL_CHOICE_made; /* poropagate this up the stack */
+ PUSHNODE(pos);
+ break;
+ default:
+ break;
+ }
+
+
+ pos = POPSTATE; /* this is pushed back on the stack later */
+ if (pos.node == 0) {
+ if (asn1_verbose) g_message(" EOI, pos.node == 0");
+ out->name = "*no-name-EOI*";
+ out->flags |= OUT_FLAG_noname;
+ PDUerrcount++;
+ return out;
+ }
+
+ info = GETINFO;
+ ret = info->name;
+ tmp = TBLTYPE(info->type);
+ if (offset != pos.offset) {
+ if (asn1_verbose)
+ g_message(" *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
+ tmp, ret, offset, pos.offset);
+ while ((offset < pos.offset) && (PDUstatec > 0)) {
+ pos = POPSTATE;
+ if (asn1_verbose)
+ g_message(" EOI extra pop, EOIoffset=%d, stack=%d",
+ offset, pos.offset);
+ }
+ if (offset != pos.offset)
+ PDUerrcount++; /* only count if still unequal */
+ } else {
+ if (asn1_verbose) g_message(" EOI %s:%s OK, offset=%d", tmp, ret, offset);
+ }
+ } else {
+ /* EOC is only present for indefinite length sequences, etc. end of sequence is always
+ * indicated by the synthetic EOI call. */
+ if ((class == ASN1_UNI) && (tag == ASN1_EOC)) { /* explicit EOC never has a name */
+ PUSHNODE(pos); /* restore stack */
+ ret = "explicit-EOC";
+ if (asn1_verbose) g_message(" return '%s', ignore", ret);
+ out->name = ret;
+ out->typename = "ASN1";
+ return out;
+ }
+
+ /* find appropriate node for this tag */
+
+ if (pos.node == 0) {
+ if (asn1_verbose) g_message(" pos.node == 0");
+ out->name = "*no-name*";
+ out->flags |= OUT_FLAG_noname;
+ PDUerrcount++;
+ return out;
+ }
+
+ /* showNode(pos.node, 3, 4); */
+
+ switch (pos.type & TBL_TYPEmask) {
+ case TBL_SEQUENCE: /* avoid finishing a choice when we have to do a sequence first */
+ case TBL_SET:
+ break;
+ default:
+ if (pos.type & TBL_CHOICE_made) {
+ if (asn1_verbose) g_message(" finish choice");
+ donext = 1;
+ }
+ break;
+ }
+
+ info = GETINFO;
+
+ if (pos.type & TBL_REPEAT) { /* start of a repeat */
+ switch(pos.type & TBL_TYPEmask) { /* type of previous node */
+ case TBL_CHOICE:
+ if (asn1_verbose) g_message(" repeating choice"); /* ignore repeat */
+ break;
+ default:
+ if (asn1_verbose) g_message(" seqof: repeat start");
+ /* decide how to continue, CHILD for next instance of sequence
+ * or NEXT for end of repeated sequence.
+ * use the tag to make a descision */
+ if (asn1_verbose) g_message(" seqof: first got %c%d, found %c%d",
+ tag_class[class], tag,
+ tag_class[info->tclass], info->tag);
+ if ( MATCH ) {
+ /* This is the start of repeating */
+ PUSHNODE(pos);
+ ret = GETNAME;
+ if (asn1_verbose) g_message(" return for repeat '%s'", ret);
+ out->type = (pos.type & TBL_TYPEmask);
+ out->typename = info->typename;
+ out->name = ret;
+ out->value_id = info->value_id;
+ out->type_id = info->type_id;
+ if (ISANONYMOUS) {
+ if (asn1_verbose) g_message(" anonymous: dontshow");
+ if (asn1_debug)
+ out->flags |= OUT_FLAG_dontshow;
+ else
+ out->name = empty;
+ }
+ return out;
+ } else {
+ /* find out where to go .... */
+ pos2 = pos;
+ CHILD; /* assume sequence is repeated */
+ if (pos.node) {
+ info = GETINFO; /* needed for MATCH to look ahead */
+ if (asn1_verbose)
+ g_message(" seqof: child: got %c%d, found %c%d",
+ tag_class[class], tag,
+ tag_class[info->tclass], info->tag);
+ }
+ if (pos2.type & TBL_CHOICE_repeat) {
+ pos = POPSTATE;
+ if (asn1_verbose)
+ g_message(" repeating a choice, %s",
+ GETNAME);
+ pos.type = TBL_CHOICE_immediate;
+ } else {
+ if ( pos.node && ! MATCH) { /* no, repeat ends, */
+ donext = 1; /* move on */
+ if (asn1_verbose)
+ g_message(" seqof: no repeat, force next");
+ }
+ /* following code will take the child again */
+ pos = pos2;
+ }
+ }
+ break;
+ }
+ } else if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
+ if (asn1_verbose) g_message(" reference pop, donext");
+ pos = POPSTATE;
+ donext = 1;
+ } else if (pos.type & TBL_SEQUENCE_done) { /* Children have been processed */
+ if (pos.type & TBL_SEQUENCE_choice) {
+ pos = POPSTATE; /* expect to find a repeat here */
+ } else {
+ donext = 1;
+ if (asn1_verbose) g_message(" sequence done, donext");
+ }
+ }
+
+ if (pos.type & TBL_REFERENCE) {
+ if (asn1_verbose) g_message(" reference change ref -> pop");
+ pos.type ^= (TBL_REFERENCE | TBL_REFERENCE_pop);
+ }
+
+ pos.offset = offset;
+
+ ret = pos.name; /* for the debug messages */
+
+ if (donext) {
+ if (asn1_verbose) g_message(" donext");
+ NEXT;
+ } else {
+ switch(pos.type & TBL_TYPEmask) { /* type of previous node */
+ case TBL_SETOF: /* ?? */
+ case TBL_SEQUENCEOF:
+ if ((pos.type & TBL_REPEAT) == 0) { /* start repeating */
+ pos.type |= TBL_REPEAT;
+ PUSHNODE(pos);
+ CHILD;
+ pushed++;
+ /* remember this is the start of a repeat cycle */
+ typeflags |= TBL_REPEAT;
+ if (asn1_verbose)
+ g_message(" seqof: set repeat mark [push,child]");
+ } else {
+ if (asn1_verbose)
+ g_message(" seqof: end of reapeat loop [next]");
+ NEXT;
+ }
+ break;
+ case TBL_SET: /* ?? */
+ case TBL_SEQUENCE:
+ pos.type |= TBL_SEQUENCE_done;
+ PUSHNODE(pos);
+ CHILD;
+ pushed++;
+ if (asn1_verbose) g_message(" seq [push,child]");
+ break;
+ case TBL_CHOICE:
+ /* no more choice */
+ pos.type = (TBL_CHOICE_done | (pos.type & ~TBL_TYPEmask));
+ PUSHNODE(pos);
+
+ pos.type = 0; /* clear all type flags */
+ if (asn1_verbose)
+ g_message(" choice [push], %c%d, %s",
+ tag_class[info->tclass], info->tag, GETNAME);
+ pos.node = makechoice(pos.node, class, tag);
+ if (pos.node == 0) {
+ pos = POPSTATE;
+ out->flags |= OUT_FLAG_noname;
+ PDUerrcount++;
+ }
+ info = GETINFO;
+
+ ret = GETNAME;
+ if (asn1_verbose)
+ g_message(" '%s' %c%d will be used",
+ ret, tag_class[info->tclass], info->tag);
+ break;
+ case TBL_CHOICE_done:
+ NEXT;
+ break;
+ case TBL_TYPEREF:
+ pos = POPSTATE;
+ NEXT;
+ if (asn1_verbose) g_message(" typeref [pop,next]");
+ break;
+ case TBL_ENUMERATED:
+ case TBL_BITSTRING:
+ /* skip named numbers now, call to PDUenum() will retrieve a name */
+ NEXT;
+ break;
+ case TBL_CHOICE_immediate:
+ if (asn1_verbose) g_message(" immediate choice [no next]");
+ /* nothing */
+ break;
+ default:
+ NEXT;
+ break;
+ }
+ }
+
+ if (pos.node == 0) {
+ ret = "*no-name-2*";
+ if (asn1_verbose) g_message(" return '%s'", ret);
+ out->name = ret;
+ out->flags |= OUT_FLAG_noname;
+ PDUerrcount++;
+ return out;
+ }
+ ret = pos.name = GETNAME;
+ pos.type = GETTYPE | (pos.type & ~TBL_TYPEmask);
+ info = GETINFO;
+
+ /* pos now points to the prospective current node, go check it ********************/
+ if (asn1_verbose) g_message(" candidate %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
+ (ISOPTIONAL)?", optional":empty,
+ (ISIMPLICIT)?", implicit":empty,
+ tag_class[info->tclass], info->tag );
+
+ if (ISOPTIONAL) { /* must check the tag */
+ while(! MATCH) { /* check optional here again...? */
+ if (asn1_verbose)
+ g_message(" got %c%d, found %c%d", tag_class[class], tag,
+ tag_class[info->tclass], info->tag);
+ NEXT;
+ if (pos.node == 0) {
+ ret = "------";
+ if (cons) {
+ pos = save_pos; /* reset for next time */
+ pos.type |= TBL_SEQUENCE_done;
+ PUSHNODE(pos);
+ pos.type &= ~TBL_SEQUENCE_done;
+ cons_handled = 1;
+ out->flags |= OUT_FLAG_dontshow;
+ if (asn1_verbose)
+ g_message(" end of optional list, constructed, expect value next time");
+ } else {
+ PDUerrcount++;
+ out->flags |= OUT_FLAG_noname;
+ if (asn1_verbose)
+ g_message(" *end of optional list...");
+ info = 0; /* this is not valid any more... */
+ }
+ break; /* end of list */
+ }
+ info = GETINFO;
+ if (asn1_verbose) g_message(" optional, %s", GETNAME);
+ }
+ if (pos.node && ! cons_handled) {
+ ret = pos.name = GETNAME;
+ pos.type = GETTYPE;
+ }
+ /* pos now refers to node with name we want, optional nodes skipped */
+ }
+
+ if (pos.type == TBL_CHOICE) { /* may be an immediate choice */
+ pos2 = pos; /* save current state */
+ if ( ! MATCH) {
+ if (! pushed) {
+ if (asn1_verbose)
+ g_message(" already pushed, skip next push");
+ PUSHNODE(pos);
+ typeflags &= ~TBL_CHOICE_made;
+ }
+
+ if (asn1_verbose)
+ g_message(" immediate choice [push], %c%d, %s",
+ tag_class[info->tclass], info->tag, GETNAME);
+ pos.node = makechoice(pos.node, class, tag);
+ if (pos.node == 0) {
+ pos = POPSTATE;
+ PDUerrcount++;
+ }
+ info = GETINFO;
+ pos.type = GETTYPE;
+ out->type = (pos.type & TBL_TYPEmask);
+ out->flags |= OUT_FLAG_type;
+
+ sprintf(namestr, "%s!%s", ret, GETNAME);
+ ret = namestr;
+ if (asn1_verbose)
+ g_message(" %s:%s will be used", TBLTYPE(pos.type), ret);
+ if (typeflags & TBL_REPEAT) {
+ pos2.type |= TBL_REPEAT | TBL_REPEAT_choice;
+ PUSHNODE(pos2);
+ pos.type |= TBL_SEQUENCE_choice;
+ PUSHNODE(pos);
+ if (asn1_verbose)
+ g_message(" return from immediate choice [%s] '%s'",
+ TBLTYPE(pos.type), ret);
+
+ out->data = pos.node; /* for access to named numbers... */
+
+ out->type = (pos.type & TBL_TYPEmask);
+ out->name = ret;
+ if (info) {
+ out->typename = info->typename;
+ out->fullname = info->fullname;
+ out->value_id = info->value_id;
+ out->type_id = info->type_id;
+ }
+
+ return out;
+ } else {
+ typeflags |= TBL_CHOICE_made;
+ }
+ } else {
+ if (asn1_verbose) g_message(" matching choice '%s'", ret);
+ }
+ if ( ! cons ) { /* ISIMPLICIT was not OK for all */
+ pos = pos2; /* reset for continuation */
+ }
+ }
+ if (asn1_verbose) {
+ if (info)
+ g_message(" using: %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
+ (ISOPTIONAL)?", optional":empty,
+ (ISIMPLICIT)?", implicit":empty,
+ tag_class[info->tclass], info->tag );
+ else
+ g_message(" using: unknown '%s'", ret);
+ }
+
+ /* must follow references now */
+ if (pos.type == TBL_TYPEREF) {
+ out->typename = info->typename;
+ out->type_id = info->typenum;
+ out->flags |= OUT_FLAG_typename;
+ pos2 = pos;
+ PUSHNODE(pos); /* remember where we were */
+ if (asn1_verbose) g_message(" typeref [push]");
+ typeflags |= TBL_REFERENCE;
+ if (info->reference == 0) { /* resolved ref to universal type.... */
+ /* showNode(pos.node, 3, 4); */
+ pos.type = GETTYPE; /* the resulting type */
+ info = GETINFO;
+ tmp = "inknown tag";
+ if ((info->tclass == ASN1_UNI) && (info->tag < 31)) {
+ tmp = asn1_tag[info->tag];
+ pos.type = asn1_uni_type[info->tag]; /* get univsrsal type */
+ }
+ if (asn1_verbose)
+ g_message(" indirect typeref to %s:%s, %s [%c%d]",
+ TBLTYPE(pos.type), info->typename, tmp,
+ tag_class[info->tclass], info->tag );
+ } else {
+ out->fullname = info->fullname;
+ donext = (ISANONYMOUS); /* refereing entity has no name ? */
+ pos.node = info->reference;
+ pos.type = GETTYPE;
+ info = GETINFO;
+ if (asn1_verbose)
+ g_message(" typeref %s %s", TBLTYPE(pos.type), GETNAME);
+ /* keep name from before going through the reference, unless anonymous */
+ if (donext) /* refering entity has no name */
+ ret = GETNAME; /* a better name */
+
+ /* handle choice here ? !!mm!! */
+
+ out->type = (pos.type & TBL_TYPEmask);
+ out->flags |= OUT_FLAG_type;
+ /* showNode(pos.node, 3, 4); */
+ /* ret = GETNAME;*/
+
+ out->data = pos.node;
+ out->flags |= OUT_FLAG_data;
+ if (asn1_verbose)
+ g_message(" typeref set named number list node %p", pos.node);
+
+ if ( ! cons) {
+ pos = POPSTATE;
+ pos.type = TBL_TYPEREF_nopop;
+ if (asn1_verbose) g_message(" typeref pop");
+ } else if ((pos.type == TBL_ENUMERATED) || (pos.type == TBL_BITSTRING)){
+ /* do not enter the named-number list */
+ pos = POPSTATE;
+ pos.type = TBL_TYPEREF_nopop;
+ if (asn1_verbose) g_message(" typeref [pop]");
+ } else {
+ typeflags |= TBL_REFERENCE;
+ }
+ }
+ }
+
+ if (cons && ! cons_handled) { /* This entity is constructed, expected ? */
+ switch(pos.type) {
+ case TBL_BOOLEAN: /* these are not expected to be constructed */
+ case TBL_INTEGER:
+ case TBL_OCTETSTRING:
+ case TBL_NULL:
+ case TBL_OID:
+ case TBL_REAL:
+ case TBL_ENUMERATED:
+ case TBL_TYPEREF:
+ typeflags |= TBL_CONSTRUCTED;
+ /* this entry has no extra info, next is the same */
+ out->flags |= (OUT_FLAG_dontshow | OUT_FLAG_constructed);
+ if (asn1_verbose) g_message(" dontshow and set constructed flag");
+ break;
+ default: /* others, such as sequences, are expected to be constructed */
+ break;
+ }
+ }
+ }
+
+ if (ISANONYMOUS) {
+ if (asn1_verbose) g_message(" anonymous: dontshow");
+ if (asn1_debug) /* this entry has no extra info, next is the same */
+ out->flags |= OUT_FLAG_dontshow;
+ else
+ out->name = empty; /* show it, but no name */
+ }
+
+ if (out->name != empty)
+ out->name = ret;
+
+ if ( ! (out->flags & OUT_FLAG_data))
+ out->data = pos.node; /* for access to named numbers... */
+
+ pos.type |= typeflags;
+ PUSHNODE(pos);
+
+ if ( ! (out->flags & OUT_FLAG_type))
+ out->type = pos.type;
+
+ out->type &= TBL_TYPEmask;
+
+ if (ret == noname) {
+ PDUerrcount++;
+ out->flags |= OUT_FLAG_noname;
+ }
+
+ if (info && ((out->flags & OUT_FLAG_typename) == 0)) {
+ out->typename = info->typename;
+ out->type_id = info->typenum;
+ }
+
+ if (info && (out->value_id == -1)) {
+ out->value_id = info->value_id;
+ out->type_id = info->type_id;
+ }
+
+ if ((out->fullname == 0) && info)
+ out->fullname = info->fullname;
+
+ if (typeflags & TBL_CONSTRUCTED)
+ constructed_save = *out;
+
+ if (asn1_verbose)
+ g_message(" return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out->type), out->name,
+ out->value_id, out->type_id);
+
+ return out;
+}
+
+char *
+getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
+{
+ GNode *list;
+ PDUinfo *info;
+ char *ret, *name;
+ static char unnamed[] = "*unnamed*";
+
+ (void) cls; (void) tag; /* make a reference */
+
+ if (props->flags & OUT_FLAG_noname)
+ return empty;
+
+ ret = unnamed;
+ list = (GNode *)props->data;
+
+ if (list == 0) {
+ if (asn1_verbose) g_message("--off=%d named number list not initialized", offset);
+ PDUerrcount++;
+ return "*list-still-0*";
+ }
+
+ if ((PDUinfo *)list->data)
+ name = ((PDUinfo *)list->data)->name;
+ else
+ name = ret;
+
+ for(list = g_node_first_child(list); list; list = g_node_next_sibling(list)) {
+ info = (PDUinfo *)list->data;
+ if (value == info->tag) {
+ ret = info->name;
+ break;
+ }
+ }
+ if (ret == unnamed)
+ PDUerrcount++;
+
+ if (asn1_verbose)
+ g_message("--off=%d namednumber %d=%s from list %s", offset, value, ret, name);
+ return ret;
+}
+
+#endif /* READSYNTAX */
+
+void
+proto_register_asn1(void) {
+
+ static const enum_val_t type_recursion_opts[] = {
+ { "0", 0 },
+ { "1", 1 },
+ { "2", 2 },
+ { "3", 3 },
+ { "4", 4 },
+ { "5", 5 },
+ { "6", 6 },
+ { "7", 7 },
+ { "8", 8 },
+ { "9", 9 },
+ { NULL, -1},
+ };
+
+ static gint *ett[1+MAX_NEST+MAXPDU];
+
+ module_t *asn1_module;
+ int i, j;
+
+
+ asn1_logfile = g_strdup(ASN1LOGFILE);
+
+ current_pduname = g_strdup("ASN1");
+ asn1_pduname = g_strdup(current_pduname);
+
+ proto_asn1 = proto_register_protocol("ASN.1 decoding",
+ "ASN1", pabbrev);
+
+ ett[0] = &ett_asn1;
+ for (i=0, j=1; i<MAX_NEST; i++, j++) {
+ ett[j] = &ett_seq[i];
+ ett_seq[i] = -1;
+ }
+ for(i=0; i<MAXPDU; i++, j++) {
+ ett[j] = &ett_pdu[i];
+ ett_pdu[i] = -1;
+ }
+
+ proto_register_subtree_array(ett, array_length(ett));
+
+ asn1_module = prefs_register_protocol(proto_asn1,
+ proto_reg_handoff_asn1);
+ prefs_register_uint_preference(asn1_module, "tcp_port",
+ "ASN.1 TCP Port",
+ "The TCP port on which "
+ "ASN.1 packets will be read",
+ 10, &global_tcp_port_asn1);
+ prefs_register_uint_preference(asn1_module, "udp_port",
+ "ASN.1 UDP Port",
+ "The UDP port on which "
+ "ASN.1 packets will be read",
+ 10, &global_udp_port_asn1);
+ prefs_register_bool_preference(asn1_module, "desegment_messages",
+ "Desegment tcp",
+ "Desegent ASN1 messages that span tcp segments",
+ &asn1_desegment);
+
+ if (asn1_filename == 0) {
+#ifdef WIN32
+ /* 'get_datafile_dir()' not yet available for plugins */
+ asn1_filename = g_strdup("C:\\ethereal\\asn1\\default.tt");
+#else
+ int n = strlen(get_datafile_dir()) + sizeof(ASN1FILE) + 2;
+ asn1_filename = g_malloc(n);
+ snprintf(asn1_filename, n, "%s" G_DIR_SEPARATOR_S "%s", get_datafile_dir(), ASN1FILE);
+#endif
+ }
+
+ prefs_register_string_preference(asn1_module, "file",
+ "ASN.1 type table file",
+ "Compiled ASN.1 description of ASN.1 types",
+ &asn1_filename);
+ prefs_register_string_preference(asn1_module, "pdu_name",
+ "ASN.1 PDU name",
+ "Name of top level PDU",
+ &asn1_pduname);
+ prefs_register_uint_preference(asn1_module, "first_pdu_offset",
+ "Offset to first PDU in first tcp packet",
+ "Offset for non-reassembled packets, "
+ "wrong if this happens on other than the first packet!",
+ 10, &first_pdu_offset);
+ prefs_register_bool_preference(asn1_module, "flat",
+ "Show full names",
+ "Show full names for all values",
+ &asn1_full);
+ prefs_register_enum_preference(asn1_module, "type_recursion",
+ "Eliminate references to level",
+ "Allow this recursion level for eliminated type references",
+ &type_recursion_level,
+ type_recursion_opts, FALSE);
+ prefs_register_bool_preference(asn1_module, "debug",
+ "ASN.1 debug mode",
+ "Extra output useful for debuging",
+ &asn1_debug);
+
+ prefs_register_bool_preference(asn1_module, "message_win",
+ "Show ASN.1 tree",
+ "show full message description",
+ &asn1_message_win);
+ prefs_register_bool_preference(asn1_module, "verbose_log",
+ "Write very verbose log",
+ "log to file " ASN1LOGFILE,
+ &asn1_verbose);
+}
+
+/* The registration hand-off routing */
+
+void
+proto_reg_handoff_asn1(void) {
+ static int asn1_initialized = FALSE;
+ static dissector_handle_t asn1_handle;
+
+ pcount = 0;
+
+ if (asn1_verbose) g_message("prefs change: tcpport=%d, udpport=%d, desegnment=%d, asn1file=%s, "
+ "pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
+ global_tcp_port_asn1, global_udp_port_asn1, asn1_desegment, asn1_filename,
+ asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
+
+ if(!asn1_initialized) {
+ asn1_handle = create_dissector_handle(dissect_asn1,proto_asn1);
+ asn1_initialized = TRUE;
+ } else {
+ dissector_delete("tcp.port", tcp_port_asn1, asn1_handle);
+ dissector_delete("udp.port", udp_port_asn1, asn1_handle);
+ }
+
+ tcp_port_asn1 = global_tcp_port_asn1;
+ udp_port_asn1 = global_udp_port_asn1;
+
+ dissector_add("tcp.port", global_tcp_port_asn1, asn1_handle);
+ dissector_add("udp.port", global_udp_port_asn1, asn1_handle);
+
+ if ( g_strcmp(asn1_filename, current_asn1) != 0) { /* new defintions, parse it */
+ /* !!! should be postponed until we really need it !!! */
+#ifdef READSYNTAX
+ read_asn1_type_table(asn1_filename);
+#endif /* READSYNTAX */
+ g_free(current_asn1);
+ current_asn1 = g_strdup(asn1_filename);
+ }
+ if (g_strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
+ if (build_pdu_tree(asn1_pduname)) {
+ g_free(current_pduname);
+ current_pduname = g_strdup(asn1_pduname);
+ }
+ }
+#ifdef SHOWPDU
+ if (asn1_message_win) { /* show what we are prepared to recognize */
+ if (window) {
+ gtk_widget_destroy (window);
+ window = NULL;
+ }
+ create_message_window();
+ }
+#endif /* SHOWPDU */
+}
+
+/* Start the functions we need for the plugin stuff */
+
+#ifndef __ETHEREAL_STATIC__
+
+G_MODULE_EXPORT void
+plugin_reg_handoff(void){
+ proto_reg_handoff_asn1();
+}
+
+G_MODULE_EXPORT void
+plugin_init(plugin_address_table_t *pat
+#ifndef PLUGINS_NEED_ADDRESS_TABLE
+_U_
+#endif
+)
+{
+ /* initialise the table of pointers needed in Win32 DLLs */
+ plugin_address_table_init(pat);
+ /* register the new protocol, protocol fields, and subtrees */
+ if (proto_asn1 == -1) { /* execute protocol initialization only once */
+ proto_register_asn1();
+ }
+}
+
+#endif
+
+/* End the functions we need for plugin stuff */