diff options
author | Guy Harris <guy@alum.mit.edu> | 2003-10-28 07:02:38 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2003-10-28 07:02:38 +0000 |
commit | c68a7d7cb15b8fede442eef7b1ec19d616ecc10e (patch) | |
tree | c65b6a8e5d259e5de569f007d9a5277eac657269 /plugins/asn1 | |
parent | 9c3e2720dac9d37a97ba9aa7067a4a3e9a46add8 (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
Diffstat (limited to 'plugins/asn1')
-rw-r--r-- | plugins/asn1/.cvsignore | 19 | ||||
-rw-r--r-- | plugins/asn1/AUTHORS | 2 | ||||
-rw-r--r-- | plugins/asn1/COPYING | 340 | ||||
-rw-r--r-- | plugins/asn1/ChangeLog | 0 | ||||
-rw-r--r-- | plugins/asn1/INSTALL | 0 | ||||
-rw-r--r-- | plugins/asn1/Makefile.am | 44 | ||||
-rw-r--r-- | plugins/asn1/Makefile.nmake | 21 | ||||
-rw-r--r-- | plugins/asn1/NEWS | 0 | ||||
-rw-r--r-- | plugins/asn1/moduleinfo.h | 17 | ||||
-rw-r--r-- | plugins/asn1/packet-asn1.c | 4800 |
10 files changed, 5243 insertions, 0 deletions
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 */ |