aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
Diffstat (limited to 'epan')
-rw-r--r--epan/Makefile.common21
-rw-r--r--epan/asn1.c1085
-rw-r--r--epan/asn1.h150
-rwxr-xr-xepan/dissectors/ncp2222.py2
-rw-r--r--epan/dissectors/packet-acse.c2
-rw-r--r--epan/dissectors/packet-ansi_map.c2
-rw-r--r--epan/dissectors/packet-atalk.c2
-rw-r--r--epan/dissectors/packet-clnp.c2
-rw-r--r--epan/dissectors/packet-cops.c2
-rw-r--r--epan/dissectors/packet-dcerpc.c2
-rw-r--r--epan/dissectors/packet-diameter.c2
-rw-r--r--epan/dissectors/packet-dnp.c2
-rw-r--r--epan/dissectors/packet-eap.c2
-rw-r--r--epan/dissectors/packet-fc.c2
-rw-r--r--epan/dissectors/packet-ftam.c2
-rw-r--r--epan/dissectors/packet-gsm_a.c2
-rw-r--r--epan/dissectors/packet-gsm_sms_ud.c2
-rw-r--r--epan/dissectors/packet-gsm_ss.c2
-rw-r--r--epan/dissectors/packet-gssapi.c2
-rw-r--r--epan/dissectors/packet-ieee80211.c2
-rw-r--r--epan/dissectors/packet-inap.c2
-rw-r--r--epan/dissectors/packet-ip.c2
-rw-r--r--epan/dissectors/packet-ipv6.c2
-rw-r--r--epan/dissectors/packet-kerberos.c2
-rw-r--r--epan/dissectors/packet-ldap.c2
-rw-r--r--epan/dissectors/packet-lwapp.c2
-rw-r--r--epan/dissectors/packet-mq.c2
-rw-r--r--epan/dissectors/packet-mysql.c2
-rw-r--r--epan/dissectors/packet-ncp.c2
-rw-r--r--epan/dissectors/packet-ndmp.c2
-rw-r--r--epan/dissectors/packet-ndps.c2
-rw-r--r--epan/dissectors/packet-netbios.c2
-rw-r--r--epan/dissectors/packet-ntlmssp.c2
-rw-r--r--epan/dissectors/packet-pgsql.c2
-rw-r--r--epan/dissectors/packet-pres.c2
-rw-r--r--epan/dissectors/packet-q931.c2
-rw-r--r--epan/dissectors/packet-rpc.c2
-rw-r--r--epan/dissectors/packet-smb-pipe.c2
-rw-r--r--epan/dissectors/packet-smb.c2
-rw-r--r--epan/dissectors/packet-sna.c2
-rw-r--r--epan/dissectors/packet-sndcp.c2
-rw-r--r--epan/dissectors/packet-snmp.c2
-rw-r--r--epan/dissectors/packet-spnego.c2
-rw-r--r--epan/dissectors/packet-srvloc.c2
-rw-r--r--epan/dissectors/packet-ssh.c2
-rw-r--r--epan/dissectors/packet-tcap.c2
-rw-r--r--epan/dissectors/packet-tcp.c4
-rw-r--r--epan/dissectors/packet-tds.c2
-rw-r--r--epan/dissectors/packet-wtp.c2
-rw-r--r--epan/dissectors/packet-x25.c2
-rw-r--r--epan/follow.c336
-rw-r--r--epan/follow.h57
-rw-r--r--epan/packet.c2
-rw-r--r--epan/plugins.c4
-rw-r--r--epan/ptvcursor.c116
-rw-r--r--epan/ptvcursor.h80
-rw-r--r--epan/reassemble.c1833
-rw-r--r--epan/reassemble.h244
-rw-r--r--epan/xmlstub.c170
-rw-r--r--epan/xmlstub.h1123
60 files changed, 5258 insertions, 59 deletions
diff --git a/epan/Makefile.common b/epan/Makefile.common
index f6d7e22526..4002bd54b2 100644
--- a/epan/Makefile.common
+++ b/epan/Makefile.common
@@ -28,6 +28,7 @@ LIBETHEREAL_SRC = \
addr_resolv.c \
adler32.c \
afn.c \
+ asn1.c \
atalk-utils.c \
base64.c \
bitswap.c \
@@ -45,6 +46,7 @@ LIBETHEREAL_SRC = \
epan.c \
except.c \
filesystem.c \
+ follow.c \
frame_data.c \
h225-persistentdata.c \
in_cksum.c \
@@ -55,7 +57,9 @@ LIBETHEREAL_SRC = \
plugins.c \
prefs.c \
proto.c \
+ ptvcursor.c \
range.c \
+ reassemble.c \
req_resp_hdrs.c \
sha1.c \
sigcomp_state_hdlr.c \
@@ -69,7 +73,8 @@ LIBETHEREAL_SRC = \
to_str.c \
tvbuff.c \
value_string.c \
- xdlc.c
+ xdlc.c \
+ xmlstub.c
LIBETHEREAL_INCLUDES = \
addr_and_mask.h \
@@ -78,6 +83,7 @@ LIBETHEREAL_INCLUDES = \
adler32.h \
afn.h \
arptypes.h \
+ asn1.h \
atalk-utils.h \
base64.h \
bitswap.h \
@@ -98,6 +104,7 @@ LIBETHEREAL_INCLUDES = \
except.h \
exceptions.h \
filesystem.h \
+ follow.h \
frame_data.h \
gdebug.h \
h225-persistentdata.h \
@@ -114,7 +121,9 @@ LIBETHEREAL_INCLUDES = \
prefs.h \
prefs-int.h \
proto.h \
+ ptvcursor.h \
range.h \
+ reassemble.h \
report_err.h \
req_resp_hdrs.h \
sha1.h \
@@ -130,13 +139,9 @@ LIBETHEREAL_INCLUDES = \
to_str.h \
tvbuff.h \
value_string.h \
- xdlc.h
+ xdlc.h \
+ xmlstub.h
# dissector helpers (needed from the dissectors, but not a dissector itself)
-DISSECTOR_SUPPORT_SRC = \
- ../asn1.c \
- ../follow.c \
- ../ptvcursor.c \
- ../reassemble.c \
- ../xmlstub.c
+DISSECTOR_SUPPORT_SRC =
diff --git a/epan/asn1.c b/epan/asn1.c
new file mode 100644
index 0000000000..f9ff91f85c
--- /dev/null
+++ b/epan/asn1.c
@@ -0,0 +1,1085 @@
+/* asn1.c
+ * Routines for ASN.1 BER dissection
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ *
+ * Based on "g_asn1.c" from:
+ *
+ * GXSNMP -- An snmp mangament application
+ * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
+ * Beholder RMON ethernet network monitor, Copyright (C) 1993 DNPAP group
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * MODULE INFORMATION
+ * ------------------
+ * FILE NAME: g_asn1.c
+ * SYSTEM NAME: ASN1 Basic Encoding
+ * ORIGINAL AUTHOR(S): Dirk Wisse
+ * VERSION NUMBER: 1
+ * CREATION DATE: 1990/11/22
+ *
+ * DESCRIPTION: ASN1 Basic Encoding Rules.
+ *
+ * To decode this we must do:
+ *
+ * asn1_open (asn1, tvb, offset);
+ * asn1_header_decode (asn1, &end_of_seq, cls, con, tag, def, len);
+ * asn1_header_decode (asn1, &end_of_octs, cls, con, tag, def, len);
+ * asn1_octets_decode (asn1, end_of_octs, str, len);
+ * asn1_header_decode (asn1, &end_of_int, cls, con, tag);
+ * asn1_int_decode (asn1, end_of_int, &integer);
+ * asn1_eoc_decode (asn1, end_of_seq);
+ * asn1_close (asn1, &offset);
+ *
+ * For indefinite encoding end_of_seq and &end_of_seq in the
+ * example above should be replaced by NULL.
+ * For indefinite decoding nothing has to be changed.
+ * This can be very useful if you want to decode both
+ * definite and indefinite encodings.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include <limits.h>
+
+#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include <epan/tvbuff.h>
+#include <epan/asn1.h>
+
+/*
+ * NAME: asn1_open [API]
+ * SYNOPSIS: void asn1_open
+ * (
+ * ASN1_SCK *asn1,
+ * tvbuff_t *tvb,
+ * int offset
+ * )
+ * DESCRIPTION: Opens an ASN1 socket.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * tvb: Tvbuff for encoding.
+ * offset: Current offset in tvbuff.
+ * Encoding starts at the end of the buffer, and
+ * proceeds to the beginning.
+ * RETURNS: void
+ */
+
+void
+asn1_open(ASN1_SCK *asn1, tvbuff_t *tvb, int offset)
+{
+ asn1->tvb = tvb;
+ asn1->offset = offset;
+}
+
+/*
+ * NAME: asn1_close [API]
+ * SYNOPSIS: void asn1_close
+ * (
+ * ASN1_SCK *asn1,
+ * int *offset
+ * )
+ * DESCRIPTION: Closes an ASN1 socket.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * offset: pointer to variable into which current offset is
+ * to be put.
+ * RETURNS: void
+ */
+
+void
+asn1_close(ASN1_SCK *asn1, int *offset)
+{
+ *offset = asn1->offset;
+}
+
+/*
+ * NAME: asn1_octet_decode
+ * SYNOPSIS: int asn1_octet_decode
+ * (
+ * ASN1_SCK *asn1,
+ * guchar *ch
+ * )
+ * DESCRIPTION: Decodes an octet.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_octet_decode(ASN1_SCK *asn1, guchar *ch)
+{
+ *ch = tvb_get_guint8(asn1->tvb, asn1->offset);
+ asn1->offset++;
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_tag_get
+ * SYNOPSIS: int asn1_tag_get
+ * (
+ * ASN1_SCK *asn1,
+ * guint *tag
+ * )
+ * DESCRIPTION: Decodes a tag number, combining it with existing tag bits.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+static int
+asn1_tag_get(ASN1_SCK *asn1, guint *tag)
+{
+ int ret;
+ guchar ch;
+
+ do {
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ *tag <<= 7;
+ *tag |= ch & 0x7F;
+ } while ((ch & 0x80) == 0x80);
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_tag_decode
+ * SYNOPSIS: int asn1_tag_decode
+ * (
+ * ASN1_SCK *asn1,
+ * guint *tag
+ * )
+ * DESCRIPTION: Decodes a tag number.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_tag_decode(ASN1_SCK *asn1, guint *tag)
+{
+ *tag = 0;
+ return asn1_tag_get(asn1, tag);
+}
+
+/*
+ * NAME: asn1_id_decode
+ * SYNOPSIS: int asn1_id_decode
+ * (
+ * ASN1_SCK *asn1,
+ * guint *cls,
+ * guint *con,
+ * guint *tag
+ * )
+ * DESCRIPTION: Decodes an identifier.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_id_decode(ASN1_SCK *asn1, guint *cls, guint *con, guint *tag)
+{
+ int ret;
+ guchar ch;
+
+ *tag = 0;
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ *cls = (ch & 0xC0) >> 6;
+ *con = (ch & 0x20) >> 5;
+ *tag = (ch & 0x1F);
+ if (*tag == 0x1F) {
+ ret = asn1_tag_decode (asn1, tag);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ }
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_id_decode1
+ * SYNOPSIS: int asn1_id_decode1
+ * (
+ * ASN1_SCK *asn1,
+ * guint *tag
+ * )
+ * DESCRIPTION: Decodes an identifier.
+ * Like asn1_id_decode() except that the Class and Constructor
+ * bits are returned in the tag.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_id_decode1(ASN1_SCK *asn1, guint *tag)
+{
+ int ret;
+ guchar ch;
+
+ *tag = 0;
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+
+ *tag = ch;
+ if ((*tag & 0x1F) == 0x1F) { /* high-tag-number format */
+ *tag = ch >> 5; /* leave just the Class and Constructor bits */
+ ret = asn1_tag_get (asn1, tag);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ }
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_length_decode
+ * SYNOPSIS: int asn1_length_decode
+ * (
+ * ASN1_SCK *asn1,
+ * gboolean *def,
+ * guint *len
+ * )
+ * DESCRIPTION: Decodes an ASN1 length.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * def: Boolean - TRUE if length definite, FALSE if not
+ * len: length, if length is definite
+ * DESCRIPTION: Decodes a definite or indefinite length.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_length_decode(ASN1_SCK *asn1, gboolean *def, guint *len)
+{
+ int ret;
+ guchar ch, cnt;
+
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ if (ch == 0x80)
+ *def = FALSE; /* indefinite length */
+ else {
+ *def = TRUE; /* definite length */
+ if (ch < 0x80)
+ *len = ch;
+ else {
+ cnt = (guchar) (ch & 0x7F);
+ *len = 0;
+ while (cnt > 0) {
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ *len <<= 8;
+ *len |= ch;
+ cnt--;
+ }
+ }
+ }
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_header_decode [API]
+ * SYNOPSIS: int asn1_header_decode
+ * (
+ * ASN1_SCK *asn1,
+ * guint *cls,
+ * guint *con,
+ * guint *tag
+ * gboolean *defp,
+ * guint *lenp
+ * )
+ * DESCRIPTION: Decodes an ASN1 header.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * cls: Class (see asn1.h)
+ * con: Primitive, Constructed (ASN1_PRI, ASN1_CON)
+ * tag: Tag (see asn1.h)
+ * defp: Boolean - TRUE if length definite, FALSE if not
+ * lenp: length, if length is definite
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_header_decode(ASN1_SCK *asn1, guint *cls, guint *con, guint *tag,
+ gboolean *defp, guint *lenp)
+{
+ int ret;
+ guint def, len;
+
+ ret = asn1_id_decode (asn1, cls, con, tag);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ ret = asn1_length_decode (asn1, &def, &len);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ *defp = def;
+ *lenp = len;
+ return ASN1_ERR_NOERROR;
+}
+
+
+/*
+ * NAME: asn1_eoc [API]
+ * SYNOPSIS: gboolean asn1_eoc
+ * (
+ * ASN1_SCK *asn1,
+ * int eoc
+ * )
+ * DESCRIPTION: Checks if decoding is at End Of Contents.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * eoc: offset of end of encoding, or -1 if indefinite.
+ * RETURNS: gboolean success
+ */
+gboolean
+asn1_eoc ( ASN1_SCK *asn1, int eoc)
+{
+ if (eoc == -1)
+ return (tvb_get_guint8(asn1->tvb, asn1->offset) == 0x00
+ && tvb_get_guint8(asn1->tvb, asn1->offset + 1) == 0x00);
+ else
+ return (asn1->offset >= eoc);
+}
+
+/*
+ * NAME: asn1_eoc_decode [API]
+ * SYNOPSIS: int asn1_eoc_decode
+ * (
+ * ASN1_SCK *asn1,
+ * int eoc
+ * )
+ * DESCRIPTION: Decodes End Of Contents.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * eoc: offset of end of encoding, or -1 if indefinite.
+ * If eoc is -1 it decodes an ASN1 End Of
+ * Contents (0x00 0x00), so it has to be an
+ * indefinite length encoding. If eoc is a non-negative
+ * integer, it probably was filled by asn1_header_decode,
+ * and should refer to the octet after the last of the encoding.
+ * It is checked if this offset refers to the octet to be
+ * decoded. This only takes place in decoding a
+ * definite length encoding.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_eoc_decode (ASN1_SCK *asn1, int eoc)
+{
+ int ret;
+ guchar ch;
+
+ if (eoc == -1) {
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ if (ch != 0x00)
+ return ASN1_ERR_EOC_MISMATCH;
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ if (ch != 0x00)
+ return ASN1_ERR_EOC_MISMATCH;
+ return ASN1_ERR_NOERROR;
+ } else {
+ if (asn1->offset != eoc)
+ return ASN1_ERR_LENGTH_MISMATCH;
+ return ASN1_ERR_NOERROR;
+ }
+}
+
+/*
+ * NAME: asn1_null_decode [API]
+ * SYNOPSIS: int asn1_null_decode
+ * (
+ * ASN1_SCK *asn1,
+ * int enc_len
+ * )
+ * DESCRIPTION: Decodes Null.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * enc_len: length of encoding of value.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_null_decode ( ASN1_SCK *asn1, int enc_len)
+{
+ int start_off = asn1->offset;
+
+ asn1->offset += enc_len;
+ /*
+ * Check for integer overflows.
+ * XXX - ASN1_ERR_LENGTH_MISMATCH seemed like the most appropriate
+ * error from the ones available. Should we make a new one?
+ */
+ if (asn1->offset < 0 || asn1->offset < start_off)
+ return ASN1_ERR_LENGTH_MISMATCH;
+
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_bool_decode [API]
+ * SYNOPSIS: int asn1_bool_decode
+ * (
+ * ASN1_SCK *asn1,
+ * int enc_len,
+ * gboolean *boolean
+ * )
+ * DESCRIPTION: Decodes Boolean.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * enc_len: length of encoding of value.
+ * bool: False, True (0, !0).
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_bool_decode ( ASN1_SCK *asn1, int enc_len, gboolean *boolean)
+{
+ int ret;
+ guchar ch;
+
+ if (enc_len != 1)
+ return ASN1_ERR_LENGTH_MISMATCH;
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ *boolean = ch ? TRUE : FALSE;
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_int32_value_decode [API]
+ * SYNOPSIS: int asn1_int32_value_decode
+ * (
+ * ASN1_SCK *asn1,
+ * int enc_len,
+ * gint32 *integer
+ * )
+ * DESCRIPTION: Decodes value portion of Integer (which must be no more
+ * than 32 bits).
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * enc_len: length of encoding of value.
+ * integer: Integer.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_int32_value_decode ( ASN1_SCK *asn1, int enc_len, gint32 *integer)
+{
+ int ret;
+ int eoc;
+ guchar ch;
+ guint len;
+
+ eoc = asn1->offset + enc_len;
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ *integer = (gint) ch;
+ len = 1;
+ while (asn1->offset < eoc) {
+ if (++len > sizeof (gint32))
+ return ASN1_ERR_WRONG_LENGTH_FOR_TYPE;
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ *integer <<= 8;
+ *integer |= ch;
+ }
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_int32_decode [API]
+ * SYNOPSIS: int asn1_int32_decode
+ * (
+ * ASN1_SCK *asn1,
+ * gint32 *integer,
+ * guint *nbytes,
+ * )
+ * DESCRIPTION: Decodes Integer (which must be no more than 32 bits).
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * integer: Integer.
+ * nbytes: number of bytes used to encode it.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_int32_decode ( ASN1_SCK *asn1, gint32 *integer, guint *nbytes)
+{
+ int ret;
+ int start;
+ guint cls;
+ guint con;
+ guint tag;
+ gboolean def;
+ guint enc_len;
+
+ start = asn1->offset;
+ ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len);
+ if (ret != ASN1_ERR_NOERROR)
+ goto done;
+ if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) {
+ ret = ASN1_ERR_WRONG_TYPE;
+ goto done;
+ }
+ if (!def) {
+ ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
+ goto done;
+ }
+ ret = asn1_int32_value_decode (asn1, enc_len, integer);
+
+done:
+ *nbytes = asn1->offset - start;
+ return ret;
+}
+
+/*
+ * NAME: asn1_uint32_value_decode [API]
+ * SYNOPSIS: int asn1_uint32_value_decode
+ * (
+ * ASN1_SCK *asn1,
+ * int enc_len,
+ * guint32 *integer
+ * )
+ * DESCRIPTION: Decodes value part of Unsigned Integer (which must be no
+ * more than 32 bits).
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * enc_len: length of encoding of value.
+ * integer: Integer.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_uint32_value_decode ( ASN1_SCK *asn1, int enc_len, guint32 *integer)
+{
+ int ret;
+ int eoc;
+ guchar ch;
+ guint len;
+
+ eoc = asn1->offset + enc_len;
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ *integer = ch;
+ if (ch == 0)
+ len = 0;
+ else
+ len = 1;
+ while (asn1->offset < eoc) {
+ if (++len > sizeof (guint32))
+ return ASN1_ERR_WRONG_LENGTH_FOR_TYPE;
+ ret = asn1_octet_decode (asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ *integer <<= 8;
+ *integer |= ch;
+ }
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_uint32_decode [API]
+ * SYNOPSIS: int asn1_uint32_decode
+ * (
+ * ASN1_SCK *asn1,
+ * guint32 *integer,
+ * guint *nbytes,
+ * )
+ * DESCRIPTION: Decodes Unsigned Integer (which must be no more than 32 bits).
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * integer: Integer.
+ * nbytes: number of bytes used to encode it.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_uint32_decode ( ASN1_SCK *asn1, guint32 *integer, guint *nbytes)
+{
+ int ret;
+ int start;
+ guint cls;
+ guint con;
+ guint tag;
+ gboolean def;
+ guint enc_len;
+
+ start = asn1->offset;
+ ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len);
+ if (ret != ASN1_ERR_NOERROR)
+ goto done;
+ if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) {
+ ret = ASN1_ERR_WRONG_TYPE;
+ goto done;
+ }
+ if (!def) {
+ ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
+ goto done;
+ }
+ ret = asn1_uint32_value_decode (asn1, enc_len, integer);
+
+done:
+ *nbytes = asn1->offset - start;
+ return ret;
+}
+
+/*
+ * NAME: asn1_bits_decode [API]
+ * SYNOPSIS: int asn1_bits_decode
+ * (
+ * ASN1_SCK *asn1,
+ * int eoc,
+ * guchar *bits,
+ * guint size,
+ * guint len,
+ * guchar unused
+ * )
+ * DESCRIPTION: Decodes Bit String.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * enc_len: length of value.
+ * bits: pointer to variable we set to point to strring
+ * len: Size of Bit String in characters.
+ * unused: Number of unused bits in last character.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_bits_decode ( ASN1_SCK *asn1, int enc_len, guchar **bits,
+ guint *len, guchar *unused)
+{
+ int ret;
+ int eoc;
+ guchar *ptr;
+
+ eoc = asn1->offset + enc_len;
+ *bits = NULL;
+ ret = asn1_octet_decode (asn1, unused);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ *len = 0;
+
+ /*
+ * First, make sure the entire string is in the tvbuff, and throw
+ * an exception if it isn't. If the length is bogus, this should
+ * keep us from trying to allocate an immensely large buffer.
+ * (It won't help if the length is *valid* but immensely large,
+ * but that's another matter; in any case, that would happen only
+ * if we had an immensely large tvbuff....)
+ */
+ if (enc_len != 0) {
+ tvb_ensure_bytes_exist(asn1->tvb, asn1->offset, enc_len);
+ *bits = g_malloc (enc_len);
+ } else {
+ /*
+ * If the length is 0, we allocate a 1-byte buffer, as
+ * "g_malloc()" returns NULL if passed 0 as an argument,
+ * and our caller expects us to return a pointer to a
+ * buffer.
+ */
+ *bits = g_malloc (1);
+ }
+
+ ptr = *bits;
+ while (asn1->offset < eoc) {
+ ret = asn1_octet_decode (asn1, (guchar *)ptr++);
+ if (ret != ASN1_ERR_NOERROR) {
+ g_free(*bits);
+ *bits = NULL;
+ return ret;
+ }
+ }
+ *len = ptr - *bits;
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_string_value_decode [API]
+ * SYNOPSIS: int asn1_string_value_decode
+ * (
+ * ASN1_SCK *asn1,
+ * int enc_len,
+ * guchar **octets
+ * )
+ * DESCRIPTION: Decodes value portion of string (Octet String, various
+ * character string types)
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * enc_len: length of encoding of value.
+ * octets: pointer to variable we set to point to string,
+ * which is '\0' terminated for ease of use as C-string
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_string_value_decode ( ASN1_SCK *asn1, int enc_len, guchar **octets)
+{
+ int ret;
+ int eoc;
+ guchar *ptr;
+
+ /*
+ * First, make sure the entire string is in the tvbuff, and throw
+ * an exception if it isn't. If the length is bogus, this should
+ * keep us from trying to allocate an immensely large buffer.
+ * (It won't help if the length is *valid* but immensely large,
+ * but that's another matter; in any case, that would happen only
+ * if we had an immensely large tvbuff....)
+ */
+ if (enc_len != 0)
+ tvb_ensure_bytes_exist(asn1->tvb, asn1->offset, enc_len);
+ *octets = g_malloc (enc_len+1);
+
+ eoc = asn1->offset + enc_len;
+ ptr = *octets;
+ while (asn1->offset < eoc) {
+ ret = asn1_octet_decode (asn1, (guchar *)ptr++);
+ if (ret != ASN1_ERR_NOERROR) {
+ g_free(*octets);
+ *octets = NULL;
+ return ret;
+ }
+ }
+ *(guchar *)ptr = '\0';
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_string_decode [API]
+ * SYNOPSIS: int asn1_string_decode
+ * (
+ * ASN1_SCK *asn1,
+ * guchar **octets,
+ * guint *str_len,
+ * guint *nbytes,
+ * guint expected_tag
+ * )
+ * DESCRIPTION: Decodes string (Octet String, various character string
+ * types)
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * octets: pointer to variable we set to point to string.
+ * str_len: length of octet_string.
+ * nbytes: number of bytes used to encode.
+ * expected_tag: tag expected for this type of string.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_string_decode ( ASN1_SCK *asn1, guchar **octets, guint *str_len,
+ guint *nbytes, guint expected_tag)
+{
+ int ret;
+ int start;
+ int enc_len;
+ guint cls;
+ guint con;
+ guint tag;
+ gboolean def;
+
+ start = asn1->offset;
+ ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len);
+ if (ret != ASN1_ERR_NOERROR)
+ goto done;
+ if (cls != ASN1_UNI || con != ASN1_PRI || tag != expected_tag) {
+ /* XXX - handle the constructed encoding? */
+ ret = ASN1_ERR_WRONG_TYPE;
+ goto done;
+ }
+ if (!def) {
+ ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
+ goto done;
+ }
+
+ ret = asn1_string_value_decode (asn1, enc_len, octets);
+ *str_len = enc_len;
+
+done:
+ *nbytes = asn1->offset - start;
+ return ret;
+}
+
+/*
+ * NAME: asn1_octet_string_decode [API]
+ * SYNOPSIS: int asn1_octet_string_decode
+ * (
+ * ASN1_SCK *asn1,
+ * guchar **octets,
+ * guint *str_len,
+ * guint *nbytes,
+ * )
+ * DESCRIPTION: Decodes Octet String.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * octets: pointer to variable we set to point to string.
+ * str_len: length of octet_string.
+ * nbytes: number of bytes used to encode.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_octet_string_decode ( ASN1_SCK *asn1, guchar **octets, guint *str_len,
+ guint *nbytes)
+{
+ return asn1_string_decode(asn1, octets, str_len, nbytes, ASN1_OTS);
+}
+
+/*
+ * NAME: asn1_subid_decode
+ * SYNOPSIS: int asn1_subid_decode
+ * (
+ * ASN1_SCK *asn1,
+ * subid_t *subid
+ * )
+ * DESCRIPTION: Decodes Sub Identifier.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * subid: Sub Identifier.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_subid_decode ( ASN1_SCK *asn1, subid_t *subid)
+{
+ int ret;
+ guchar ch;
+
+ *subid = 0;
+ do {
+ ret = asn1_octet_decode(asn1, &ch);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ *subid <<= 7;
+ *subid |= ch & 0x7F;
+ } while ((ch & 0x80) == 0x80);
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_oid_value_decode [API]
+ * SYNOPSIS: int asn1_oid_value_decode
+ * (
+ * ASN1_SCK *asn1,
+ * int enc_len,
+ * subid_t **oid,
+ * guint *len
+ * )
+ * DESCRIPTION: Decodes value portion of Object Identifier.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * enc_len: length of encoding of value.
+ * oid: pointer to variable we set to Object Identifier.
+ * len: Length of Object Identifier in gulongs.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_oid_value_decode ( ASN1_SCK *asn1, int enc_len, subid_t **oid, guint *len)
+{
+ int ret;
+ int eoc;
+ subid_t subid;
+ guint size;
+ subid_t *optr;
+
+ /*
+ * First, make sure the entire string is in the tvbuff, and throw
+ * an exception if it isn't. If the length is bogus, this should
+ * keep us from trying to allocate an immensely large buffer.
+ * (It won't help if the length is *valid* but immensely large,
+ * but that's another matter; in any case, that would happen only
+ * if we had an immensely large tvbuff....)
+ */
+ if (enc_len != 0)
+ tvb_ensure_bytes_exist(asn1->tvb, asn1->offset, enc_len);
+
+ eoc = asn1->offset + enc_len;
+
+ size = enc_len + 1;
+ *oid = g_malloc(size * sizeof(gulong));
+ optr = *oid;
+
+ ret = asn1_subid_decode (asn1, &subid);
+ if (ret != ASN1_ERR_NOERROR) {
+ g_free(*oid);
+ *oid = NULL;
+ return ret;
+ }
+ if (subid < 40) {
+ optr[0] = 0;
+ optr[1] = subid;
+ } else if (subid < 80) {
+ optr[0] = 1;
+ optr[1] = subid - 40;
+ } else {
+ optr[0] = 2;
+ optr[1] = subid - 80;
+ }
+ *len = 2;
+ optr += 2;
+ while (asn1->offset < eoc) {
+ if (++(*len) > size) {
+ g_free(*oid);
+ *oid = NULL;
+ return ASN1_ERR_WRONG_LENGTH_FOR_TYPE;
+ }
+ ret = asn1_subid_decode (asn1, optr++);
+ if (ret != ASN1_ERR_NOERROR) {
+ g_free(*oid);
+ *oid = NULL;
+ return ret;
+ }
+ }
+ return ASN1_ERR_NOERROR;
+}
+
+/*
+ * NAME: asn1_oid_decode [API]
+ * SYNOPSIS: int asn1_oid_decode
+ * (
+ * ASN1_SCK *asn1,
+ * subid_t **oid,
+ * guint *len,
+ * guint *nbytes
+ * )
+ * DESCRIPTION: Decodes Object Identifier.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * oid: pointer to variable we set to Object Identifier.
+ * len: Length of Object Identifier in gulongs.
+ * nbytes: number of bytes used to encode.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_oid_decode ( ASN1_SCK *asn1, subid_t **oid, guint *len, guint *nbytes)
+{
+ int ret;
+ int start;
+ guint cls;
+ guint con;
+ guint tag;
+ gboolean def;
+ guint enc_len;
+
+ start = asn1->offset;
+ ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len);
+ if (ret != ASN1_ERR_NOERROR)
+ goto done;
+ if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI) {
+ ret = ASN1_ERR_WRONG_TYPE;
+ goto done;
+ }
+ if (!def) {
+ ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
+ goto done;
+ }
+
+ ret = asn1_oid_value_decode (asn1, enc_len, oid, len);
+
+done:
+ *nbytes = asn1->offset - start;
+ return ret;
+}
+
+/*
+ * NAME: asn1_sequence_decode [API]
+ * SYNOPSIS: int asn1_sequence_decode
+ * (
+ * ASN1_SCK *asn1,
+ * guint *seq_len,
+ * guint *nbytes
+ * )
+ * DESCRIPTION: Decodes header for SEQUENCE.
+ * Parameters:
+ * asn1: pointer to ASN1 socket.
+ * seq_len: length of sequence.
+ * nbytes: number of bytes used to encode header.
+ * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
+ */
+int
+asn1_sequence_decode ( ASN1_SCK *asn1, guint *seq_len, guint *nbytes)
+{
+ int ret;
+ int start;
+ guint cls;
+ guint con;
+ guint tag;
+ gboolean def;
+
+ start = asn1->offset;
+ ret = asn1_header_decode(asn1, &cls, &con, &tag,
+ &def, seq_len);
+ if (ret != ASN1_ERR_NOERROR)
+ goto done;
+ if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) {
+ ret = ASN1_ERR_WRONG_TYPE;
+ goto done;
+ }
+ if (!def) {
+ /* XXX - might some sequences have an indefinite length? */
+ ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
+ goto done;
+ }
+ ret = ASN1_ERR_NOERROR;
+
+done:
+ *nbytes = asn1->offset - start;
+ return ret;
+}
+
+/*
+ * NAME: asn1_err_to_str [API]
+ * SYNOPSIS: char *asn1_err_to_str
+ * (
+ * int err
+ * )
+ * DESCRIPTION: Returns the string corresponding to an ASN.1 library error.
+ * Parameters:
+ * err: the error code
+ * RETURNS: string for the error
+ */
+char *
+asn1_err_to_str(int err)
+{
+ char *errstr;
+ char errstrbuf[14+1+1+11+1+1]; /* "Unknown error (%d)\0" */
+
+ switch (err) {
+
+ case ASN1_ERR_EOC_MISMATCH:
+ errstr = "EOC mismatch";
+ break;
+
+ case ASN1_ERR_WRONG_TYPE:
+ errstr = "Wrong type for that item";
+ break;
+
+ case ASN1_ERR_LENGTH_NOT_DEFINITE:
+ errstr = "Length was indefinite";
+ break;
+
+ case ASN1_ERR_LENGTH_MISMATCH:
+ errstr = "Length mismatch";
+ break;
+
+ case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
+ errstr = "Wrong length for that item's type";
+ break;
+
+ default:
+ snprintf(errstrbuf, sizeof errstrbuf, "Unknown error (%d)", err);
+ errstr = errstrbuf;
+ break;
+ }
+ return errstr;
+}
diff --git a/epan/asn1.h b/epan/asn1.h
new file mode 100644
index 0000000000..5d751ff7fd
--- /dev/null
+++ b/epan/asn1.h
@@ -0,0 +1,150 @@
+/* asn1.h
+ * Definitions for ASN.1 BER dissection
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ *
+ * Based on "g_asn1.h" from:
+ *
+ * GXSNMP -- An snmp mangament application
+ * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
+ * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __ASN1_H__
+#define __ASN1_H__
+
+#define ASN1_UNI 0 /* Universal */
+#define ASN1_APL 1 /* Application */
+#define ASN1_CTX 2 /* Context */
+#define ASN1_PRV 3 /* Private */
+
+ /* Tag */
+#define ASN1_EOC 0 /* End Of Contents */
+#define ASN1_BOL 1 /* Boolean */
+#define ASN1_INT 2 /* Integer */
+#define ASN1_BTS 3 /* Bit String */
+#define ASN1_OTS 4 /* Octet String */
+#define ASN1_NUL 5 /* Null */
+#define ASN1_OJI 6 /* Object Identifier */
+#define ASN1_OJD 7 /* Object Description */
+#define ASN1_EXT 8 /* External */
+#define ASN1_REAL 9 /* Real */
+#define ASN1_ENUM 10 /* Enumerated */
+#define ASN1_SEQ 16 /* Sequence */
+#define ASN1_SET 17 /* Set */
+#define ASN1_NUMSTR 18 /* Numerical String */
+#define ASN1_PRNSTR 19 /* Printable String */
+#define ASN1_TEXSTR 20 /* Teletext String */
+#define ASN1_VIDSTR 21 /* Video String */
+#define ASN1_IA5STR 22 /* IA5 String */
+#define ASN1_UNITIM 23 /* Universal Time */
+#define ASN1_GENTIM 24 /* General Time */
+#define ASN1_GRASTR 25 /* Graphical String */
+#define ASN1_VISSTR 26 /* Visible String */
+#define ASN1_GENSTR 27 /* General String */
+
+ /* Primitive / Constructed */
+#define ASN1_PRI 0 /* Primitive */
+#define ASN1_CON 1 /* Constructed */
+
+/*
+ * Oh, this is hellish.
+ *
+ * The CMU SNMP library defines an OID as a sequence of "u_int"s,
+ * unless EIGHTBIT_SUBIDS is defined, in which case it defines
+ * an OID as a sequence of "u_char"s. None of its header files
+ * define EIGHTBIT_SUBIDS, and if a program defines it, that's
+ * not going to change the library to treat OIDs as sequences
+ * of "u_chars", so I'll assume that it'll be "u_int"s.
+ *
+ * The UCD SNMP library does the same, except it defines an OID
+ * as a sequence of "u_long"s, by default.
+ *
+ * "libsmi" defines it as a sequence of "unsigned int"s.
+ *
+ * I don't want to oblige all users of ASN.1 to include the SNMP
+ * library header files, so I'll assume none of the SNMP libraries
+ * will rudely surprise me by changing the definition; if they
+ * do, there will be compiler warnings, so we'll at least be able
+ * to catch it.
+ *
+ * This requires that, if you're going to use "asn1_subid_decode()",
+ * "asn1_oid_value_decode()", or "asn1_oid_decode()", you include
+ * "config.h", to get the right #defines defined, so that we properly
+ * typedef "subid_t".
+ */
+#if defined(HAVE_SOME_SNMP)
+typedef gulong subid_t; /* Net-SNMP or UCD SNMP */
+#else
+typedef guint subid_t; /* CMU SNMP, libsmi, or nothing */
+#endif
+
+#define ASN1_ERR_NOERROR 0 /* no error */
+#define ASN1_ERR_EOC_MISMATCH 1
+#define ASN1_ERR_WRONG_TYPE 2 /* type not right */
+#define ASN1_ERR_LENGTH_NOT_DEFINITE 3 /* length should be definite */
+#define ASN1_ERR_LENGTH_MISMATCH 4
+#define ASN1_ERR_WRONG_LENGTH_FOR_TYPE 5 /* length wrong for type */
+
+typedef struct _ASN1_SCK ASN1_SCK;
+
+struct _ASN1_SCK
+{ /* ASN1 socket */
+ tvbuff_t *tvb; /* Tvbuff whence the data comes */
+ int offset; /* Current offset in tvbuff */
+};
+
+extern void asn1_open (ASN1_SCK *asn1, tvbuff_t *tvb, int offset);
+extern void asn1_close (ASN1_SCK *asn1, int *offset);
+extern int asn1_octet_decode (ASN1_SCK *asn1, guchar *ch);
+extern int asn1_tag_decode (ASN1_SCK *asn1, guint *tag);
+extern int asn1_id_decode (ASN1_SCK *asn1, guint *cls, guint *con, guint *tag);
+extern int asn1_id_decode1 (ASN1_SCK *asn1, guint *tag);
+extern int asn1_length_decode (ASN1_SCK *asn1, gboolean *def, guint *len);
+extern int asn1_header_decode(ASN1_SCK *asn1, guint *cls, guint *con,
+ guint *tag, gboolean *defp, guint *lenp);
+extern int asn1_eoc (ASN1_SCK *asn1, int eoc);
+extern int asn1_eoc_decode (ASN1_SCK *asn1, int eoc);
+extern int asn1_null_decode (ASN1_SCK *asn1, int enc_len);
+extern int asn1_bool_decode (ASN1_SCK *asn1, int enc_len, gboolean *boolean);
+extern int asn1_int32_value_decode (ASN1_SCK *asn1, int enc_len,
+ gint32 *integer);
+extern int asn1_int32_decode (ASN1_SCK *asn1, gint32 *integer, guint *nbytes);
+extern int asn1_uint32_value_decode (ASN1_SCK *asn1, int enc_len,
+ guint32 *integer);
+extern int asn1_uint32_decode (ASN1_SCK *asn1, guint32 *integer, guint *nbytes);
+extern int asn1_bits_decode (ASN1_SCK *asn1, int enc_len, guchar **bits,
+ guint *len, guchar *unused);
+extern int asn1_string_value_decode (ASN1_SCK *asn1, int enc_len,
+ guchar **octets);
+extern int asn1_string_decode (ASN1_SCK *asn1, guchar **octets, guint *str_len,
+ guint *nbytes, guint expected_tag);
+extern int asn1_octet_string_decode (ASN1_SCK *asn1, guchar **octets,
+ guint *str_len, guint *nbytes);
+extern int asn1_subid_decode (ASN1_SCK *asn1, subid_t *subid);
+extern int asn1_oid_value_decode (ASN1_SCK *asn1, int enc_len, subid_t **oid,
+ guint *len);
+extern int asn1_oid_decode (ASN1_SCK *asn1, subid_t **oid, guint *len,
+ guint *nbytes);
+extern int asn1_sequence_decode (ASN1_SCK *asn1, guint *seq_len, guint *nbytes);
+
+extern char *asn1_err_to_str (int err);
+
+#endif
diff --git a/epan/dissectors/ncp2222.py b/epan/dissectors/ncp2222.py
index b341510745..5e156ccf62 100755
--- a/epan/dissectors/ncp2222.py
+++ b/epan/dissectors/ncp2222.py
@@ -5559,7 +5559,7 @@ def produce_code():
#include <glib.h>
#include <epan/packet.h>
#include <epan/conversation.h>
-#include "ptvcursor.h"
+#include <epan/ptvcursor.h>
#include "packet-ncp-int.h"
#include "packet-ncp-nmas.h"
#include <epan/strutil.h>
diff --git a/epan/dissectors/packet-acse.c b/epan/dissectors/packet-acse.c
index 1ba1eb52ea..778c6f2695 100644
--- a/epan/dissectors/packet-acse.c
+++ b/epan/dissectors/packet-acse.c
@@ -41,7 +41,7 @@
#include <epan/strutil.h>
-#include "asn1.h"
+#include <epan/asn1.h>
#include "format-oid.h"
#include "packet-ses.h"
diff --git a/epan/dissectors/packet-ansi_map.c b/epan/dissectors/packet-ansi_map.c
index ad5928a32e..3b9dd942f1 100644
--- a/epan/dissectors/packet-ansi_map.c
+++ b/epan/dissectors/packet-ansi_map.c
@@ -110,7 +110,7 @@
#include <string.h>
#include "epan/packet.h"
-#include "asn1.h"
+#include <epan/asn1.h>
#include <epan/tap.h>
#include "packet-ansi_a.h"
diff --git a/epan/dissectors/packet-atalk.c b/epan/dissectors/packet-atalk.c
index 3204e7e79a..7f48b4e346 100644
--- a/epan/dissectors/packet-atalk.c
+++ b/epan/dissectors/packet-atalk.c
@@ -41,7 +41,7 @@
#include <epan/conversation.h>
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include "packet-afp.h"
diff --git a/epan/dissectors/packet-clnp.c b/epan/dissectors/packet-clnp.c
index e1dbb4a3e7..95da85266f 100644
--- a/epan/dissectors/packet-clnp.c
+++ b/epan/dissectors/packet-clnp.c
@@ -33,7 +33,7 @@
#include <glib.h>
#include <epan/prefs.h>
#include <epan/packet.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include "packet-osi.h"
#include "packet-osi-options.h"
#include "packet-isis.h"
diff --git a/epan/dissectors/packet-cops.c b/epan/dissectors/packet-cops.c
index f69dc05a59..5b42d14293 100644
--- a/epan/dissectors/packet-cops.c
+++ b/epan/dissectors/packet-cops.c
@@ -84,7 +84,7 @@
#endif /* HAVE_NET_SNMP */
#endif /* HAVE_SOME_SNMP */
-#include "asn1.h"
+#include <epan/asn1.h>
#include "format-oid.h"
#include <epan/prefs.h>
diff --git a/epan/dissectors/packet-dcerpc.c b/epan/dissectors/packet-dcerpc.c
index 0dde4abb9f..4c762c6826 100644
--- a/epan/dissectors/packet-dcerpc.c
+++ b/epan/dissectors/packet-dcerpc.c
@@ -40,7 +40,7 @@
#include <epan/dissectors/packet-dcerpc.h>
#include <epan/conversation.h>
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/tap.h>
#include <epan/dissectors/packet-frame.h>
#include <epan/dissectors/packet-dcerpc-nt.h>
diff --git a/epan/dissectors/packet-diameter.c b/epan/dissectors/packet-diameter.c
index 1c7d096c60..1a33176b5a 100644
--- a/epan/dissectors/packet-diameter.c
+++ b/epan/dissectors/packet-diameter.c
@@ -48,7 +48,7 @@
#include <time.h>
#include <glib.h>
#include <epan/filesystem.h>
-#include "xmlstub.h"
+#include <epan/xmlstub.h>
#include <epan/packet.h>
#include <epan/addr_resolv.h>
#include <epan/report_err.h>
diff --git a/epan/dissectors/packet-dnp.c b/epan/dissectors/packet-dnp.c
index 1c69ff1f35..7d3dda725d 100644
--- a/epan/dissectors/packet-dnp.c
+++ b/epan/dissectors/packet-dnp.c
@@ -40,7 +40,7 @@
#include <epan/packet.h>
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
/*
* See
diff --git a/epan/dissectors/packet-eap.c b/epan/dissectors/packet-eap.c
index 72389f65b9..570a212400 100644
--- a/epan/dissectors/packet-eap.c
+++ b/epan/dissectors/packet-eap.c
@@ -31,7 +31,7 @@
#include <epan/packet.h>
#include <epan/conversation.h>
#include "ppptypes.h"
-#include "reassemble.h"
+#include <epan/reassemble.h>
static int proto_eap = -1;
static int hf_eap_code = -1;
diff --git a/epan/dissectors/packet-fc.c b/epan/dissectors/packet-fc.c
index 73acfb07e2..85810905d4 100644
--- a/epan/dissectors/packet-fc.c
+++ b/epan/dissectors/packet-fc.c
@@ -50,7 +50,7 @@
#include <epan/packet.h>
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/conversation.h>
#include "etypes.h"
#include "packet-fc.h"
diff --git a/epan/dissectors/packet-ftam.c b/epan/dissectors/packet-ftam.c
index ebec9ad767..90eaa400eb 100644
--- a/epan/dissectors/packet-ftam.c
+++ b/epan/dissectors/packet-ftam.c
@@ -42,7 +42,7 @@
#include <epan/strutil.h>
-#include "asn1.h"
+#include <epan/asn1.h>
#include "format-oid.h"
#include "packet-ses.h"
diff --git a/epan/dissectors/packet-gsm_a.c b/epan/dissectors/packet-gsm_a.c
index a5c7428026..8b93c4e6ae 100644
--- a/epan/dissectors/packet-gsm_a.c
+++ b/epan/dissectors/packet-gsm_a.c
@@ -84,7 +84,7 @@
#include <epan/prefs.h>
#include <epan/ipv6-utils.h>
#include <epan/tap.h>
-#include "asn1.h"
+#include <epan/asn1.h>
#include "packet-tcap.h"
#include "packet-bssap.h"
diff --git a/epan/dissectors/packet-gsm_sms_ud.c b/epan/dissectors/packet-gsm_sms_ud.c
index 542207d213..005cae0a11 100644
--- a/epan/dissectors/packet-gsm_sms_ud.c
+++ b/epan/dissectors/packet-gsm_sms_ud.c
@@ -70,7 +70,7 @@
#include <epan/packet.h>
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
static void dissect_gsm_sms_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
diff --git a/epan/dissectors/packet-gsm_ss.c b/epan/dissectors/packet-gsm_ss.c
index 2be9f7aef5..f91bf761d1 100644
--- a/epan/dissectors/packet-gsm_ss.c
+++ b/epan/dissectors/packet-gsm_ss.c
@@ -56,7 +56,7 @@
#include "epan/packet.h"
#include <epan/tap.h>
-#include "asn1.h"
+#include <epan/asn1.h>
#include "packet-tcap.h"
#include "packet-gsm_sms.h"
diff --git a/epan/dissectors/packet-gssapi.c b/epan/dissectors/packet-gssapi.c
index 5356ba024c..ac3ad4bb95 100644
--- a/epan/dissectors/packet-gssapi.c
+++ b/epan/dissectors/packet-gssapi.c
@@ -38,7 +38,7 @@
#include <glib.h>
#include <epan/packet.h>
-#include "asn1.h"
+#include <epan/asn1.h>
#include "format-oid.h"
#include <epan/dissectors/packet-dcerpc.h>
#include <epan/dissectors/packet-gssapi.h>
diff --git a/epan/dissectors/packet-ieee80211.c b/epan/dissectors/packet-ieee80211.c
index 5805a4f720..330d1338b1 100644
--- a/epan/dissectors/packet-ieee80211.c
+++ b/epan/dissectors/packet-ieee80211.c
@@ -62,7 +62,7 @@
#include <epan/addr_resolv.h>
#include <epan/strutil.h>
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include "packet-ipx.h"
#include "packet-llc.h"
#include "packet-ieee80211.h"
diff --git a/epan/dissectors/packet-inap.c b/epan/dissectors/packet-inap.c
index b062dd0800..8c5bfb3814 100644
--- a/epan/dissectors/packet-inap.c
+++ b/epan/dissectors/packet-inap.c
@@ -11,7 +11,7 @@
* Copyright 2004, Tim Endean <endeant@hotmail.com>
* Built from the gsm-map dissector Copyright 2004, Anders Broman <anders.broman@ericsson.com>
*
- * $Id:$
+ * $Id$
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
diff --git a/epan/dissectors/packet-ip.c b/epan/dissectors/packet-ip.c
index 646a822a9d..7e5f6e8a43 100644
--- a/epan/dissectors/packet-ip.c
+++ b/epan/dissectors/packet-ip.c
@@ -39,7 +39,7 @@
#include <epan/ipproto.h>
#include "ip_opts.h"
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include "etypes.h"
#include "greproto.h"
#include "ppptypes.h"
diff --git a/epan/dissectors/packet-ipv6.c b/epan/dissectors/packet-ipv6.c
index dce5de93fb..9b4bf99e0c 100644
--- a/epan/dissectors/packet-ipv6.c
+++ b/epan/dissectors/packet-ipv6.c
@@ -37,7 +37,7 @@
#include "ip_opts.h"
#include <epan/addr_resolv.h>
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/ipproto.h>
#include "etypes.h"
#include "ppptypes.h"
diff --git a/epan/dissectors/packet-kerberos.c b/epan/dissectors/packet-kerberos.c
index afa3dfe7d4..bab8577bd7 100644
--- a/epan/dissectors/packet-kerberos.c
+++ b/epan/dissectors/packet-kerberos.c
@@ -94,7 +94,7 @@
#include <epan/dissectors/packet-dcerpc-netlogon.h>
#include <epan/dissectors/packet-dcerpc.h>
-#include "asn1.h" /* for "subid_t" */
+#include <epan/asn1.h> /* for "subid_t" */
#include <epan/dissectors/packet-gssapi.h>
#define UDP_PORT_KERBEROS 88
diff --git a/epan/dissectors/packet-ldap.c b/epan/dissectors/packet-ldap.c
index 19eb208d18..5ffd40d666 100644
--- a/epan/dissectors/packet-ldap.c
+++ b/epan/dissectors/packet-ldap.c
@@ -79,7 +79,7 @@
#include <epan/packet.h>
-#include "asn1.h"
+#include <epan/asn1.h>
#include <epan/prefs.h>
#include <epan/conversation.h>
#include "packet-frame.h"
diff --git a/epan/dissectors/packet-lwapp.c b/epan/dissectors/packet-lwapp.c
index cdba063454..b3aa845a76 100644
--- a/epan/dissectors/packet-lwapp.c
+++ b/epan/dissectors/packet-lwapp.c
@@ -37,7 +37,7 @@
#include <time.h>
#include <glib.h>
#include <epan/filesystem.h>
-#include "xmlstub.h"
+#include <epan/xmlstub.h>
#include <epan/packet.h>
#include <epan/addr_resolv.h>
#include <epan/prefs.h>
diff --git a/epan/dissectors/packet-mq.c b/epan/dissectors/packet-mq.c
index fdea9d0121..a1f7aabe64 100644
--- a/epan/dissectors/packet-mq.c
+++ b/epan/dissectors/packet-mq.c
@@ -71,7 +71,7 @@
#include <glib.h>
#include <epan/packet.h>
#include <epan/conversation.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/prefs.h>
#include "packet-tcp.h"
#include "packet-mq.h"
diff --git a/epan/dissectors/packet-mysql.c b/epan/dissectors/packet-mysql.c
index 73f45389bf..46fb2f74ef 100644
--- a/epan/dissectors/packet-mysql.c
+++ b/epan/dissectors/packet-mysql.c
@@ -40,7 +40,7 @@
#include <epan/conversation.h>
#include "packet-tcp.h"
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/prefs.h>
/* Capabilities */
diff --git a/epan/dissectors/packet-ncp.c b/epan/dissectors/packet-ncp.c
index e3d453b9fd..7d4035a65d 100644
--- a/epan/dissectors/packet-ncp.c
+++ b/epan/dissectors/packet-ncp.c
@@ -49,7 +49,7 @@
#include "packet-ipx.h"
#include "packet-tcp.h"
#include "packet-ncp-int.h"
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/conversation.h>
int proto_ncp = -1;
diff --git a/epan/dissectors/packet-ndmp.c b/epan/dissectors/packet-ndmp.c
index 535b9d11ec..002178d56b 100644
--- a/epan/dissectors/packet-ndmp.c
+++ b/epan/dissectors/packet-ndmp.c
@@ -42,7 +42,7 @@
#include "packet-scsi.h"
#include "packet-frame.h"
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include "rpc_defrag.h"
#define TCP_PORT_NDMP 10000
diff --git a/epan/dissectors/packet-ndps.c b/epan/dissectors/packet-ndps.c
index a35961ebbf..6ea84aba9b 100644
--- a/epan/dissectors/packet-ndps.c
+++ b/epan/dissectors/packet-ndps.c
@@ -36,7 +36,7 @@
#include "packet-tcp.h"
#include <epan/conversation.h>
#include "packet-ndps.h"
-#include "reassemble.h"
+#include <epan/reassemble.h>
#define NDPS_PACKET_INIT_COUNT 200
diff --git a/epan/dissectors/packet-netbios.c b/epan/dissectors/packet-netbios.c
index 364ca9faa5..1d3b29289f 100644
--- a/epan/dissectors/packet-netbios.c
+++ b/epan/dissectors/packet-netbios.c
@@ -36,7 +36,7 @@
#include <epan/packet.h>
#include "llcsaps.h"
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/prefs.h>
#include "packet-netbios.h"
diff --git a/epan/dissectors/packet-ntlmssp.c b/epan/dissectors/packet-ntlmssp.c
index 1b5790c412..707e90c4ff 100644
--- a/epan/dissectors/packet-ntlmssp.c
+++ b/epan/dissectors/packet-ntlmssp.c
@@ -36,7 +36,7 @@
#include "packet-windows-common.h"
#include "packet-smb-common.h"
-#include "asn1.h" /* XXX - needed for subid_t */
+#include <epan/asn1.h> /* XXX - needed for subid_t */
#include "packet-gssapi.h"
#include "packet-frame.h"
#include <epan/prefs.h>
diff --git a/epan/dissectors/packet-pgsql.c b/epan/dissectors/packet-pgsql.c
index ee3727e291..34371d0a10 100644
--- a/epan/dissectors/packet-pgsql.c
+++ b/epan/dissectors/packet-pgsql.c
@@ -34,7 +34,7 @@
#include <epan/prefs.h>
#include "packet-tcp.h"
-#include "reassemble.h"
+#include <epan/reassemble.h>
static int proto_pgsql = -1;
diff --git a/epan/dissectors/packet-pres.c b/epan/dissectors/packet-pres.c
index b692101ae7..b988fb9b97 100644
--- a/epan/dissectors/packet-pres.c
+++ b/epan/dissectors/packet-pres.c
@@ -41,7 +41,7 @@
#include <epan/strutil.h>
-#include "asn1.h"
+#include <epan/asn1.h>
#include "format-oid.h"
#include "packet-ses.h"
diff --git a/epan/dissectors/packet-q931.c b/epan/dissectors/packet-q931.c
index 4e2f40000b..96189169cf 100644
--- a/epan/dissectors/packet-q931.c
+++ b/epan/dissectors/packet-q931.c
@@ -39,7 +39,7 @@
#include "packet-q931.h"
#include "packet-e164.h"
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include "lapd_sapi.h"
#include "packet-tpkt.h"
diff --git a/epan/dissectors/packet-rpc.c b/epan/dissectors/packet-rpc.c
index c6c56d0d50..933561b36d 100644
--- a/epan/dissectors/packet-rpc.c
+++ b/epan/dissectors/packet-rpc.c
@@ -39,7 +39,7 @@
#include "packet-frame.h"
#include "packet-tcp.h"
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include "rpc_defrag.h"
#include "packet-nfs.h"
#include <epan/tap.h>
diff --git a/epan/dissectors/packet-smb-pipe.c b/epan/dissectors/packet-smb-pipe.c
index e2bb58e518..8d7ca90ee3 100644
--- a/epan/dissectors/packet-smb-pipe.c
+++ b/epan/dissectors/packet-smb-pipe.c
@@ -48,7 +48,7 @@ XXX Fixme : shouldnt show [malformed frame] for long packets
#include "packet-smb-common.h"
#include "packet-windows-common.h"
#include "packet-dcerpc.h"
-#include "reassemble.h"
+#include <epan/reassemble.h>
static int proto_smb_pipe = -1;
static int hf_pipe_function = -1;
diff --git a/epan/dissectors/packet-smb.c b/epan/dissectors/packet-smb.c
index a9e60e1d49..d2ea3ab4b2 100644
--- a/epan/dissectors/packet-smb.c
+++ b/epan/dissectors/packet-smb.c
@@ -41,7 +41,7 @@
#include "smb.h"
#include <epan/strutil.h>
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/tap.h>
#include "packet-ipx.h"
diff --git a/epan/dissectors/packet-sna.c b/epan/dissectors/packet-sna.c
index 9fc9603edb..70e8ef4337 100644
--- a/epan/dissectors/packet-sna.c
+++ b/epan/dissectors/packet-sna.c
@@ -35,7 +35,7 @@
#include <epan/sna-utils.h>
#include <epan/charsets.h>
#include <epan/prefs.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
/*
* http://www.wanresources.com/snacell.html
diff --git a/epan/dissectors/packet-sndcp.c b/epan/dissectors/packet-sndcp.c
index b6123b3310..f46da753d7 100644
--- a/epan/dissectors/packet-sndcp.c
+++ b/epan/dissectors/packet-sndcp.c
@@ -38,7 +38,7 @@
#endif
#include <epan/packet.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
/* Bitmasks for the bits in the address field
*/
diff --git a/epan/dissectors/packet-snmp.c b/epan/dissectors/packet-snmp.c
index e63a930abd..18c2fcc753 100644
--- a/epan/dissectors/packet-snmp.c
+++ b/epan/dissectors/packet-snmp.c
@@ -105,7 +105,7 @@
#endif /* HAVE_SOME_SNMP */
-#include "asn1.h"
+#include <epan/asn1.h>
#include "packet-snmp.h"
#include "format-oid.h"
diff --git a/epan/dissectors/packet-spnego.c b/epan/dissectors/packet-spnego.c
index 28255daa0c..6ad56b9656 100644
--- a/epan/dissectors/packet-spnego.c
+++ b/epan/dissectors/packet-spnego.c
@@ -37,7 +37,7 @@
#include <glib.h>
#include <epan/packet.h>
-#include "asn1.h"
+#include <epan/asn1.h>
#include "format-oid.h"
#include "packet-gssapi.h"
#include "packet-kerberos.h"
diff --git a/epan/dissectors/packet-srvloc.c b/epan/dissectors/packet-srvloc.c
index 7a5a0c1b62..5105f36da1 100644
--- a/epan/dissectors/packet-srvloc.c
+++ b/epan/dissectors/packet-srvloc.c
@@ -49,7 +49,7 @@
#include <epan/strutil.h>
#include <epan/prefs.h>
#include "packet-tcp.h"
-#include "reassemble.h"
+#include <epan/reassemble.h>
static gboolean srvloc_desegment = TRUE;
static int proto_srvloc = -1;
diff --git a/epan/dissectors/packet-ssh.c b/epan/dissectors/packet-ssh.c
index 9de167baa0..d6cc21821b 100644
--- a/epan/dissectors/packet-ssh.c
+++ b/epan/dissectors/packet-ssh.c
@@ -39,7 +39,7 @@
#include <epan/conversation.h>
#include "packet-tcp.h"
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/prefs.h>
/* get from openssh ssh2.h */
diff --git a/epan/dissectors/packet-tcap.c b/epan/dissectors/packet-tcap.c
index ce8865d7b6..1c8bf2f178 100644
--- a/epan/dissectors/packet-tcap.c
+++ b/epan/dissectors/packet-tcap.c
@@ -61,7 +61,7 @@
#include <epan/packet.h>
#include <epan/prefs.h>
-#include "asn1.h"
+#include <epan/asn1.h>
#include "packet-tcap.h"
#include "packet-ber.h"
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
index b7065674ed..c64d74d691 100644
--- a/epan/dissectors/packet-tcp.c
+++ b/epan/dissectors/packet-tcp.c
@@ -35,14 +35,14 @@
#include <epan/addr_resolv.h>
#include <epan/ipproto.h>
#include "ip_opts.h"
-#include "follow.h"
+#include <epan/follow.h>
#include <epan/prefs.h>
#include "packet-tcp.h"
#include "packet-ip.h"
#include "packet-frame.h"
#include <epan/conversation.h>
#include <epan/strutil.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/tap.h>
static int tcp_tap = -1;
diff --git a/epan/dissectors/packet-tds.c b/epan/dissectors/packet-tds.c
index 7cb1124d26..511eeba062 100644
--- a/epan/dissectors/packet-tds.c
+++ b/epan/dissectors/packet-tds.c
@@ -157,7 +157,7 @@
#include <epan/strutil.h>
#include "packet-frame.h"
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/prefs.h>
#define TDS_QUERY_PKT 1
diff --git a/epan/dissectors/packet-wtp.c b/epan/dissectors/packet-wtp.c
index f9082b2780..36649ead4c 100644
--- a/epan/dissectors/packet-wtp.c
+++ b/epan/dissectors/packet-wtp.c
@@ -41,7 +41,7 @@
#include <string.h>
#include <glib.h>
#include <epan/packet.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include "packet-wap.h"
#include "packet-wtp.h"
#include "packet-wsp.h"
diff --git a/epan/dissectors/packet-x25.c b/epan/dissectors/packet-x25.c
index b7f2d4d69f..aba61af789 100644
--- a/epan/dissectors/packet-x25.c
+++ b/epan/dissectors/packet-x25.c
@@ -34,7 +34,7 @@
#include "llcsaps.h"
#include <epan/packet.h>
#include <epan/circuit.h>
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/prefs.h>
#include "nlpid.h"
#include "x264_prt_id.h"
diff --git a/epan/follow.c b/epan/follow.c
new file mode 100644
index 0000000000..19e14303b2
--- /dev/null
+++ b/epan/follow.c
@@ -0,0 +1,336 @@
+/* follow.c
+ *
+ * $Id$
+ *
+ * Copyright 1998 Mike Hall <mlh@io.com>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <glib.h>
+#include <epan/packet.h>
+#include "follow.h"
+
+#define MAX_IPADDR_LEN 16
+
+typedef struct _tcp_frag {
+ gulong seq;
+ gulong len;
+ gulong data_len;
+ gchar *data;
+ struct _tcp_frag *next;
+} tcp_frag;
+
+FILE* data_out_file = NULL;
+
+gboolean incomplete_tcp_stream = FALSE;
+
+static guint8 ip_address[2][MAX_IPADDR_LEN];
+static guint tcp_port[2];
+static guint bytes_written[2];
+static gboolean is_ipv6 = FALSE;
+
+static int check_fragments( int, tcp_stream_chunk * );
+static void write_packet_data( int, tcp_stream_chunk *, const char * );
+
+void
+follow_tcp_stats(follow_tcp_stats_t* stats)
+{
+ int i;
+
+ for (i = 0; i < 2 ; i++) {
+ memcpy(stats->ip_address[i], ip_address[i], MAX_IPADDR_LEN);
+ stats->tcp_port[i] = tcp_port[i];
+ stats->bytes_written[i] = bytes_written[i];
+ stats->is_ipv6 = is_ipv6;
+ }
+}
+
+/* this will build libpcap filter text that will only
+ pass the packets related to the stream. There is a
+ chance that two streams could intersect, but not a
+ very good one */
+char*
+build_follow_filter( packet_info *pi ) {
+ char* buf = g_malloc(1024);
+ int len;
+ if( pi->net_src.type == AT_IPv4 && pi->net_dst.type == AT_IPv4
+ && pi->ipproto == 6 ) {
+ /* TCP over IPv4 */
+ sprintf( buf,
+ "(ip.addr eq %s and ip.addr eq %s) and (tcp.port eq %d and tcp.port eq %d)",
+ ip_to_str( pi->net_src.data),
+ ip_to_str( pi->net_dst.data),
+ pi->srcport, pi->destport );
+ len = 4;
+ is_ipv6 = FALSE;
+ }
+ else if( pi->net_src.type == AT_IPv6 && pi->net_dst.type == AT_IPv6
+ && pi->ipproto == 6 ) {
+ /* TCP over IPv6 */
+ sprintf( buf,
+ "(ipv6.addr eq %s and ipv6.addr eq %s) and (tcp.port eq %d and tcp.port eq %d)",
+ ip6_to_str((const struct e_in6_addr *)pi->net_src.data),
+ ip6_to_str((const struct e_in6_addr *)pi->net_dst.data),
+ pi->srcport, pi->destport );
+ len = 16;
+ is_ipv6 = TRUE;
+ }
+ else {
+ g_free( buf );
+ return NULL;
+ }
+ memcpy(ip_address[0], pi->net_src.data, len);
+ memcpy(ip_address[1], pi->net_dst.data, len);
+ tcp_port[0] = pi->srcport;
+ tcp_port[1] = pi->destport;
+ return buf;
+}
+
+/* here we are going to try and reconstruct the data portion of a TCP
+ session. We will try and handle duplicates, TCP fragments, and out
+ of order packets in a smart way. */
+
+static tcp_frag *frags[2] = { 0, 0 };
+static gulong seq[2];
+static guint8 src_addr[2][MAX_IPADDR_LEN];
+static guint src_port[2] = { 0, 0 };
+
+void
+reassemble_tcp( gulong sequence, gulong length, const char* data,
+ gulong data_length, int synflag, address *net_src,
+ address *net_dst, guint srcport, guint dstport) {
+ guint8 srcx[MAX_IPADDR_LEN], dstx[MAX_IPADDR_LEN];
+ int src_index, j, first = 0, len;
+ gulong newseq;
+ tcp_frag *tmp_frag;
+ tcp_stream_chunk sc;
+
+ src_index = -1;
+
+ /* First, check if this packet should be processed. */
+
+ if ((net_src->type != AT_IPv4 && net_src->type != AT_IPv6) ||
+ (net_dst->type != AT_IPv4 && net_dst->type != AT_IPv6))
+ return;
+
+ if (net_src->type == AT_IPv4)
+ len = 4;
+ else
+ len = 16;
+
+ /* Now check if the packet is for this connection. */
+ memcpy(srcx, net_src->data, len);
+ memcpy(dstx, net_dst->data, len);
+ if (
+ ! (
+ memcmp(srcx, ip_address[0], len) == 0 &&
+ memcmp(dstx, ip_address[1], len) == 0 &&
+ srcport == tcp_port[0] &&
+ dstport == tcp_port[1]
+ ) &&
+ ! (
+ memcmp(srcx, ip_address[1], len) == 0 &&
+ memcmp(dstx, ip_address[0], len) == 0 &&
+ srcport == tcp_port[1] &&
+ dstport == tcp_port[0]
+ )
+ )
+ return;
+
+ /* Initialize our stream chunk. This data gets written to disk. */
+ memcpy(sc.src_addr, srcx, len);
+ sc.src_port = srcport;
+ sc.dlen = data_length;
+
+ /* Check to see if we have seen this source IP and port before.
+ (Yes, we have to check both source IP and port; the connection
+ might be between two different ports on the same machine.) */
+ for( j=0; j<2; j++ ) {
+ if (memcmp(src_addr[j], srcx, len) == 0 && src_port[j] == srcport ) {
+ src_index = j;
+ }
+ }
+ /* we didn't find it if src_index == -1 */
+ if( src_index < 0 ) {
+ /* assign it to a src_index and get going */
+ for( j=0; j<2; j++ ) {
+ if( src_port[j] == 0 ) {
+ memcpy(src_addr[j], srcx, len);
+ src_port[j] = srcport;
+ src_index = j;
+ first = 1;
+ break;
+ }
+ }
+ }
+ if( src_index < 0 ) {
+ fprintf( stderr, "ERROR in reassemble_tcp: Too many addresses!\n");
+ return;
+ }
+
+ if( data_length < length ) {
+ incomplete_tcp_stream = TRUE;
+ }
+
+ /* now that we have filed away the srcs, lets get the sequence number stuff
+ figured out */
+ if( first ) {
+ /* this is the first time we have seen this src's sequence number */
+ seq[src_index] = sequence + length;
+ if( synflag ) {
+ seq[src_index]++;
+ }
+ /* write out the packet data */
+ write_packet_data( src_index, &sc, data );
+ return;
+ }
+ /* if we are here, we have already seen this src, let's
+ try and figure out if this packet is in the right place */
+ if( sequence < seq[src_index] ) {
+ /* this sequence number seems dated, but
+ check the end to make sure it has no more
+ info than we have already seen */
+ newseq = sequence + length;
+ if( newseq > seq[src_index] ) {
+ gulong new_len;
+
+ /* this one has more than we have seen. let's get the
+ payload that we have not seen. */
+
+ new_len = seq[src_index] - sequence;
+
+ if ( data_length <= new_len ) {
+ data = NULL;
+ data_length = 0;
+ incomplete_tcp_stream = TRUE;
+ } else {
+ data += new_len;
+ data_length -= new_len;
+ }
+ sc.dlen = data_length;
+ sequence = seq[src_index];
+ length = newseq - seq[src_index];
+
+ /* this will now appear to be right on time :) */
+ }
+ }
+ if ( sequence == seq[src_index] ) {
+ /* right on time */
+ seq[src_index] += length;
+ if( synflag ) seq[src_index]++;
+ if( data ) {
+ write_packet_data( src_index, &sc, data );
+ }
+ /* done with the packet, see if it caused a fragment to fit */
+ while( check_fragments( src_index, &sc ) )
+ ;
+ }
+ else {
+ /* out of order packet */
+ if(data_length > 0 && sequence > seq[src_index] ) {
+ tmp_frag = (tcp_frag *)malloc( sizeof( tcp_frag ) );
+ tmp_frag->data = (guchar *)malloc( data_length );
+ tmp_frag->seq = sequence;
+ tmp_frag->len = length;
+ tmp_frag->data_len = data_length;
+ memcpy( tmp_frag->data, data, data_length );
+ if( frags[src_index] ) {
+ tmp_frag->next = frags[src_index];
+ } else {
+ tmp_frag->next = NULL;
+ }
+ frags[src_index] = tmp_frag;
+ }
+ }
+} /* end reassemble_tcp */
+
+/* here we search through all the frag we have collected to see if
+ one fits */
+static int
+check_fragments( int index, tcp_stream_chunk *sc ) {
+ tcp_frag *prev = NULL;
+ tcp_frag *current;
+ current = frags[index];
+ while( current ) {
+ if( current->seq == seq[index] ) {
+ /* this fragment fits the stream */
+ if( current->data ) {
+ sc->dlen = current->data_len;
+ write_packet_data( index, sc, current->data );
+ }
+ seq[index] += current->len;
+ if( prev ) {
+ prev->next = current->next;
+ } else {
+ frags[index] = current->next;
+ }
+ free( current->data );
+ free( current );
+ return 1;
+ }
+ prev = current;
+ current = current->next;
+ }
+ return 0;
+}
+
+/* this should always be called before we start to reassemble a stream */
+void
+reset_tcp_reassembly() {
+ tcp_frag *current, *next;
+ int i;
+ incomplete_tcp_stream = FALSE;
+ for( i=0; i<2; i++ ) {
+ seq[i] = 0;
+ memset(src_addr[i], '\0', MAX_IPADDR_LEN);
+ src_port[i] = 0;
+ memset(ip_address[i], '\0', MAX_IPADDR_LEN);
+ tcp_port[i] = 0;
+ bytes_written[i] = 0;
+ current = frags[i];
+ while( current ) {
+ next = current->next;
+ free( current->data );
+ free( current );
+ current = next;
+ }
+ frags[i] = NULL;
+ }
+}
+
+static void
+write_packet_data( int index, tcp_stream_chunk *sc, const char *data )
+{
+ fwrite( sc, 1, sizeof(tcp_stream_chunk), data_out_file );
+ fwrite( data, 1, sc->dlen, data_out_file );
+ bytes_written[index] += sc->dlen;
+}
diff --git a/epan/follow.h b/epan/follow.h
new file mode 100644
index 0000000000..013519d43e
--- /dev/null
+++ b/epan/follow.h
@@ -0,0 +1,57 @@
+/* follow.h
+ *
+ * $Id$
+ *
+ * Copyright 1998 Mike Hall <mlh@io.com>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 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.
+ *
+ */
+
+#ifndef __FOLLOW_H__
+#define __FOLLOW_H__
+
+#include <epan/packet.h>
+
+#define MAX_IPADDR_LEN 16
+
+/* With MSVC and a libethereal.dll, we need a special declaration. */
+ETH_VAR_IMPORT gboolean incomplete_tcp_stream;
+
+typedef struct _tcp_stream_chunk {
+ guint8 src_addr[MAX_IPADDR_LEN];
+ guint16 src_port;
+ guint32 dlen;
+} tcp_stream_chunk;
+
+char* build_follow_filter( packet_info * );
+void reassemble_tcp( gulong, gulong, const char*, gulong, int,
+ address *, address *, guint, guint );
+void reset_tcp_reassembly( void );
+
+typedef struct {
+ guint8 ip_address[2][MAX_IPADDR_LEN];
+ guint32 tcp_port[2];
+ unsigned int bytes_written[2];
+ gboolean is_ipv6;
+} follow_tcp_stats_t;
+
+void follow_tcp_stats(follow_tcp_stats_t* stats);
+
+#endif
diff --git a/epan/packet.c b/epan/packet.c
index 671eacbef7..b7528983c1 100644
--- a/epan/packet.c
+++ b/epan/packet.c
@@ -53,7 +53,7 @@
#include "plugins.h"
#include "epan_dissect.h"
-#include "../reassemble.h"
+#include <epan/reassemble.h>
static gint proto_malformed = -1;
static dissector_handle_t frame_handle = NULL;
diff --git a/epan/plugins.c b/epan/plugins.c
index 72a41e8853..b880fe7963 100644
--- a/epan/plugins.c
+++ b/epan/plugins.c
@@ -60,14 +60,14 @@
#ifdef PLUGINS_NEED_ADDRESS_TABLE
#include "conversation.h"
-#include "reassemble.h"
+#include <epan/reassemble.h>
#include <epan/prefs.h>
#include <epan/dissectors/packet-giop.h>
#include <epan/dissectors/packet-tpkt.h>
#include <epan/dissectors/packet-tcp.h>
#include <epan/dissectors/packet-rpc.h>
#include <epan/tap.h>
-#include "asn1.h"
+#include <epan/asn1.h>
#include <epan/dissectors/packet-per.h>
#include <epan/dissectors/packet-ber.h>
#include <epan/dissectors/packet-rtp.h>
diff --git a/epan/ptvcursor.c b/epan/ptvcursor.c
new file mode 100644
index 0000000000..cde56022f0
--- /dev/null
+++ b/epan/ptvcursor.c
@@ -0,0 +1,116 @@
+/* ptvcursor.c
+ *
+ * Proto Tree TVBuff cursor
+ * Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@zing.org>
+ * Copyright 2000 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.
+ */
+
+#include "ptvcursor.h"
+
+
+struct ptvcursor {
+ proto_tree *tree;
+ tvbuff_t *tvb;
+ gint offset;
+};
+
+
+/* Allocates an initializes a ptvcursor_t with 3 variables:
+ * proto_tree, tvbuff, and offset. */
+ptvcursor_t*
+ptvcursor_new(proto_tree *tree, tvbuff_t *tvb, gint offset)
+{
+ ptvcursor_t *ptvc;
+
+ ptvc = g_new(ptvcursor_t, 1);
+ ptvc->tree = tree;
+ ptvc->tvb = tvb;
+ ptvc->offset = offset;
+ return ptvc;
+}
+
+
+/* Gets data from tvbuff, adds it to proto_tree, increments offset,
+ * and returns proto_item* */
+proto_item*
+ptvcursor_add(ptvcursor_t *ptvc, int hf, gint length, gboolean endianness)
+{
+ proto_item *item;
+
+ item = ptvcursor_add_no_advance(ptvc, hf, length, endianness);
+ ptvc->offset += proto_item_get_len(item);
+ return item;
+}
+
+/* Gets data from tvbuff, adds it to proto_tree, *DOES NOT* increment
+ * offset, and returns proto_item* */
+proto_item*
+ptvcursor_add_no_advance(ptvcursor_t* ptvc, int hf, gint length,
+ gboolean endianness)
+{
+ proto_item *item;
+
+ item = proto_tree_add_item(ptvc->tree, hf, ptvc->tvb, ptvc->offset,
+ length, endianness);
+
+ return item;
+}
+
+/* Advance the ptvcursor's offset within its tvbuff without
+ * adding anything to the proto_tree. */
+void
+ptvcursor_advance(ptvcursor_t* ptvc, gint length)
+{
+ ptvc->offset += length;
+}
+
+/* Frees memory for ptvcursor_t, but nothing deeper than that. */
+void
+ptvcursor_free(ptvcursor_t *ptvc)
+{
+ g_free(ptvc);
+}
+/* Returns tvbuff. */
+tvbuff_t*
+ptvcursor_tvbuff(ptvcursor_t* ptvc)
+{
+ return ptvc->tvb;
+}
+
+/* Returns current offset. */
+gint
+ptvcursor_current_offset(ptvcursor_t* ptvc)
+{
+ return ptvc->offset;
+}
+
+proto_tree*
+ptvcursor_tree(ptvcursor_t* ptvc)
+{
+ return ptvc->tree;
+}
+
+void
+ptvcursor_set_tree(ptvcursor_t* ptvc, proto_tree *tree)
+{
+ ptvc->tree = tree;
+}
diff --git a/epan/ptvcursor.h b/epan/ptvcursor.h
new file mode 100644
index 0000000000..6467bcdea9
--- /dev/null
+++ b/epan/ptvcursor.h
@@ -0,0 +1,80 @@
+/* ptvcursor.h
+ *
+ * Proto Tree TVBuff cursor
+ * Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 2000 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.
+ */
+
+#ifndef __PTVCURSOR_H__
+#define __PTVCURSOR_H__
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <epan/packet.h>
+
+typedef struct ptvcursor ptvcursor_t;
+
+/* Allocates an initializes a ptvcursor_t with 3 variables:
+ * proto_tree, tvbuff, and offset. */
+ptvcursor_t*
+ptvcursor_new(proto_tree*, tvbuff_t*, gint);
+
+/* Gets data from tvbuff, adds it to proto_tree, increments offset,
+ * and returns proto_item* */
+proto_item*
+ptvcursor_add(ptvcursor_t*, int hf, gint length, gboolean endianness);
+
+
+/* Gets data from tvbuff, adds it to proto_tree, *DOES NOT* increment
+ * offset, and returns proto_item* */
+proto_item*
+ptvcursor_add_no_advance(ptvcursor_t*, int hf, gint length, gboolean endianness);
+
+/* Advance the ptvcursor's offset within its tvbuff without
+ * adding anything to the proto_tree. */
+void
+ptvcursor_advance(ptvcursor_t* ptvc, gint length);
+
+/* Frees memory for ptvcursor_t, but nothing deeper than that. */
+void
+ptvcursor_free(ptvcursor_t*);
+
+/* Returns tvbuff. */
+tvbuff_t*
+ptvcursor_tvbuff(ptvcursor_t*);
+
+/* Returns current offset. */
+gint
+ptvcursor_current_offset(ptvcursor_t*);
+
+/* Returns the proto_tree* */
+proto_tree*
+ptvcursor_tree(ptvcursor_t* ptvc);
+
+/* Sets a new proto_tree* for the ptvcursor_t */
+void
+ptvcursor_set_tree(ptvcursor_t* ptvc, proto_tree *tree);
+
+#endif /* __PTVCURSOR_H__ */
diff --git a/epan/reassemble.c b/epan/reassemble.c
new file mode 100644
index 0000000000..9622d390e2
--- /dev/null
+++ b/epan/reassemble.c
@@ -0,0 +1,1833 @@
+/* reassemble.c
+ * Routines for {fragment,segment} reassembly
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <epan/packet.h>
+
+#include <epan/reassemble.h>
+
+#include <epan/dissectors/packet-dcerpc.h>
+
+typedef struct _fragment_key {
+ address src;
+ address dst;
+ guint32 id;
+} fragment_key;
+
+typedef struct _dcerpc_fragment_key {
+ address src;
+ address dst;
+ guint32 id;
+ e_uuid_t act_id;
+} dcerpc_fragment_key;
+
+static GMemChunk *fragment_key_chunk = NULL;
+static GMemChunk *dcerpc_fragment_key_chunk = NULL;
+static GMemChunk *fragment_data_chunk = NULL;
+static int fragment_init_count = 200;
+
+#define LINK_FRAG(fd_head,fd) \
+ { fragment_data *fd_i; \
+ /* add fragment to list, keep list sorted */ \
+ for(fd_i=(fd_head);fd_i->next;fd_i=fd_i->next){ \
+ if( ((fd)->offset) < (fd_i->next->offset) ) \
+ break; \
+ } \
+ (fd)->next=fd_i->next; \
+ fd_i->next=(fd); \
+ }
+
+static gint
+fragment_equal(gconstpointer k1, gconstpointer k2)
+{
+ const fragment_key* key1 = (const fragment_key*) k1;
+ const fragment_key* key2 = (const fragment_key*) k2;
+
+ /*key.id is the first item to compare since item is most
+ likely to differ between sessions, thus shortcircuiting
+ the comparasion of addresses.
+ */
+ return ( ( (key1->id == key2->id) &&
+ (ADDRESSES_EQUAL(&key1->src, &key2->src)) &&
+ (ADDRESSES_EQUAL(&key1->dst, &key2->dst))
+ ) ?
+ TRUE : FALSE);
+}
+
+static guint
+fragment_hash(gconstpointer k)
+{
+ const fragment_key* key = (const fragment_key*) k;
+ guint hash_val;
+/*
+ int i;
+*/
+
+ hash_val = 0;
+
+/* More than likely: in most captures src and dst addresses are the
+ same, and would hash the same.
+ We only use id as the hash as an optimization.
+
+ for (i = 0; i < key->src.len; i++)
+ hash_val += key->src.data[i];
+ for (i = 0; i < key->dst.len; i++)
+ hash_val += key->dst.data[i];
+*/
+
+ hash_val += key->id;
+
+ return hash_val;
+}
+
+static gint
+dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
+{
+ const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
+ const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
+
+ /*key.id is the first item to compare since item is most
+ likely to differ between sessions, thus shortcircuiting
+ the comparasion of addresses.
+ */
+ return (((key1->id == key2->id)
+ && (ADDRESSES_EQUAL(&key1->src, &key2->src))
+ && (ADDRESSES_EQUAL(&key1->dst, &key2->dst))
+ && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0))
+ ? TRUE : FALSE);
+}
+
+static guint
+dcerpc_fragment_hash(gconstpointer k)
+{
+ const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
+ guint hash_val;
+
+ hash_val = 0;
+
+ hash_val += key->id;
+ hash_val += key->act_id.Data1;
+ hash_val += key->act_id.Data2 << 16;
+ hash_val += key->act_id.Data3;
+
+ return hash_val;
+}
+
+typedef struct _reassembled_key {
+ guint32 id;
+ guint32 frame;
+} reassembled_key;
+
+static GMemChunk *reassembled_key_chunk = NULL;
+
+static gint
+reassembled_equal(gconstpointer k1, gconstpointer k2)
+{
+ const reassembled_key* key1 = (const reassembled_key*) k1;
+ const reassembled_key* key2 = (const reassembled_key*) k2;
+
+ /*
+ * We assume that the frame numbers are unlikely to be equal,
+ * so we check them first.
+ */
+ return key1->frame == key2->frame && key1->id == key2->id;
+}
+
+static guint
+reassembled_hash(gconstpointer k)
+{
+ const reassembled_key* key = (const reassembled_key*) k;
+
+ return key->frame;
+}
+
+/*
+ * For a fragment hash table entry, free the address data to which the key
+ * refers and the fragment data to which the value refers.
+ * (The actual key and value structures get freed by "reassemble_init()".)
+ */
+static gboolean
+free_all_fragments(gpointer key_arg, gpointer value, gpointer user_data _U_)
+{
+ fragment_key *key = key_arg;
+ fragment_data *fd_head;
+
+ /*
+ * Grr. I guess the theory here is that freeing
+ * something sure as heck modifies it, so you
+ * want to ban attempts to free it, but, alas,
+ * if we make the "data" field of an "address"
+ * structure not a "const", the compiler whines if
+ * we try to make it point into the data for a packet,
+ * as that's a "const" array (and should be, as dissectors
+ * shouldn't trash it).
+ *
+ * So we cast the complaint into oblivion, and rely on
+ * the fact that these addresses are known to have had
+ * their data mallocated, i.e. they don't point into,
+ * say, the middle of the data for a packet.
+ */
+ g_free((gpointer)key->src.data);
+ g_free((gpointer)key->dst.data);
+
+ for (fd_head = value; fd_head != NULL; fd_head = fd_head->next) {
+ if(fd_head->data && !(fd_head->flags&FD_NOT_MALLOCED))
+ g_free(fd_head->data);
+ }
+
+ return TRUE;
+}
+
+/*
+ * For a reassembled-packet hash table entry, free the fragment data
+ * to which the value refers.
+ * (The actual value structures get freed by "reassemble_init()".)
+ */
+static gboolean
+free_all_reassembled_fragments(gpointer key_arg _U_, gpointer value,
+ gpointer user_data _U_)
+{
+ fragment_data *fd_head;
+
+ for (fd_head = value; fd_head != NULL; fd_head = fd_head->next) {
+ if(fd_head->data && !(fd_head->flags&FD_NOT_MALLOCED)) {
+ g_free(fd_head->data);
+
+ /*
+ * A reassembled packet is inserted into the
+ * hash table once for every frame that made
+ * up the reassembled packet; clear the data
+ * pointer so that we only free the data the
+ * first time we see it.
+ */
+ fd_head->data = NULL;
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Initialize a fragment table.
+ */
+void
+fragment_table_init(GHashTable **fragment_table)
+{
+ if (*fragment_table != NULL) {
+ /*
+ * The fragment hash table exists.
+ *
+ * Remove all entries and free fragment data for
+ * each entry. (The key and value data is freed
+ * by "reassemble_init()".)
+ */
+ g_hash_table_foreach_remove(*fragment_table,
+ free_all_fragments, NULL);
+ } else {
+ /* The fragment table does not exist. Create it */
+ *fragment_table = g_hash_table_new(fragment_hash,
+ fragment_equal);
+ }
+}
+
+void
+dcerpc_fragment_table_init(GHashTable **fragment_table)
+{
+ if (*fragment_table != NULL) {
+ /*
+ * The fragment hash table exists.
+ *
+ * Remove all entries and free fragment data for
+ * each entry. (The key and value data is freed
+ * by "reassemble_init()".)
+ */
+ g_hash_table_foreach_remove(*fragment_table,
+ free_all_fragments, NULL);
+ } else {
+ /* The fragment table does not exist. Create it */
+ *fragment_table = g_hash_table_new(dcerpc_fragment_hash,
+ dcerpc_fragment_equal);
+ }
+}
+
+/*
+ * Initialize a reassembled-packet table.
+ */
+void
+reassembled_table_init(GHashTable **reassembled_table)
+{
+ if (*reassembled_table != NULL) {
+ /*
+ * The reassembled-packet hash table exists.
+ *
+ * Remove all entries and free reassembled packet
+ * data for each entry. (The key data is freed
+ * by "reassemble_init()".)
+ */
+ g_hash_table_foreach_remove(*reassembled_table,
+ free_all_reassembled_fragments, NULL);
+ } else {
+ /* The fragment table does not exist. Create it */
+ *reassembled_table = g_hash_table_new(reassembled_hash,
+ reassembled_equal);
+ }
+}
+
+/*
+ * Free up all space allocated for fragment keys and data and
+ * reassembled keys.
+ */
+void
+reassemble_init(void)
+{
+ if (fragment_key_chunk != NULL)
+ g_mem_chunk_destroy(fragment_key_chunk);
+ if (dcerpc_fragment_key_chunk != NULL)
+ g_mem_chunk_destroy(dcerpc_fragment_key_chunk);
+ if (fragment_data_chunk != NULL)
+ g_mem_chunk_destroy(fragment_data_chunk);
+ if (reassembled_key_chunk != NULL)
+ g_mem_chunk_destroy(reassembled_key_chunk);
+ fragment_key_chunk = g_mem_chunk_new("fragment_key_chunk",
+ sizeof(fragment_key),
+ fragment_init_count * sizeof(fragment_key),
+ G_ALLOC_AND_FREE);
+ dcerpc_fragment_key_chunk = g_mem_chunk_new("dcerpc_fragment_key_chunk",
+ sizeof(dcerpc_fragment_key),
+ fragment_init_count * sizeof(dcerpc_fragment_key),
+ G_ALLOC_AND_FREE);
+ fragment_data_chunk = g_mem_chunk_new("fragment_data_chunk",
+ sizeof(fragment_data),
+ fragment_init_count * sizeof(fragment_data),
+ G_ALLOC_ONLY);
+ reassembled_key_chunk = g_mem_chunk_new("reassembled_key_chunk",
+ sizeof(reassembled_key),
+ fragment_init_count * sizeof(reassembled_key),
+ G_ALLOC_AND_FREE);
+}
+
+/* This function cleans up the stored state and removes the reassembly data and
+ * (with one exception) all allocated memory for matching reassembly.
+ *
+ * The exception is :
+ * If the PDU was already completely reassembled, then the buffer containing the
+ * reassembled data WILL NOT be free()d, and the pointer to that buffer will be
+ * returned.
+ * Othervise the function will return NULL.
+ *
+ * So, if you call fragment_delete and it returns non-NULL, YOU are responsible to
+ * g_free() that buffer.
+ */
+unsigned char *
+fragment_delete(packet_info *pinfo, guint32 id, GHashTable *fragment_table)
+{
+ fragment_data *fd_head, *fd;
+ fragment_key key;
+ unsigned char *data=NULL;
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ fd_head = g_hash_table_lookup(fragment_table, &key);
+
+ if(fd_head==NULL){
+ /* We do not recognize this as a PDU we have seen before. return*/
+ return NULL;
+ }
+
+ data=fd_head->data;
+ /* loop over all partial fragments and free any buffers */
+ for(fd=fd_head->next;fd;){
+ fragment_data *tmp_fd;
+ tmp_fd=fd->next;
+
+ if( !(fd->flags&FD_NOT_MALLOCED) )
+ g_free(fd->data);
+ g_mem_chunk_free(fragment_data_chunk, fd);
+ fd=tmp_fd;
+ }
+ g_mem_chunk_free(fragment_data_chunk, fd_head);
+ g_hash_table_remove(fragment_table, &key);
+
+ return data;
+}
+
+/* This function is used to check if there is partial or completed reassembly state
+ * matching this packet. I.e. Are there reassembly going on or not for this packet?
+ */
+fragment_data *
+fragment_get(packet_info *pinfo, guint32 id, GHashTable *fragment_table)
+{
+ fragment_data *fd_head;
+ fragment_key key;
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ fd_head = g_hash_table_lookup(fragment_table, &key);
+
+ return fd_head;
+}
+
+/* This function can be used to explicitely set the total length (if known)
+ * for reassembly of a PDU.
+ * This is useful for reassembly of PDUs where one may have the total length specified
+ * in the first fragment instead of as for, say, IPv4 where a flag indicates which
+ * is the last fragment.
+ *
+ * Such protocols might fragment_add with a more_frags==TRUE for every fragment
+ * and just tell the reassembly engine the expected total length of the reassembled data
+ * using fragment_set_tot_len immediately after doing fragment_add for the first packet.
+ *
+ * note that for FD_BLOCKSEQUENCE tot_len is the index for the tail fragment.
+ * i.e. since the block numbers start at 0, if we specify tot_len==2, that
+ * actually means we want to defragment 3 blocks, block 0, 1 and 2.
+ */
+void
+fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table,
+ guint32 tot_len)
+{
+ fragment_data *fd_head;
+ fragment_key key;
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ fd_head = g_hash_table_lookup(fragment_table, &key);
+
+ if(fd_head){
+ fd_head->datalen = tot_len;
+ }
+
+ return;
+}
+
+guint32
+fragment_get_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table)
+{
+ fragment_data *fd_head;
+ fragment_key key;
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ fd_head = g_hash_table_lookup(fragment_table, &key);
+
+ if(fd_head){
+ return fd_head->datalen;
+ }
+
+ return 0;
+}
+
+
+/* This function will set the partial reassembly flag for a fh.
+ When this function is called, the fh MUST already exist, i.e.
+ the fh MUST be created by the initial call to fragment_add() before
+ this function is called.
+ Also note that this function MUST be called to indicate a fh will be
+ extended (increase the already stored data)
+*/
+
+void
+fragment_set_partial_reassembly(packet_info *pinfo, guint32 id, GHashTable *fragment_table)
+{
+ fragment_data *fd_head;
+ fragment_key key;
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ fd_head = g_hash_table_lookup(fragment_table, &key);
+
+ if(fd_head){
+ fd_head->flags |= FD_PARTIAL_REASSEMBLY;
+ }
+}
+
+/*
+ * This function gets rid of an entry from a fragment table, given
+ * a pointer to the key for that entry; it also frees up the key
+ * and the addresses in it.
+ */
+static void
+fragment_unhash(GHashTable *fragment_table, fragment_key *key)
+{
+ /*
+ * Free up the copies of the addresses from the old key.
+ */
+ g_free((gpointer)key->src.data);
+ g_free((gpointer)key->dst.data);
+
+ /*
+ * Remove the entry from the fragment table.
+ */
+ g_hash_table_remove(fragment_table, key);
+
+ /*
+ * Free the key itself.
+ */
+ g_mem_chunk_free(fragment_key_chunk, key);
+}
+
+/*
+ * This function adds fragment_data structure to a reassembled-packet
+ * hash table, using the frame numbers of each of the frames from
+ * which it was reassembled as keys, and sets the "reassembled_in"
+ * frame number.
+ */
+static void
+fragment_reassembled(fragment_data *fd_head, packet_info *pinfo,
+ GHashTable *reassembled_table, guint32 id)
+{
+ reassembled_key *new_key;
+ fragment_data *fd;
+
+ if (fd_head->next == NULL) {
+ /*
+ * This was not fragmented, so there's no fragment
+ * table; just hash it using the current frame number.
+ */
+ new_key = g_mem_chunk_alloc(reassembled_key_chunk);
+ new_key->frame = pinfo->fd->num;
+ new_key->id = id;
+ g_hash_table_insert(reassembled_table, new_key, fd_head);
+ } else {
+ /*
+ * Hash it with the frame numbers for all the frames.
+ */
+ for (fd = fd_head->next; fd != NULL; fd = fd->next){
+ new_key = g_mem_chunk_alloc(reassembled_key_chunk);
+ new_key->frame = fd->frame;
+ new_key->id = id;
+ g_hash_table_insert(reassembled_table, new_key,
+ fd_head);
+ }
+ }
+ fd_head->flags |= FD_DEFRAGMENTED;
+ fd_head->reassembled_in = pinfo->fd->num;
+}
+
+/*
+ * This function adds a new fragment to the fragment hash table.
+ * If this is the first fragment seen for this datagram, a new entry
+ * is created in the hash table, otherwise this fragment is just added
+ * to the linked list of fragments for this packet.
+ * The list of fragments for a specific datagram is kept sorted for
+ * easier handling.
+ *
+ * Returns a pointer to the head of the fragment data list if we have all the
+ * fragments, NULL otherwise.
+ *
+ * This function assumes frag_offset being a byte offset into the defragment
+ * packet.
+ *
+ * 01-2002
+ * Once the fh is defragmented (= FD_DEFRAGMENTED set), it can be
+ * extended using the FD_PARTIAL_REASSEMBLY flag. This flag should be set
+ * using fragment_set_partial_reassembly() before calling fragment_add
+ * with the new fragment. FD_TOOLONGFRAGMENT and FD_MULTIPLETAILS flags
+ * are lowered when a new extension process is started.
+ */
+static gboolean
+fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
+ packet_info *pinfo, guint32 frag_offset,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ fragment_data *fd;
+ fragment_data *fd_i;
+ guint32 max, dfpos;
+ unsigned char *old_data;
+
+ /* create new fd describing this fragment */
+ fd = g_mem_chunk_alloc(fragment_data_chunk);
+ fd->next = NULL;
+ fd->flags = 0;
+ fd->frame = pinfo->fd->num;
+ fd->offset = frag_offset;
+ fd->len = frag_data_len;
+ fd->data = NULL;
+
+ /*
+ * If it was already defragmented and this new fragment goes beyond
+ * data limits, set flag in already empty fds & point old fds to malloc'ed data.
+ */
+ if(fd_head->flags & FD_DEFRAGMENTED && (frag_offset+frag_data_len) >= fd_head->datalen &&
+ fd_head->flags & FD_PARTIAL_REASSEMBLY){
+ for(fd_i=fd_head->next; fd_i; fd_i=fd_i->next){
+ if( !fd_i->data ) {
+ fd_i->data = fd_head->data + fd_i->offset;
+ fd_i->flags |= FD_NOT_MALLOCED;
+ }
+ fd_i->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS);
+ }
+ fd_head->flags ^= FD_DEFRAGMENTED|FD_PARTIAL_REASSEMBLY;
+ fd_head->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS);
+ fd_head->datalen=0;
+ }
+
+ if (!more_frags) {
+ /*
+ * This is the tail fragment in the sequence.
+ */
+ if (fd_head->datalen) {
+ /* ok we have already seen other tails for this packet
+ * it might be a duplicate.
+ */
+ if (fd_head->datalen != (fd->offset + fd->len) ){
+ /* Oops, this tail indicates a different packet
+ * len than the previous ones. Somethings wrong
+ */
+ fd->flags |= FD_MULTIPLETAILS;
+ fd_head->flags |= FD_MULTIPLETAILS;
+ }
+ } else {
+ /* this was the first tail fragment, now we know the
+ * length of the packet
+ */
+ fd_head->datalen = fd->offset + fd->len;
+ }
+ }
+
+
+
+
+ /* If the packet is already defragmented, this MUST be an overlap.
+ * The entire defragmented packet is in fd_head->data
+ * Even if we have previously defragmented this packet, we still check
+ * check it. Someone might play overlap and TTL games.
+ */
+ if (fd_head->flags & FD_DEFRAGMENTED) {
+ fd->flags |= FD_OVERLAP;
+ fd_head->flags |= FD_OVERLAP;
+ /* make sure its not too long */
+ if (fd->offset + fd->len > fd_head->datalen) {
+ fd->flags |= FD_TOOLONGFRAGMENT;
+ fd_head->flags |= FD_TOOLONGFRAGMENT;
+ LINK_FRAG(fd_head,fd);
+ return TRUE;
+ }
+ /* make sure it doesnt conflict with previous data */
+ if ( memcmp(fd_head->data+fd->offset,
+ tvb_get_ptr(tvb,offset,fd->len),fd->len) ){
+ fd->flags |= FD_OVERLAPCONFLICT;
+ fd_head->flags |= FD_OVERLAPCONFLICT;
+ LINK_FRAG(fd_head,fd);
+ return TRUE;
+ }
+ /* it was just an overlap, link it and return */
+ LINK_FRAG(fd_head,fd);
+ return TRUE;
+ }
+
+
+
+ /* If we have reached this point, the packet is not defragmented yet.
+ * Save all payload in a buffer until we can defragment.
+ * XXX - what if we didn't capture the entire fragment due
+ * to a too-short snapshot length?
+ */
+ fd->data = g_malloc(fd->len);
+ tvb_memcpy(tvb, fd->data, offset, fd->len);
+ LINK_FRAG(fd_head,fd);
+
+
+ if( !(fd_head->datalen) ){
+ /* if we dont know the datalen, there are still missing
+ * packets. Cheaper than the check below.
+ */
+ return FALSE;
+ }
+
+
+ /* check if we have received the entire fragment
+ * this is easy since the list is sorted and the head is faked.
+ */
+ max = 0;
+ for (fd_i=fd_head->next;fd_i;fd_i=fd_i->next) {
+ if ( ((fd_i->offset)<=max) &&
+ ((fd_i->offset+fd_i->len)>max) ){
+ max = fd_i->offset+fd_i->len;
+ }
+ }
+
+ if (max < (fd_head->datalen)) {
+ /* we have not received all packets yet */
+ return FALSE;
+ }
+
+
+ if (max > (fd_head->datalen)) {
+ /*XXX not sure if current fd was the TOOLONG*/
+ /*XXX is it fair to flag current fd*/
+ /* oops, too long fragment detected */
+ fd->flags |= FD_TOOLONGFRAGMENT;
+ fd_head->flags |= FD_TOOLONGFRAGMENT;
+ }
+
+
+ /* we have received an entire packet, defragment it and
+ * free all fragments
+ */
+ /* store old data just in case */
+ old_data=fd_head->data;
+ fd_head->data = g_malloc(max);
+
+ /* add all data fragments */
+ for (dfpos=0,fd_i=fd_head;fd_i;fd_i=fd_i->next) {
+ if (fd_i->len) {
+ if (fd_i->offset < dfpos) {
+ fd_i->flags |= FD_OVERLAP;
+ fd_head->flags |= FD_OVERLAP;
+ if ( memcmp(fd_head->data+fd_i->offset,
+ fd_i->data,
+ MIN(fd_i->len,(dfpos-fd_i->offset))
+ ) ){
+ fd_i->flags |= FD_OVERLAPCONFLICT;
+ fd_head->flags |= FD_OVERLAPCONFLICT;
+ }
+ }
+ /* dfpos is always >= than fd_i->offset */
+ /* No gaps can exist here, max_loop(above) does this */
+ if( fd_i->offset+fd_i->len > dfpos )
+ memcpy(fd_head->data+dfpos, fd_i->data+(dfpos-fd_i->offset),
+ fd_i->len-(dfpos-fd_i->offset));
+ if( fd_i->flags & FD_NOT_MALLOCED )
+ fd_i->flags ^= FD_NOT_MALLOCED;
+ else
+ g_free(fd_i->data);
+ fd_i->data=NULL;
+
+ dfpos=MAX(dfpos,(fd_i->offset+fd_i->len));
+ }
+ }
+
+ if( old_data )
+ g_free(old_data);
+ /* mark this packet as defragmented.
+ allows us to skip any trailing fragments */
+ fd_head->flags |= FD_DEFRAGMENTED;
+ fd_head->reassembled_in=pinfo->fd->num;
+
+ return TRUE;
+}
+
+fragment_data *
+fragment_add_common(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
+ GHashTable *fragment_table, guint32 frag_offset,
+ guint32 frag_data_len, gboolean more_frags,
+ gboolean check_already_added)
+{
+ fragment_key key, *new_key;
+ fragment_data *fd_head;
+ fragment_data *fd_item;
+ gboolean already_added=pinfo->fd->flags.visited;
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ fd_head = g_hash_table_lookup(fragment_table, &key);
+
+ /*
+ * "already_added" is true if "pinfo->fd->flags.visited" is true;
+ * if "pinfo->fd->flags.visited", this isn't the first pass, so
+ * we've already done all the reassembly and added all the
+ * fragments.
+ *
+ * If it's not true, but "check_already_added" is true, just check
+ * if we have seen this fragment before, i.e., if we have already
+ * added it to reassembly.
+ * That can be true even if "pinfo->fd->flags.visited" is false
+ * since we sometimes might call a subdissector multiple times.
+ * As an additional check, just make sure we have not already added
+ * this frame to the reassembly list, if there is a reassembly list;
+ * note that the first item in the reassembly list is not a
+ * fragment, it's a data structure for the reassembled packet.
+ * We don't check it because its "frame" member isn't initialized
+ * to anything, and because it doesn't count in any case.
+ */
+ if (!already_added && check_already_added && fd_head != NULL) {
+ for(fd_item=fd_head->next;fd_item;fd_item=fd_item->next){
+ if(pinfo->fd->num==fd_item->frame){
+ already_added=TRUE;
+ }
+ }
+ }
+ /* have we already added this frame ?*/
+ if (already_added) {
+ if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) {
+ return fd_head;
+ } else {
+ return NULL;
+ }
+ }
+
+ if (fd_head==NULL){
+ /* not found, this must be the first snooped fragment for this
+ * packet. Create list-head.
+ */
+ fd_head=g_mem_chunk_alloc(fragment_data_chunk);
+
+ /* head/first structure in list only holds no other data than
+ * 'datalen' then we don't have to change the head of the list
+ * even if we want to keep it sorted
+ */
+ fd_head->next=NULL;
+ fd_head->datalen=0;
+ fd_head->offset=0;
+ fd_head->len=0;
+ fd_head->flags=0;
+ fd_head->data=NULL;
+ fd_head->reassembled_in=0;
+
+ /*
+ * We're going to use the key to insert the fragment,
+ * so allocate a structure for it, and copy the
+ * addresses, allocating new buffers for the address
+ * data.
+ */
+ new_key = g_mem_chunk_alloc(fragment_key_chunk);
+ COPY_ADDRESS(&new_key->src, &key.src);
+ COPY_ADDRESS(&new_key->dst, &key.dst);
+ new_key->id = key.id;
+ g_hash_table_insert(fragment_table, new_key, fd_head);
+ }
+
+ if (fragment_add_work(fd_head, tvb, offset, pinfo, frag_offset,
+ frag_data_len, more_frags)) {
+ /*
+ * Reassembly is complete.
+ */
+ return fd_head;
+ } else {
+ /*
+ * Reassembly isn't complete.
+ */
+ return NULL;
+ }
+}
+
+fragment_data *
+fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
+ GHashTable *fragment_table, guint32 frag_offset,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ return fragment_add_common(tvb, offset, pinfo, id, fragment_table,
+ frag_offset, frag_data_len, more_frags, TRUE);
+}
+
+/*
+ * For use when you can have multiple fragments in the same frame added
+ * to the same reassembled PDU, e.g. with ONC RPC-over-TCP.
+ */
+fragment_data *
+fragment_add_multiple_ok(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table,
+ guint32 frag_offset, guint32 frag_data_len,
+ gboolean more_frags)
+{
+ return fragment_add_common(tvb, offset, pinfo, id, fragment_table,
+ frag_offset, frag_data_len, more_frags, FALSE);
+}
+
+fragment_data *
+fragment_add_check(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table,
+ GHashTable *reassembled_table, guint32 frag_offset,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ reassembled_key reass_key;
+ fragment_key key, *new_key, *old_key;
+ gpointer orig_key, value;
+ fragment_data *fd_head;
+
+ /*
+ * If this isn't the first pass, look for this frame in the table
+ * of reassembled packets.
+ */
+ if (pinfo->fd->flags.visited) {
+ reass_key.frame = pinfo->fd->num;
+ reass_key.id = id;
+ return g_hash_table_lookup(reassembled_table, &reass_key);
+ }
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ if (!g_hash_table_lookup_extended(fragment_table, &key,
+ &orig_key, &value)) {
+ /* not found, this must be the first snooped fragment for this
+ * packet. Create list-head.
+ */
+ fd_head=g_mem_chunk_alloc(fragment_data_chunk);
+
+ /* head/first structure in list only holds no other data than
+ * 'datalen' then we don't have to change the head of the list
+ * even if we want to keep it sorted
+ */
+ fd_head->next=NULL;
+ fd_head->datalen=0;
+ fd_head->offset=0;
+ fd_head->len=0;
+ fd_head->flags=0;
+ fd_head->data=NULL;
+ fd_head->reassembled_in=0;
+
+ /*
+ * We're going to use the key to insert the fragment,
+ * so allocate a structure for it, and copy the
+ * addresses, allocating new buffers for the address
+ * data.
+ */
+ new_key = g_mem_chunk_alloc(fragment_key_chunk);
+ COPY_ADDRESS(&new_key->src, &key.src);
+ COPY_ADDRESS(&new_key->dst, &key.dst);
+ new_key->id = key.id;
+ g_hash_table_insert(fragment_table, new_key, fd_head);
+
+ orig_key = new_key; /* for unhashing it later */
+ } else {
+ /*
+ * We found it.
+ */
+ fd_head = value;
+ }
+
+ /*
+ * If this is a short frame, then we can't, and don't, do
+ * reassembly on it. We just give up.
+ */
+ if (tvb_reported_length(tvb) > tvb_length(tvb))
+ return NULL;
+
+ if (fragment_add_work(fd_head, tvb, offset, pinfo, frag_offset,
+ frag_data_len, more_frags)) {
+ /*
+ * Reassembly is complete.
+ * Remove this from the table of in-progress
+ * reassemblies, add it to the table of
+ * reassembled packets, and return it.
+ */
+
+ /*
+ * Remove this from the table of in-progress reassemblies,
+ * and free up any memory used for it in that table.
+ */
+ old_key = orig_key;
+ fragment_unhash(fragment_table, old_key);
+
+ /*
+ * Add this item to the table of reassembled packets.
+ */
+ fragment_reassembled(fd_head, pinfo, reassembled_table, id);
+ return fd_head;
+ } else {
+ /*
+ * Reassembly isn't complete.
+ */
+ return NULL;
+ }
+}
+
+/*
+ * This function adds a new fragment to the entry for a reassembly
+ * operation.
+ *
+ * The list of fragments for a specific datagram is kept sorted for
+ * easier handling.
+ *
+ * Returns TRUE if we have all the fragments, FALSE otherwise.
+ *
+ * This function assumes frag_number being a block sequence number.
+ * The bsn for the first block is 0.
+ */
+static gboolean
+fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
+ packet_info *pinfo, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ fragment_data *fd;
+ fragment_data *fd_i;
+ fragment_data *last_fd;
+ guint32 max, dfpos, size;
+
+ /* create new fd describing this fragment */
+ fd = g_mem_chunk_alloc(fragment_data_chunk);
+ fd->next = NULL;
+ fd->flags = 0;
+ fd->frame = pinfo->fd->num;
+ fd->offset = frag_number;
+ fd->len = frag_data_len;
+ fd->data = NULL;
+
+ if (!more_frags) {
+ /*
+ * This is the tail fragment in the sequence.
+ */
+ if (fd_head->datalen) {
+ /* ok we have already seen other tails for this packet
+ * it might be a duplicate.
+ */
+ if (fd_head->datalen != fd->offset ){
+ /* Oops, this tail indicates a different packet
+ * len than the previous ones. Somethings wrong
+ */
+ fd->flags |= FD_MULTIPLETAILS;
+ fd_head->flags |= FD_MULTIPLETAILS;
+ }
+ } else {
+ /* this was the first tail fragment, now we know the
+ * sequence number of that fragment (which is NOT
+ * the length of the packet!)
+ */
+ fd_head->datalen = fd->offset;
+ }
+ }
+
+ /* If the packet is already defragmented, this MUST be an overlap.
+ * The entire defragmented packet is in fd_head->data
+ * Even if we have previously defragmented this packet, we still check
+ * check it. Someone might play overlap and TTL games.
+ */
+ if (fd_head->flags & FD_DEFRAGMENTED) {
+ fd->flags |= FD_OVERLAP;
+ fd_head->flags |= FD_OVERLAP;
+
+ /* make sure it's not past the end */
+ if (fd->offset > fd_head->datalen) {
+ /* new fragment comes after the end */
+ fd->flags |= FD_TOOLONGFRAGMENT;
+ fd_head->flags |= FD_TOOLONGFRAGMENT;
+ LINK_FRAG(fd_head,fd);
+ return TRUE;
+ }
+ /* make sure it doesnt conflict with previous data */
+ dfpos=0;
+ last_fd=NULL;
+ for (fd_i=fd_head->next;fd_i->offset!=fd->offset;fd_i=fd_i->next) {
+ if (!last_fd || last_fd->offset!=fd_i->offset){
+ dfpos += fd_i->len;
+ }
+ last_fd=fd_i;
+ }
+ if(fd_i){
+ /* new fragment overlaps existing fragment */
+ if(fd_i->len!=fd->len){
+ /*
+ * They have different lengths; this
+ * is definitely a conflict.
+ */
+ fd->flags |= FD_OVERLAPCONFLICT;
+ fd_head->flags |= FD_OVERLAPCONFLICT;
+ LINK_FRAG(fd_head,fd);
+ return TRUE;
+ }
+ g_assert(fd_head->len >= dfpos + fd->len);
+ if ( memcmp(fd_head->data+dfpos,
+ tvb_get_ptr(tvb,offset,fd->len),fd->len) ){
+ /*
+ * They have the same length, but the
+ * data isn't the same.
+ */
+ fd->flags |= FD_OVERLAPCONFLICT;
+ fd_head->flags |= FD_OVERLAPCONFLICT;
+ LINK_FRAG(fd_head,fd);
+ return TRUE;
+ }
+ /* it was just an overlap, link it and return */
+ LINK_FRAG(fd_head,fd);
+ return TRUE;
+ } else {
+ /*
+ * New fragment doesn't overlap an existing
+ * fragment - there was presumably a gap in
+ * the sequence number space.
+ *
+ * XXX - what should we do here? Is it always
+ * the case that there are no gaps, or are there
+ * protcols using sequence numbers where there
+ * can be gaps?
+ *
+ * If the former, the check below for having
+ * received all the fragments should check for
+ * holes in the sequence number space and for the
+ * first sequence number being 0. If we do that,
+ * the only way we can get here is if this fragment
+ * is past the end of the sequence number space -
+ * but the check for "fd->offset > fd_head->datalen"
+ * would have caught that above, so it can't happen.
+ *
+ * If the latter, we don't have a good way of
+ * knowing whether reassembly is complete if we
+ * get packet out of order such that the "last"
+ * fragment doesn't show up last - but, unless
+ * in-order reliable delivery of fragments is
+ * guaranteed, an implementation of the protocol
+ * has no way of knowing whether reassembly is
+ * complete, either.
+ *
+ * For now, we just link the fragment in and
+ * return.
+ */
+ LINK_FRAG(fd_head,fd);
+ return TRUE;
+ }
+ }
+
+ /* If we have reached this point, the packet is not defragmented yet.
+ * Save all payload in a buffer until we can defragment.
+ * XXX - what if we didn't capture the entire fragment due
+ * to a too-short snapshot length?
+ */
+ fd->data = g_malloc(fd->len);
+ tvb_memcpy(tvb, fd->data, offset, fd->len);
+ LINK_FRAG(fd_head,fd);
+
+
+ if( !(fd_head->datalen) ){
+ /* if we dont know the sequence number of the last fragment,
+ * there are definitely still missing packets. Cheaper than
+ * the check below.
+ */
+ return FALSE;
+ }
+
+
+ /* check if we have received the entire fragment
+ * this is easy since the list is sorted and the head is faked.
+ */
+ max = 0;
+ for(fd_i=fd_head->next;fd_i;fd_i=fd_i->next) {
+ if ( fd_i->offset==max ){
+ max++;
+ }
+ }
+ /* max will now be datalen+1 if all fragments have been seen */
+
+ if (max <= fd_head->datalen) {
+ /* we have not received all packets yet */
+ return FALSE;
+ }
+
+
+ if (max > (fd_head->datalen+1)) {
+ /* oops, too long fragment detected */
+ fd->flags |= FD_TOOLONGFRAGMENT;
+ fd_head->flags |= FD_TOOLONGFRAGMENT;
+ }
+
+
+ /* we have received an entire packet, defragment it and
+ * free all fragments
+ */
+ size=0;
+ last_fd=NULL;
+ for(fd_i=fd_head->next;fd_i;fd_i=fd_i->next) {
+ if(!last_fd || last_fd->offset!=fd_i->offset){
+ size+=fd_i->len;
+ }
+ last_fd=fd_i;
+ }
+ fd_head->data = g_malloc(size);
+ fd_head->len = size; /* record size for caller */
+
+ /* add all data fragments */
+ last_fd=NULL;
+ for (dfpos=0,fd_i=fd_head->next;fd_i;fd_i=fd_i->next) {
+ if (fd_i->len) {
+ if(!last_fd || last_fd->offset!=fd_i->offset){
+ memcpy(fd_head->data+dfpos,fd_i->data,fd_i->len);
+ dfpos += fd_i->len;
+ } else {
+ /* duplicate/retransmission/overlap */
+ fd_i->flags |= FD_OVERLAP;
+ fd_head->flags |= FD_OVERLAP;
+ if( (last_fd->len!=fd_i->datalen)
+ || memcmp(last_fd->data, fd_i->data, last_fd->len) ){
+ fd->flags |= FD_OVERLAPCONFLICT;
+ fd_head->flags |= FD_OVERLAPCONFLICT;
+ }
+ }
+ last_fd=fd_i;
+ }
+ }
+
+ /* we have defragmented the pdu, now free all fragments*/
+ for (fd_i=fd_head->next;fd_i;fd_i=fd_i->next) {
+ if(fd_i->data){
+ g_free(fd_i->data);
+ fd_i->data=NULL;
+ }
+ }
+
+ /* mark this packet as defragmented.
+ allows us to skip any trailing fragments */
+ fd_head->flags |= FD_DEFRAGMENTED;
+ fd_head->reassembled_in=pinfo->fd->num;
+
+ return TRUE;
+}
+
+/*
+ * This function adds a new fragment to the fragment hash table.
+ * If this is the first fragment seen for this datagram, a new entry
+ * is created in the hash table, otherwise this fragment is just added
+ * to the linked list of fragments for this packet.
+ *
+ * Returns a pointer to the head of the fragment data list if we have all the
+ * fragments, NULL otherwise.
+ *
+ * This function assumes frag_number being a block sequence number.
+ * The bsn for the first block is 0.
+ */
+fragment_data *
+fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
+ GHashTable *fragment_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ fragment_key key, *new_key;
+ fragment_data *fd_head;
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ fd_head = g_hash_table_lookup(fragment_table, &key);
+
+ /* have we already seen this frame ?*/
+ if (pinfo->fd->flags.visited) {
+ if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) {
+ return fd_head;
+ } else {
+ return NULL;
+ }
+ }
+
+ if (fd_head==NULL){
+ /* not found, this must be the first snooped fragment for this
+ * packet. Create list-head.
+ */
+ fd_head=g_mem_chunk_alloc(fragment_data_chunk);
+
+ /* head/first structure in list only holds no other data than
+ * 'datalen' then we don't have to change the head of the list
+ * even if we want to keep it sorted
+ */
+ fd_head->next=NULL;
+ fd_head->datalen=0;
+ fd_head->offset=0;
+ fd_head->len=0;
+ fd_head->flags=FD_BLOCKSEQUENCE;
+ fd_head->data=NULL;
+ fd_head->reassembled_in=0;
+
+ /*
+ * We're going to use the key to insert the fragment,
+ * so allocate a structure for it, and copy the
+ * addresses, allocating new buffers for the address
+ * data.
+ */
+ new_key = g_mem_chunk_alloc(fragment_key_chunk);
+ COPY_ADDRESS(&new_key->src, &key.src);
+ COPY_ADDRESS(&new_key->dst, &key.dst);
+ new_key->id = key.id;
+ g_hash_table_insert(fragment_table, new_key, fd_head);
+ }
+
+ if (fragment_add_seq_work(fd_head, tvb, offset, pinfo,
+ frag_number, frag_data_len, more_frags)) {
+ /*
+ * Reassembly is complete.
+ */
+ return fd_head;
+ } else {
+ /*
+ * Reassembly isn't complete.
+ */
+ return NULL;
+ }
+}
+
+fragment_data *
+fragment_add_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
+ void *v_act_id,
+ GHashTable *fragment_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ dcerpc_fragment_key key, *new_key;
+ fragment_data *fd_head;
+ e_uuid_t *act_id = (e_uuid_t *)v_act_id;
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+ key.act_id = *act_id;
+
+ fd_head = g_hash_table_lookup(fragment_table, &key);
+
+ /* have we already seen this frame ?*/
+ if (pinfo->fd->flags.visited) {
+ if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) {
+ return fd_head;
+ } else {
+ return NULL;
+ }
+ }
+
+ if (fd_head==NULL){
+ /* not found, this must be the first snooped fragment for this
+ * packet. Create list-head.
+ */
+ fd_head=g_mem_chunk_alloc(fragment_data_chunk);
+
+ /* head/first structure in list only holds no other data than
+ * 'datalen' then we don't have to change the head of the list
+ * even if we want to keep it sorted
+ */
+ fd_head->next=NULL;
+ fd_head->datalen=0;
+ fd_head->offset=0;
+ fd_head->len=0;
+ fd_head->flags=FD_BLOCKSEQUENCE;
+ fd_head->data=NULL;
+ fd_head->reassembled_in=0;
+
+ /*
+ * We're going to use the key to insert the fragment,
+ * so allocate a structure for it, and copy the
+ * addresses, allocating new buffers for the address
+ * data.
+ */
+ new_key = g_mem_chunk_alloc(dcerpc_fragment_key_chunk);
+ COPY_ADDRESS(&new_key->src, &key.src);
+ COPY_ADDRESS(&new_key->dst, &key.dst);
+ new_key->id = key.id;
+ new_key->act_id = key.act_id;
+ g_hash_table_insert(fragment_table, new_key, fd_head);
+ }
+
+ if (fragment_add_seq_work(fd_head, tvb, offset, pinfo,
+ frag_number, frag_data_len, more_frags)) {
+ /*
+ * Reassembly is complete.
+ */
+ return fd_head;
+ } else {
+ /*
+ * Reassembly isn't complete.
+ */
+ return NULL;
+ }
+}
+
+/*
+ * This does the work for "fragment_add_seq_check()" and
+ * "fragment_add_seq_next()".
+ *
+ * This function assumes frag_number being a block sequence number.
+ * The bsn for the first block is 0.
+ *
+ * If "no_frag_number" is TRUE, it uses the next expected fragment number
+ * as the fragment number if there is a reassembly in progress, otherwise
+ * it uses 0.
+ *
+ * If "no_frag_number" is FALSE, it uses the "frag_number" argument as
+ * the fragment number.
+ *
+ * If this is the first fragment seen for this datagram, a new
+ * "fragment_data" structure is allocated to refer to the reassembled,
+ * packet, and:
+ *
+ * if "more_frags" is false and "frag_802_11_hack" is true, the
+ * structure is not added to the hash table, and not given any
+ * fragments to refer to, but is just returned - this is a special
+ * hack for the 802.11 dissector (see packet-80211.c);
+ *
+ * otherwise, this fragment is added to the linked list of fragments
+ * for this packet, and the "fragment_data" structure is put into
+ * the hash table.
+ *
+ * Otherwise, this fragment is just added to the linked list of fragments
+ * for this packet.
+ *
+ * If, after processing this fragment, we have all the fragments,
+ * "fragment_add_seq_check_work()" removes that from the fragment hash
+ * table if necessary and adds it to the table of reassembled fragments,
+ * and returns a pointer to the head of the fragment list.
+ *
+ * If this is the first fragment we've seen, and "more_frags" is false
+ * and "frag_802_11_hack" is true, "fragment_add_seq_check_work()" does
+ * nothing to the fragment data list, and returns a pointer to the head
+ * of that (empty) list.
+ *
+ * Otherwise, it returns NULL.
+ */
+static fragment_data *
+fragment_add_seq_check_work(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table,
+ GHashTable *reassembled_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags,
+ gboolean no_frag_number, gboolean frag_802_11_hack)
+{
+ reassembled_key reass_key;
+ fragment_key key, *new_key, *old_key;
+ gpointer orig_key, value;
+ fragment_data *fd_head, *fd;
+
+ /*
+ * Have we already seen this frame?
+ * If so, look for it in the table of reassembled packets.
+ */
+ if (pinfo->fd->flags.visited) {
+ reass_key.frame = pinfo->fd->num;
+ reass_key.id = id;
+ return g_hash_table_lookup(reassembled_table, &reass_key);
+ }
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ if (!g_hash_table_lookup_extended(fragment_table, &key,
+ &orig_key, &value)) {
+ /* not found, this must be the first snooped fragment for this
+ * packet. Create list-head.
+ */
+ fd_head=g_mem_chunk_alloc(fragment_data_chunk);
+
+ /* head/first structure in list only holds no other data than
+ * 'datalen' then we don't have to change the head of the list
+ * even if we want to keep it sorted
+ */
+ fd_head->next=NULL;
+ fd_head->datalen=0;
+ fd_head->offset=0;
+ fd_head->len=0;
+ fd_head->flags=FD_BLOCKSEQUENCE;
+ fd_head->data=NULL;
+ fd_head->reassembled_in=0;
+
+ if ((no_frag_number || frag_802_11_hack) && !more_frags) {
+ /*
+ * This is the last fragment for this packet, and
+ * is the only one we've seen.
+ *
+ * Either we don't have sequence numbers, in which
+ * case we assume this is the first fragment for
+ * this packet, or we're doing special 802.11
+ * processing, in which case we assume it's one
+ * of those reassembled packets with a non-zero
+ * fragment number (see packet-80211.c); just
+ * add the fragment to the table of reassembled
+ * packets, and return a pointer to the head of
+ * the list.
+ */
+ fragment_reassembled(fd_head, pinfo,
+ reassembled_table, id);
+ return fd_head;
+ }
+
+ /*
+ * We're going to use the key to insert the fragment,
+ * so allocate a structure for it, and copy the
+ * addresses, allocating new buffers for the address
+ * data.
+ */
+ new_key = g_mem_chunk_alloc(fragment_key_chunk);
+ COPY_ADDRESS(&new_key->src, &key.src);
+ COPY_ADDRESS(&new_key->dst, &key.dst);
+ new_key->id = key.id;
+ g_hash_table_insert(fragment_table, new_key, fd_head);
+
+ orig_key = new_key; /* for unhashing it later */
+
+ /*
+ * If we weren't given an initial fragment number,
+ * make it 0.
+ */
+ if (no_frag_number)
+ frag_number = 0;
+ } else {
+ /*
+ * We found it.
+ */
+ fd_head = value;
+
+ /*
+ * If we weren't given an initial fragment number,
+ * use the next expected fragment number as the fragment
+ * number for this fragment.
+ */
+ if (no_frag_number) {
+ for (fd = fd_head; fd != NULL; fd = fd->next) {
+ if (fd->next == NULL)
+ frag_number = fd->offset + 1;
+ }
+ }
+ }
+
+ /*
+ * If we don't have all the data that is in this fragment,
+ * then we can't, and don't, do reassembly on it.
+ *
+ * If it's the first frame, handle it as an unfragmented packet.
+ * Otherwise, just handle it as a fragment.
+ *
+ * If "more_frags" isn't set, we get rid of the entry in the
+ * hash table for this reassembly, as we don't need it any more.
+ */
+ if (!tvb_bytes_exist(tvb, offset, frag_data_len)) {
+ if (!more_frags) {
+ /*
+ * Remove this from the table of in-progress
+ * reassemblies, and free up any memory used for
+ * it in that table.
+ */
+ old_key = orig_key;
+ fragment_unhash(fragment_table, old_key);
+ }
+ return frag_number == 0 ? fd_head : NULL;
+ }
+
+ if (fragment_add_seq_work(fd_head, tvb, offset, pinfo,
+ frag_number, frag_data_len, more_frags)) {
+ /*
+ * Reassembly is complete.
+ * Remove this from the table of in-progress
+ * reassemblies, add it to the table of
+ * reassembled packets, and return it.
+ */
+
+ /*
+ * Remove this from the table of in-progress reassemblies,
+ * and free up any memory used for it in that table.
+ */
+ old_key = orig_key;
+ fragment_unhash(fragment_table, old_key);
+
+ /*
+ * Add this item to the table of reassembled packets.
+ */
+ fragment_reassembled(fd_head, pinfo, reassembled_table, id);
+ return fd_head;
+ } else {
+ /*
+ * Reassembly isn't complete.
+ */
+ return NULL;
+ }
+}
+
+fragment_data *
+fragment_add_seq_check(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table,
+ GHashTable *reassembled_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ return fragment_add_seq_check_work(tvb, offset, pinfo, id,
+ fragment_table, reassembled_table, frag_number, frag_data_len,
+ more_frags, FALSE, FALSE);
+}
+
+fragment_data *
+fragment_add_seq_802_11(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table,
+ GHashTable *reassembled_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ return fragment_add_seq_check_work(tvb, offset, pinfo, id,
+ fragment_table, reassembled_table, frag_number, frag_data_len,
+ more_frags, FALSE, TRUE);
+}
+
+fragment_data *
+fragment_add_seq_next(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table,
+ GHashTable *reassembled_table, guint32 frag_data_len,
+ gboolean more_frags)
+{
+ return fragment_add_seq_check_work(tvb, offset, pinfo, id,
+ fragment_table, reassembled_table, 0, frag_data_len,
+ more_frags, TRUE, FALSE);
+}
+
+/*
+ * Process reassembled data; if we're on the frame in which the data
+ * was reassembled, put the fragment information into the protocol
+ * tree, and construct a tvbuff with the reassembled data, otherwise
+ * just put a "reassembled in" item into the protocol tree.
+ */
+tvbuff_t *
+process_reassembled_data(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ char *name, fragment_data *fd_head, const fragment_items *fit,
+ gboolean *update_col_infop, proto_tree *tree)
+{
+ tvbuff_t *next_tvb;
+ gboolean update_col_info;
+
+ if (fd_head != NULL && pinfo->fd->num == fd_head->reassembled_in) {
+ /*
+ * OK, we've reassembled this.
+ * Is this something that's been reassembled from more
+ * than one fragment?
+ */
+ if (fd_head->next != NULL) {
+ /*
+ * Yes.
+ * Allocate a new tvbuff, referring to the
+ * reassembled payload.
+ */
+ if (fd_head->flags & FD_BLOCKSEQUENCE) {
+ next_tvb = tvb_new_real_data(fd_head->data,
+ fd_head->len, fd_head->len);
+ } else {
+ next_tvb = tvb_new_real_data(fd_head->data,
+ fd_head->datalen, fd_head->datalen);
+ }
+
+ /*
+ * Add the tvbuff to the list of tvbuffs to which
+ * the tvbuff we were handed refers, so it'll get
+ * cleaned up when that tvbuff is cleaned up.
+ */
+ tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+
+ /* Add the defragmented data to the data source list. */
+ add_new_data_source(pinfo, next_tvb, name);
+
+ /* show all fragments */
+ if (fd_head->flags & FD_BLOCKSEQUENCE) {
+ update_col_info = !show_fragment_seq_tree(
+ fd_head, fit, tree, pinfo, next_tvb);
+ } else {
+ update_col_info = !show_fragment_tree(fd_head,
+ fit, tree, pinfo, next_tvb);
+ }
+ } else {
+ /*
+ * No.
+ * Return a tvbuff with the payload.
+ */
+ next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+ pinfo->fragmented = FALSE; /* one-fragment packet */
+ update_col_info = TRUE;
+ }
+ if (update_col_infop != NULL)
+ *update_col_infop = update_col_info;
+ } else {
+ /*
+ * We don't have the complete reassembled payload, or this
+ * isn't the final frame of that payload.
+ */
+ next_tvb = NULL;
+
+ /*
+ * If we know what frame this was reassembled in,
+ * and if there's a field to use for the number of
+ * the frame in which the packet was reassembled,
+ * add it to the protocol tree.
+ */
+ if (fd_head != NULL && fit->hf_reassembled_in != NULL) {
+ proto_tree_add_uint(tree,
+ *(fit->hf_reassembled_in), tvb,
+ 0, 0, fd_head->reassembled_in);
+ }
+ }
+ return next_tvb;
+}
+
+/*
+ * Show a single fragment in a fragment subtree.
+ */
+static void
+show_fragment(fragment_data *fd, int offset, const fragment_items *fit,
+ proto_tree *ft, tvbuff_t *tvb)
+{
+ proto_item *fei=NULL;
+ int hf;
+
+ if (fd->flags & (FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+ hf = *(fit->hf_fragment_error);
+ } else {
+ hf = *(fit->hf_fragment);
+ }
+ if (fd->len == 0) {
+ fei = proto_tree_add_uint_format(ft, hf,
+ tvb, offset, fd->len,
+ fd->frame,
+ "Frame: %u (no data)",
+ fd->frame);
+ } else {
+ fei = proto_tree_add_uint_format(ft, hf,
+ tvb, offset, fd->len,
+ fd->frame,
+ "Frame: %u, payload: %u-%u (%u bytes)",
+ fd->frame,
+ offset,
+ offset+fd->len-1,
+ fd->len);
+ }
+ PROTO_ITEM_SET_GENERATED(fei);
+ if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+ /* this fragment has some flags set, create a subtree
+ * for it and display the flags.
+ */
+ proto_tree *fet=NULL;
+
+ fet = proto_item_add_subtree(fei, *(fit->ett_fragment));
+ if (fd->flags&FD_OVERLAP) {
+ fei=proto_tree_add_boolean(fet,
+ *(fit->hf_fragment_overlap),
+ tvb, 0, 0,
+ TRUE);
+ PROTO_ITEM_SET_GENERATED(fei);
+ }
+ if (fd->flags&FD_OVERLAPCONFLICT) {
+ fei=proto_tree_add_boolean(fet,
+ *(fit->hf_fragment_overlap_conflict),
+ tvb, 0, 0,
+ TRUE);
+ PROTO_ITEM_SET_GENERATED(fei);
+ }
+ if (fd->flags&FD_MULTIPLETAILS) {
+ fei=proto_tree_add_boolean(fet,
+ *(fit->hf_fragment_multiple_tails),
+ tvb, 0, 0,
+ TRUE);
+ PROTO_ITEM_SET_GENERATED(fei);
+ }
+ if (fd->flags&FD_TOOLONGFRAGMENT) {
+ fei=proto_tree_add_boolean(fet,
+ *(fit->hf_fragment_too_long_fragment),
+ tvb, 0, 0,
+ TRUE);
+ PROTO_ITEM_SET_GENERATED(fei);
+ }
+ }
+}
+
+static gboolean
+show_fragment_errs_in_col(fragment_data *fd_head, const fragment_items *fit,
+ packet_info *pinfo)
+{
+ if (fd_head->flags & (FD_OVERLAPCONFLICT
+ |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "[Illegal %s]", fit->tag);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* This function will build the fragment subtree; it's for fragments
+ reassembled with "fragment_add()".
+
+ It will return TRUE if there were fragmentation errors
+ or FALSE if fragmentation was ok.
+*/
+gboolean
+show_fragment_tree(fragment_data *fd_head, const fragment_items *fit,
+ proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
+{
+ fragment_data *fd;
+ proto_tree *ft;
+ proto_item *fi;
+
+ /* It's not fragmented. */
+ pinfo->fragmented = FALSE;
+
+ fi = proto_tree_add_item(tree, *(fit->hf_fragments),
+ tvb, 0, -1, FALSE);
+ PROTO_ITEM_SET_GENERATED(fi);
+
+ ft = proto_item_add_subtree(fi, *(fit->ett_fragments));
+ for (fd = fd_head->next; fd != NULL; fd = fd->next)
+ show_fragment(fd, fd->offset, fit, ft, tvb);
+
+ return show_fragment_errs_in_col(fd_head, fit, pinfo);
+}
+
+/* This function will build the fragment subtree; it's for fragments
+ reassembled with "fragment_add_seq()" or "fragment_add_seq_check()".
+
+ It will return TRUE if there were fragmentation errors
+ or FALSE if fragmentation was ok.
+*/
+gboolean
+show_fragment_seq_tree(fragment_data *fd_head, const fragment_items *fit,
+ proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb)
+{
+ guint32 offset, next_offset;
+ fragment_data *fd, *last_fd;
+ proto_tree *ft;
+ proto_item *fi;
+
+ /* It's not fragmented. */
+ pinfo->fragmented = FALSE;
+
+ fi = proto_tree_add_item(tree, *(fit->hf_fragments),
+ tvb, 0, -1, FALSE);
+ PROTO_ITEM_SET_GENERATED(fi);
+ ft = proto_item_add_subtree(fi, *(fit->ett_fragments));
+ offset = 0;
+ next_offset = 0;
+ last_fd = NULL;
+ for (fd = fd_head->next; fd != NULL; fd = fd->next){
+ if (last_fd == NULL || last_fd->offset != fd->offset) {
+ offset = next_offset;
+ next_offset += fd->len;
+ }
+ last_fd = fd;
+ show_fragment(fd, offset, fit, ft, tvb);
+ }
+
+ return show_fragment_errs_in_col(fd_head, fit, pinfo);
+}
diff --git a/epan/reassemble.h b/epan/reassemble.h
new file mode 100644
index 0000000000..85c66942c9
--- /dev/null
+++ b/epan/reassemble.h
@@ -0,0 +1,244 @@
+/* reassemble.h
+ * Declarations of outines for {fragment,segment} reassembly
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 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.
+ */
+
+/* make sure that all flags that are set in a fragment entry is also set for
+ * the flags field of fd_head !!!
+ */
+
+/* only in fd_head: packet is defragmented */
+#define FD_DEFRAGMENTED 0x0001
+
+/* there are overlapping fragments */
+#define FD_OVERLAP 0x0002
+
+/* overlapping fragments contain different data */
+#define FD_OVERLAPCONFLICT 0x0004
+
+/* more than one fragment which indicates end-of data */
+#define FD_MULTIPLETAILS 0x0008
+
+/* fragment contains data past the end of the datagram */
+#define FD_TOOLONGFRAGMENT 0x0010
+
+/* fragment data not alloced, fd->data pointing to fd_head->data+fd->offset */
+#define FD_NOT_MALLOCED 0x0020
+
+/* this flag is used to request fragment_add to continue the reassembly process */
+#define FD_PARTIAL_REASSEMBLY 0x0040
+
+/* fragment offset is indicated by sequence number and not byte offset
+ into the defragmented packet */
+#define FD_BLOCKSEQUENCE 0x0100
+
+typedef struct _fragment_data {
+ struct _fragment_data *next;
+ guint32 frame;
+ guint32 offset;
+ guint32 len;
+ guint32 datalen; /*Only valid in first item of list */
+ guint32 reassembled_in; /* frame where this PDU was reassembled,
+ only valid in the first item of the list
+ and when FD_DEFRAGMENTED is set*/
+ guint32 flags;
+ unsigned char *data;
+} fragment_data;
+
+/*
+ * Initialize a fragment table.
+ */
+extern void fragment_table_init(GHashTable **fragment_table);
+extern void dcerpc_fragment_table_init(GHashTable **fragment_table);
+
+/*
+ * Initialize a reassembled-packet table.
+ */
+extern void reassembled_table_init(GHashTable **reassembled_table);
+
+/*
+ * Free up all space allocated for fragment keys and data.
+ */
+void reassemble_init(void);
+
+/*
+ * This function adds a new fragment to the fragment hash table.
+ * If this is the first fragment seen for this datagram, a new entry
+ * is created in the hash table, otherwise this fragment is just added
+ * to the linked list of fragments for this packet.
+ * The list of fragments for a specific datagram is kept sorted for
+ * easier handling.
+ *
+ * Returns a pointer to the head of the fragment data list if we have all the
+ * fragments, NULL otherwise.
+ */
+extern fragment_data *fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table, guint32 frag_offset,
+ guint32 frag_data_len, gboolean more_frags);
+extern fragment_data *fragment_add_multiple_ok(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, guint32 id, GHashTable *fragment_table,
+ guint32 frag_offset, guint32 frag_data_len, gboolean more_frags);
+
+extern fragment_data *fragment_add_check(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, guint32 id, GHashTable *fragment_table,
+ GHashTable *reassembled_table, guint32 frag_offset,
+ guint32 frag_data_len, gboolean more_frags);
+
+/* same as fragment_add() but this one assumes frag_number is a block
+ sequence number. note that frag_number is 0 for the first fragment. */
+extern fragment_data *fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags);
+
+extern fragment_data *
+fragment_add_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
+ void *act_id,
+ GHashTable *fragment_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags);
+
+/*
+ * These functions add a new fragment to the fragment hash table.
+ * If this is the first fragment seen for this datagram, a new
+ * "fragment_data" structure is allocated to refer to the reassembled,
+ * packet, and:
+ *
+ * in "fragment_add_seq_802_11()", if "more_frags" is false,
+ * the structure is not added to the hash table, and not given
+ * any fragments to refer to, but is just returned;
+ *
+ * otherwise, this fragment is added to the linked list of fragments
+ * for this packet, and the "fragment_data" structure is put into
+ * the hash table.
+ *
+ * Otherwise, this fragment is just added to the linked list of fragments
+ * for this packet.
+ *
+ * If, after processing this fragment, we have all the fragments, they
+ * remove that from the fragment hash table if necessary and add it
+ * to the table of reassembled fragments, and return a pointer to the
+ * head of the fragment list.
+ *
+ * If this is the first fragment we've seen, and "more_frags" is false,
+ * "fragment_add_seq_802_11()" does nothing to the fragment data list,
+ * and returns a pointer to the head of that (empty) list. The other
+ * routines return NULL.
+ *
+ * Otherwise, they return NULL.
+ *
+ * "fragment_add_seq_check()" and "fragment_add_seq_802_11()" assume
+ * frag_number is a block sequence number.
+ * The bsn for the first block is 0.
+ *
+ * "fragment_add_seq_next()" is for protocols with no sequence number,
+ * and assumes fragments always appear in sequence.
+ */
+extern fragment_data *
+fragment_add_seq_check(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table,
+ GHashTable *reassembled_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags);
+
+extern fragment_data *
+fragment_add_seq_802_11(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ guint32 id, GHashTable *fragment_table,
+ GHashTable *reassembled_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags);
+
+extern fragment_data *
+fragment_add_seq_next(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
+ GHashTable *fragment_table, GHashTable *reassembled_table,
+ guint32 frag_data_len, gboolean more_frags);
+
+/* to specify how much to reassemble, for fragmentation where last fragment can not be
+ * identified by flags or such.
+ * note that for FD_BLOCKSEQUENCE tot_len is the index for the tail fragment.
+ * i.e. since the block numbers start at 0, if we specify tot_len==2, that
+ * actually means we want to defragment 3 blocks, block 0, 1 and 2.
+ *
+ */
+extern void
+fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table,
+ guint32 tot_len);
+
+/* to resad whatever totlen previously set */
+extern guint32
+fragment_get_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table);
+
+/*
+ * This function will set the partial reassembly flag(FD_PARTIAL_REASSEMBLY) for a fh.
+ * When this function is called, the fh MUST already exist, i.e.
+ * the fh MUST be created by the initial call to fragment_add() before
+ * this function is called. Also note that this function MUST be called to indicate
+ * a fh will be extended (increase the already stored data). After calling this function,
+ * and if FD_DEFRAGMENTED is set, the reassembly process will be continued.
+ */
+extern void
+fragment_set_partial_reassembly(packet_info *pinfo, guint32 id, GHashTable *fragment_table);
+
+/* This function is used to check if there is partial or completed reassembly state
+ * matching this packet. I.e. Are there reassembly going on or not for this packet?
+ */
+extern fragment_data *
+fragment_get(packet_info *pinfo, guint32 id, GHashTable *fragment_table);
+
+/* This will free up all resources and delete reassembly state for this PDU.
+ * Except if the PDU is completely reassembled, then it would NOT deallocate the
+ * buffer holding the reassembled data but instead return the pointer to that
+ * buffer.
+ *
+ * So, if you call fragment_delete and it returns non-NULL, YOU are responsible to
+ * g_free() that buffer.
+ */
+extern unsigned char *
+fragment_delete(packet_info *pinfo, guint32 id, GHashTable *fragment_table);
+
+/* hf_fragment, hf_fragment_error, and hf_reassembled_in should be
+ FT_FRAMENUM, the others should be FT_BOOLEAN
+*/
+typedef struct _fragment_items {
+ gint *ett_fragment;
+ gint *ett_fragments;
+
+ int *hf_fragments;
+ int *hf_fragment;
+ int *hf_fragment_overlap;
+ int *hf_fragment_overlap_conflict;
+ int *hf_fragment_multiple_tails;
+ int *hf_fragment_too_long_fragment;
+ int *hf_fragment_error;
+ int *hf_reassembled_in;
+
+ char *tag;
+} fragment_items;
+
+extern tvbuff_t *
+process_reassembled_data(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ char *name, fragment_data *fd_head, const fragment_items *fit,
+ gboolean *update_col_infop, proto_tree *tree);
+
+extern gboolean
+show_fragment_tree(fragment_data *ipfd_head, const fragment_items *fit,
+ proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb);
+
+extern gboolean
+show_fragment_seq_tree(fragment_data *ipfd_head, const fragment_items *fit,
+ proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb);
diff --git a/epan/xmlstub.c b/epan/xmlstub.c
new file mode 100644
index 0000000000..6ceb9c32be
--- /dev/null
+++ b/epan/xmlstub.c
@@ -0,0 +1,170 @@
+/* xmlstub.c
+ * Routines to parse XML files using libxml2. This stub
+ * exists so that the library can be loaded on systems that
+ * have it.
+ *
+ * $Id$
+ *
+ * Copyright (c) 2001 by David Frascone <dave@frascone.com>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998-2001 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.
+ */
+
+#include <glib.h>
+#include <gmodule.h>
+#include <epan/report_err.h>
+
+/* XML Stub routines */
+#define IN_XMLSTUB
+#include "xmlstub.h"
+
+/*
+ * This routine will dynamically load libxml2 and will populate the
+ * XmlStub pointer structure.
+ *
+ * On any error, it will return non-zero, and it should be assumed that
+ * the current platform does not have dynamic library support, or does
+ * not have libxml2 installed.
+ */
+int
+loadLibXML(void)
+{
+ GModule *handle;
+ gpointer symbol;
+ int error=FALSE;
+
+ if (XmlStubInitialized) {
+ /* Did you ever get the feeling you've been here before? */
+
+ /*
+ * This is not thread safe. With threads, we'd need to
+ * synchronize all this so two threads can't initialize at once.
+ */
+ return 0;
+ }
+
+ /* Check to see if gmodule is supported */
+ if (!g_module_supported()) {
+ g_warning("XMLStub: Modules are not supported. Not initializing XML Stub");
+ return (-1);
+ }
+
+ /* open the dll. Is this named something different
+ * under windows? Perhaps we should check . . .
+ */
+ if ((handle = g_module_open(XML_LIBRARY, G_MODULE_BIND_LAZY)) == NULL) {
+ report_failure("XMLStub: Unable to open module " XML_LIBRARY );
+ return (-1);
+ }
+
+ /*
+ * Now that the library is open, copy all our relevant
+ * function pointers and integer pointers into our structure.
+ */
+ if (!g_module_symbol(handle, "xmlParseFile", &symbol)) {
+ g_warning("Unable to find \"xmlParseFile\"");
+ error=TRUE;
+ }
+ XmlStub.xmlParseFile= (xmlDocPtr(*)(const char *))symbol;
+
+ if (!g_module_symbol(handle, "xmlStrcmp", &symbol)) {
+ g_warning("Unable to find \"xmlStrcmp\"");
+ error=TRUE;
+ }
+ XmlStub.xmlStrcmp= (int (*)(const xmlChar *, const xmlChar *))symbol;
+
+ if (!g_module_symbol(handle, "xmlCreatePushParserCtxt", &symbol)) {
+ g_warning("Unable to find \"xmlCreatePushParserCtxt\"");
+ error=TRUE;
+ }
+ XmlStub.xmlCreatePushParserCtxt=(xmlParserCtxtPtr (*)
+ (xmlSAXHandlerPtr, void *, const char *,
+ int, const char *)) symbol;
+
+ if (!g_module_symbol(handle, "xmlParseChunk", &symbol)) {
+ g_warning("Unable to find \"xmlParseChunk\"");
+ error=TRUE;
+ }
+ XmlStub.xmlParseChunk=(int (*)(xmlParserCtxtPtr, const char *, int, int))symbol;
+
+ if (!g_module_symbol(handle, "xmlFreeParserCtxt", &symbol)) {
+ g_warning("Unable to find \"xmlFreeParserCtxt\"");
+ error=TRUE;
+ }
+ XmlStub.xmlFreeParserCtxt=(void (*)(xmlParserCtxtPtr))symbol;
+
+ if (!g_module_symbol(handle, "xmlDocGetRootElement", &symbol)) {
+ g_warning("Unable to find \"xmlDocGetRootElement\"");
+ error=TRUE;
+ }
+ XmlStub.xmlDocGetRootElement=(xmlNodePtr(*)(xmlDocPtr))symbol;
+
+ if (!g_module_symbol(handle, "xmlFreeDoc", &symbol)) {
+ g_warning("Unable to find \"xmlFreeDoc\"");
+ error=TRUE;
+ }
+ XmlStub.xmlFreeDoc=(void (*)(xmlDocPtr))symbol;
+
+ if (!g_module_symbol(handle, "xmlNodeListGetString", &symbol)) {
+ g_warning("Unable to find \"xmlNodeListGetString\"");
+ error=TRUE;
+ }
+ XmlStub.xmlNodeListGetString=(char * (*)(xmlDocPtr, xmlNodePtr, int))symbol;
+
+ if (!g_module_symbol(handle, "xmlGetProp", &symbol)) {
+ g_warning("Unable to find \"xmlGetProp\"");
+ error=TRUE;
+ }
+ XmlStub.xmlGetProp=(char * (*)(xmlNodePtr, char *))symbol;
+
+ if (!g_module_symbol(handle, "xmlKeepBlanksDefault", &symbol)) {
+ g_warning("Unable to find \"xmlKeepBlanksDefault\"");
+ error=TRUE;
+ }
+ XmlStub.xmlKeepBlanksDefault=(int(*)(int))symbol;
+
+ if (!g_module_symbol(handle, "xmlSubstituteEntitiesDefault", &symbol)) {
+ g_warning("Unable to find \"xmlSubstituteEntitiesDefault\"");
+ error=TRUE;
+ }
+ XmlStub.xmlSubstituteEntitiesDefault=(int(*)(int))symbol;
+
+#ifdef ETHEREAL_XML_DO_VALIDITY_CHECKING
+ if (!g_module_symbol(handle, "xmlDoValidityCheckingDefaultValue", &symbol)) {
+ g_warning("Unable to find \"xmlDoValidityCheckingDefaultValue\"");
+ error=TRUE;
+ }
+ XmlStub.xmlDoValidityCheckingDefaultValue = (int *)symbol;
+#endif
+
+ /*
+ * Return if any of the above functions set our error flag.
+ * A flag was used, instead of returning immediately, so
+ * that *all* unresolved symbols would be printed.
+ */
+ if (error) {
+ g_module_close(handle);
+ return (-1);
+ }
+ /* Set our global so that we don't try to load twice */
+ XmlStubInitialized=1;
+
+ return 0; /* Success! */
+
+} /* loadLibXML */
diff --git a/epan/xmlstub.h b/epan/xmlstub.h
new file mode 100644
index 0000000000..47a6d0a0ef
--- /dev/null
+++ b/epan/xmlstub.h
@@ -0,0 +1,1123 @@
+/*
+ * This is part of tree.h from the libxml2 distribution. It is used
+ * for structure reference when dynamically linking to libxml.
+ *
+ * The GPL agreement for this file and for libxml2 can be found at
+ * http://www.xmlsoft.org
+ */
+
+#include "config.h"
+
+/****************** specific to ethereal ********************************/
+/*
+ * Uncomment the following line to restore XML_DO_VALIDITY_CHECKING
+ * behavior which is causing issues on WIN32 platforms. See:
+ * http://www.ethereal.com/lists/ethereal-dev/200410/msg00194.html
+ */
+/* #define ETHEREAL_XML_DO_VALIDITY_CHECKING */
+/****************** From xml headers ************************************/
+
+/*
+ * use those to be sure nothing nasty will happen if
+ * your library and includes mismatch
+ */
+#ifndef LIBXML2_COMPILING_MSCCDEF
+extern void xmlCheckVersion(int version);
+#endif /* LIBXML2_COMPILING_MSCCDEF */
+#define LIBXML_DOTTED_VERSION "2.3.8"
+#define LIBXML_VERSION 20308
+#define LIBXML_VERSION_STRING "20308"
+#define LIBXML_TEST_VERSION xmlCheckVersion(20308);
+
+/*
+ * Whether the trio support need to be configured in
+ */
+#if 0
+#define WITH_TRIO
+#else
+#define WITHOUT_TRIO
+#endif
+
+/*
+ * Whether the FTP support is configured in
+ */
+#if 1
+#define LIBXML_FTP_ENABLED
+#else
+#define LIBXML_FTP_DISABLED
+#endif
+
+/*
+ * Whether the HTTP support is configured in
+ */
+#if 1
+#define LIBXML_HTTP_ENABLED
+#else
+#define LIBXML_HTTP_DISABLED
+#endif
+
+/*
+ * Whether the HTML support is configured in
+ */
+#if 1
+#define LIBXML_HTML_ENABLED
+#else
+#define LIBXML_HTML_DISABLED
+#endif
+
+/*
+ * Whether the SGML Docbook support is configured in
+ */
+#if 1
+#define LIBXML_DOCB_ENABLED
+#else
+#define LIBXML_DOCB_DISABLED
+#endif
+
+/*
+ * Whether XPath is configured in
+ */
+#if 1
+#define LIBXML_XPATH_ENABLED
+#else
+#define LIBXML_XPATH_DISABLED
+#endif
+
+/*
+ * Whether XPointer is configured in
+ */
+#if 1
+#define LIBXML_XPTR_ENABLED
+#else
+#define LIBXML_XPTR_DISABLED
+#endif
+
+/*
+ * Whether XInclude is configured in
+ */
+#if 1
+#define LIBXML_XINCLUDE_ENABLED
+#else
+#define LIBXML_XINCLUDE_DISABLED
+#endif
+
+/*
+ * Whether iconv support is available
+ */
+#ifdef HAVE_ICONV_H
+#define LIBXML_ICONV_ENABLED
+#include <iconv.h>
+#else
+#define LIBXML_ICONV_DISABLED
+#endif
+
+/*
+ * Whether Debugging module is configured in
+ */
+#if 1
+#define LIBXML_DEBUG_ENABLED
+#else
+#define LIBXML_DEBUG_DISABLED
+#endif
+
+/*
+ * Whether the memory debugging is configured in
+ */
+#if 0
+#define DEBUG_MEMORY_LOCATION
+#endif
+
+#ifndef LIBXML_DLL_IMPORT
+#if defined(_WIN32) && !defined(STATIC)
+#define LIBXML_DLL_IMPORT __declspec(dllimport)
+#else
+#define LIBXML_DLL_IMPORT
+#endif
+#endif
+
+#ifdef __GNUC__
+#ifdef HAVE_ANSIDECL_H
+#include <ansidecl.h>
+#endif
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED
+#endif
+#else
+#define ATTRIBUTE_UNUSED
+#endif
+
+
+#define XML_XML_NAMESPACE \
+ (const xmlChar *) "http://www.w3.org/XML/1998/namespace"
+
+/*
+ * The different element types carried by an XML tree
+ *
+ * NOTE: This is synchronized with DOM Level1 values
+ * See http://www.w3.org/TR/REC-DOM-Level-1/
+ *
+ * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should
+ * be deprecated to use an XML_DTD_NODE.
+ */
+typedef enum {
+ XML_ELEMENT_NODE= 1,
+ XML_ATTRIBUTE_NODE= 2,
+ XML_TEXT_NODE= 3,
+ XML_CDATA_SECTION_NODE= 4,
+ XML_ENTITY_REF_NODE= 5,
+ XML_ENTITY_NODE= 6,
+ XML_PI_NODE= 7,
+ XML_COMMENT_NODE= 8,
+ XML_DOCUMENT_NODE= 9,
+ XML_DOCUMENT_TYPE_NODE= 10,
+ XML_DOCUMENT_FRAG_NODE= 11,
+ XML_NOTATION_NODE= 12,
+ XML_HTML_DOCUMENT_NODE= 13,
+ XML_DTD_NODE= 14,
+ XML_ELEMENT_DECL= 15,
+ XML_ATTRIBUTE_DECL= 16,
+ XML_ENTITY_DECL= 17,
+ XML_NAMESPACE_DECL= 18,
+ XML_XINCLUDE_START= 19,
+ XML_XINCLUDE_END= 20
+#ifdef LIBXML_DOCB_ENABLED
+ ,XML_DOCB_DOCUMENT_NODE= 21
+#endif
+} xmlElementType;
+
+/*
+ * Size of an internal character representation.
+ *
+ * We use 8bit chars internal representation for memory efficiency,
+ * Note that with 8 bits wide xmlChars one can still use UTF-8 to handle
+ * correctly non ISO-Latin input.
+ */
+
+typedef unsigned char xmlChar;
+
+#ifndef _WIN32
+#ifndef CHAR
+#define CHAR xmlChar
+#endif
+#endif
+
+#define BAD_CAST (xmlChar *)
+
+/*
+ * a DTD Notation definition
+ */
+
+typedef struct _xmlNotation xmlNotation;
+typedef xmlNotation *xmlNotationPtr;
+struct _xmlNotation {
+ const xmlChar *name; /* Notation name */
+ const xmlChar *PublicID; /* Public identifier, if any */
+ const xmlChar *SystemID; /* System identifier, if any */
+};
+
+/*
+ * a DTD Attribute definition
+ */
+
+typedef enum {
+ XML_ATTRIBUTE_CDATA = 1,
+ XML_ATTRIBUTE_ID,
+ XML_ATTRIBUTE_IDREF ,
+ XML_ATTRIBUTE_IDREFS,
+ XML_ATTRIBUTE_ENTITY,
+ XML_ATTRIBUTE_ENTITIES,
+ XML_ATTRIBUTE_NMTOKEN,
+ XML_ATTRIBUTE_NMTOKENS,
+ XML_ATTRIBUTE_ENUMERATION,
+ XML_ATTRIBUTE_NOTATION
+} xmlAttributeType;
+
+typedef enum {
+ XML_ATTRIBUTE_NONE = 1,
+ XML_ATTRIBUTE_REQUIRED,
+ XML_ATTRIBUTE_IMPLIED,
+ XML_ATTRIBUTE_FIXED
+} xmlAttributeDefault;
+
+typedef struct _xmlEnumeration xmlEnumeration;
+typedef xmlEnumeration *xmlEnumerationPtr;
+struct _xmlEnumeration {
+ struct _xmlEnumeration *next; /* next one */
+ const xmlChar *name; /* Enumeration name */
+};
+
+typedef struct _xmlAttribute xmlAttribute;
+typedef xmlAttribute *xmlAttributePtr;
+struct _xmlAttribute {
+#ifndef XML_WITHOUT_CORBA
+ void *_private; /* for Corba, must be first ! */
+#endif
+ xmlElementType type; /* XML_ATTRIBUTE_DECL, must be second ! */
+ const xmlChar *name; /* Attribute name */
+ struct _xmlNode *children; /* NULL */
+ struct _xmlNode *last; /* NULL */
+ struct _xmlDtd *parent; /* -> DTD */
+ struct _xmlNode *next; /* next sibling link */
+ struct _xmlNode *prev; /* previous sibling link */
+ struct _xmlDoc *doc; /* the containing document */
+
+ struct _xmlAttribute *nexth; /* next in hash table */
+ xmlAttributeType atype; /* The attribute type */
+ xmlAttributeDefault def; /* the default */
+ const xmlChar *defaultValue; /* or the default value */
+ xmlEnumerationPtr tree; /* or the enumeration tree if any */
+ const xmlChar *prefix; /* the namespace prefix if any */
+ const xmlChar *elem; /* Element holding the attribute */
+};
+
+/*
+ * a DTD Element definition.
+ */
+typedef enum {
+ XML_ELEMENT_CONTENT_PCDATA = 1,
+ XML_ELEMENT_CONTENT_ELEMENT,
+ XML_ELEMENT_CONTENT_SEQ,
+ XML_ELEMENT_CONTENT_OR
+} xmlElementContentType;
+
+typedef enum {
+ XML_ELEMENT_CONTENT_ONCE = 1,
+ XML_ELEMENT_CONTENT_OPT,
+ XML_ELEMENT_CONTENT_MULT,
+ XML_ELEMENT_CONTENT_PLUS
+} xmlElementContentOccur;
+
+typedef struct _xmlElementContent xmlElementContent;
+typedef xmlElementContent *xmlElementContentPtr;
+struct _xmlElementContent {
+ xmlElementContentType type; /* PCDATA, ELEMENT, SEQ or OR */
+ xmlElementContentOccur ocur; /* ONCE, OPT, MULT or PLUS */
+ const xmlChar *name; /* Element name */
+ struct _xmlElementContent *c1; /* first child */
+ struct _xmlElementContent *c2; /* second child */
+ struct _xmlElementContent *parent; /* parent */
+};
+
+typedef enum {
+ XML_ELEMENT_TYPE_UNDEFINED = 0,
+ XML_ELEMENT_TYPE_EMPTY = 1,
+ XML_ELEMENT_TYPE_ANY,
+ XML_ELEMENT_TYPE_MIXED,
+ XML_ELEMENT_TYPE_ELEMENT
+} xmlElementTypeVal;
+
+typedef struct _xmlElement xmlElement;
+typedef xmlElement *xmlElementPtr;
+struct _xmlElement {
+#ifndef XML_WITHOUT_CORBA
+ void *_private; /* for Corba, must be first ! */
+#endif
+ xmlElementType type; /* XML_ELEMENT_DECL, must be second ! */
+ const xmlChar *name; /* Element name */
+ struct _xmlNode *children; /* NULL */
+ struct _xmlNode *last; /* NULL */
+ struct _xmlDtd *parent; /* -> DTD */
+ struct _xmlNode *next; /* next sibling link */
+ struct _xmlNode *prev; /* previous sibling link */
+ struct _xmlDoc *doc; /* the containing document */
+
+ xmlElementTypeVal etype; /* The type */
+ xmlElementContentPtr content; /* the allowed element content */
+ xmlAttributePtr attributes; /* List of the declared attributes */
+ const xmlChar *prefix; /* the namespace prefix if any */
+};
+
+/*
+ * An XML namespace.
+ * Note that prefix == NULL is valid, it defines the default namespace
+ * within the subtree (until overriden).
+ *
+ * XML_GLOBAL_NAMESPACE is now deprecated for good
+ * xmlNsType is unified with xmlElementType
+ */
+
+#define XML_LOCAL_NAMESPACE XML_NAMESPACE_DECL
+typedef xmlElementType xmlNsType;
+
+typedef struct _xmlNs xmlNs;
+typedef xmlNs *xmlNsPtr;
+struct _xmlNs {
+ struct _xmlNs *next; /* next Ns link for this node */
+ xmlNsType type; /* global or local */
+ const xmlChar *href; /* URL for the namespace */
+ const xmlChar *prefix; /* prefix for the namespace */
+};
+
+/*
+ * An XML DtD, as defined by <!DOCTYPE.
+ */
+typedef struct _xmlDtd xmlDtd;
+typedef xmlDtd *xmlDtdPtr;
+struct _xmlDtd {
+#ifndef XML_WITHOUT_CORBA
+ void *_private; /* for Corba, must be first ! */
+#endif
+ xmlElementType type; /* XML_DTD_NODE, must be second ! */
+ const xmlChar *name; /* Name of the DTD */
+ struct _xmlNode *children; /* the value of the property link */
+ struct _xmlNode *last; /* last child link */
+ struct _xmlDoc *parent; /* child->parent link */
+ struct _xmlNode *next; /* next sibling link */
+ struct _xmlNode *prev; /* previous sibling link */
+ struct _xmlDoc *doc; /* the containing document */
+
+ /* End of common part */
+ void *notations; /* Hash table for notations if any */
+ void *elements; /* Hash table for elements if any */
+ void *attributes; /* Hash table for attributes if any */
+ void *entities; /* Hash table for entities if any */
+ const xmlChar *ExternalID; /* External identifier for PUBLIC DTD */
+ const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC DTD */
+ void *pentities; /* Hash table for param entities if any */
+};
+
+/*
+ * A attribute of an XML node.
+ */
+typedef struct _xmlAttr xmlAttr;
+typedef xmlAttr *xmlAttrPtr;
+struct _xmlAttr {
+#ifndef XML_WITHOUT_CORBA
+ void *_private; /* for Corba, must be first ! */
+#endif
+ xmlElementType type; /* XML_ATTRIBUTE_NODE, must be second ! */
+ const xmlChar *name; /* the name of the property */
+ struct _xmlNode *children; /* the value of the property */
+ struct _xmlNode *last; /* NULL */
+ struct _xmlNode *parent; /* child->parent link */
+ struct _xmlAttr *next; /* next sibling link */
+ struct _xmlAttr *prev; /* previous sibling link */
+ struct _xmlDoc *doc; /* the containing document */
+ xmlNs *ns; /* pointer to the associated namespace */
+ xmlAttributeType atype; /* the attribute type if validating */
+};
+
+/*
+ * An XML ID instance.
+ */
+
+typedef struct _xmlID xmlID;
+typedef xmlID *xmlIDPtr;
+struct _xmlID {
+ struct _xmlID *next; /* next ID */
+ const xmlChar *value; /* The ID name */
+ xmlAttrPtr attr; /* The attribut holding it */
+};
+
+/*
+ * An XML IDREF instance.
+ */
+
+typedef struct _xmlRef xmlRef;
+typedef xmlRef *xmlRefPtr;
+struct _xmlRef {
+ struct _xmlRef *next; /* next Ref */
+ const xmlChar *value; /* The Ref name */
+ xmlAttrPtr attr; /* The attribut holding it */
+};
+
+/*
+ * A buffer structure
+ */
+
+typedef enum {
+ XML_BUFFER_ALLOC_DOUBLEIT,
+ XML_BUFFER_ALLOC_EXACT
+} xmlBufferAllocationScheme;
+
+typedef struct _xmlBuffer xmlBuffer;
+typedef xmlBuffer *xmlBufferPtr;
+struct _xmlBuffer {
+ xmlChar *content; /* The buffer content UTF8 */
+ unsigned int use; /* The buffer size used */
+ unsigned int size; /* The buffer size */
+ xmlBufferAllocationScheme alloc; /* The realloc method */
+};
+
+/*
+ * A node in an XML tree.
+ */
+typedef struct _xmlNode xmlNode;
+typedef xmlNode *xmlNodePtr;
+struct _xmlNode {
+#ifndef XML_WITHOUT_CORBA
+ void *_private; /* for Corba, must be first ! */
+#endif
+ xmlElementType type; /* type number, must be second ! */
+ const xmlChar *name; /* the name of the node, or the entity */
+ struct _xmlNode *children; /* parent->childs link */
+ struct _xmlNode *last; /* last child link */
+ struct _xmlNode *parent; /* child->parent link */
+ struct _xmlNode *next; /* next sibling link */
+ struct _xmlNode *prev; /* previous sibling link */
+ struct _xmlDoc *doc; /* the containing document */
+ xmlNs *ns; /* pointer to the associated namespace */
+#ifndef XML_USE_BUFFER_CONTENT
+ xmlChar *content; /* the content */
+#else
+ xmlBufferPtr content; /* the content in a buffer */
+#endif
+
+ /* End of common part */
+ struct _xmlAttr *properties;/* properties list */
+ xmlNs *nsDef; /* namespace definitions on this node */
+};
+
+/*
+ * An XML document.
+ */
+typedef struct _xmlDoc xmlDoc;
+typedef xmlDoc *xmlDocPtr;
+struct _xmlDoc {
+#ifndef XML_WITHOUT_CORBA
+ void *_private; /* for Corba, must be first ! */
+#endif
+ xmlElementType type; /* XML_DOCUMENT_NODE, must be second ! */
+ char *name; /* name/filename/URI of the document */
+ struct _xmlNode *children; /* the document tree */
+ struct _xmlNode *last; /* last child link */
+ struct _xmlNode *parent; /* child->parent link */
+ struct _xmlNode *next; /* next sibling link */
+ struct _xmlNode *prev; /* previous sibling link */
+ struct _xmlDoc *doc; /* autoreference to itself */
+
+ /* End of common part */
+ int compression;/* level of zlib compression */
+ int standalone; /* standalone document (no external refs) */
+ struct _xmlDtd *intSubset; /* the document internal subset */
+ struct _xmlDtd *extSubset; /* the document external subset */
+ struct _xmlNs *oldNs; /* Global namespace, the old way */
+ const xmlChar *version; /* the XML version string */
+ const xmlChar *encoding; /* external initial encoding, if any */
+ void *ids; /* Hash table for ID attributes if any */
+ void *refs; /* Hash table for IDREFs attributes if any */
+ const xmlChar *URL; /* The URI for that document */
+ int charset; /* encoding of the in-memory content
+ actually an xmlCharEncoding */
+};
+
+/**
+ * Predefined values for some standard encodings
+ * Libxml don't do beforehand translation on UTF8, ISOLatinX
+ * It also support UTF16 (LE and BE) by default.
+ *
+ * Anything else would have to be translated to UTF8 before being
+ * given to the parser itself. The BOM for UTF16 and the encoding
+ * declaration are looked at and a converter is looked for at that
+ * point. If not found the parser stops here as asked by the XML REC
+ * Converter can be registered by the user using xmlRegisterCharEncodingHandler
+ * but the currentl form doesn't allow stateful transcoding (a serious
+ * problem agreed !). If iconv has been found it will be used
+ * automatically and allow stateful transcoding, the simplest is then
+ * to be sure to enable icon and to provide iconv libs for the encoding
+ * support needed.
+ */
+typedef enum {
+ XML_CHAR_ENCODING_ERROR= -1, /* No char encoding detected */
+ XML_CHAR_ENCODING_NONE= 0, /* No char encoding detected */
+ XML_CHAR_ENCODING_UTF8= 1, /* UTF-8 */
+ XML_CHAR_ENCODING_UTF16LE= 2, /* UTF-16 little endian */
+ XML_CHAR_ENCODING_UTF16BE= 3, /* UTF-16 big endian */
+ XML_CHAR_ENCODING_UCS4LE= 4, /* UCS-4 little endian */
+ XML_CHAR_ENCODING_UCS4BE= 5, /* UCS-4 big endian */
+ XML_CHAR_ENCODING_EBCDIC= 6, /* EBCDIC uh! */
+ XML_CHAR_ENCODING_UCS4_2143=7, /* UCS-4 unusual ordering */
+ XML_CHAR_ENCODING_UCS4_3412=8, /* UCS-4 unusual ordering */
+ XML_CHAR_ENCODING_UCS2= 9, /* UCS-2 */
+ XML_CHAR_ENCODING_8859_1= 10,/* ISO-8859-1 ISO Latin 1 */
+ XML_CHAR_ENCODING_8859_2= 11,/* ISO-8859-2 ISO Latin 2 */
+ XML_CHAR_ENCODING_8859_3= 12,/* ISO-8859-3 */
+ XML_CHAR_ENCODING_8859_4= 13,/* ISO-8859-4 */
+ XML_CHAR_ENCODING_8859_5= 14,/* ISO-8859-5 */
+ XML_CHAR_ENCODING_8859_6= 15,/* ISO-8859-6 */
+ XML_CHAR_ENCODING_8859_7= 16,/* ISO-8859-7 */
+ XML_CHAR_ENCODING_8859_8= 17,/* ISO-8859-8 */
+ XML_CHAR_ENCODING_8859_9= 18,/* ISO-8859-9 */
+ XML_CHAR_ENCODING_2022_JP= 19,/* ISO-2022-JP */
+ XML_CHAR_ENCODING_SHIFT_JIS=20,/* Shift_JIS */
+ XML_CHAR_ENCODING_EUC_JP= 21,/* EUC-JP */
+ XML_CHAR_ENCODING_ASCII= 22 /* pure ASCII */
+} xmlCharEncoding;
+
+/**
+ * xmlCharEncodingInputFunc:
+ * @out: a pointer ot an array of bytes to store the UTF-8 result
+ * @outlen: the lenght of @out
+ * @in: a pointer ot an array of chars in the original encoding
+ * @inlen: the lenght of @in
+ *
+ * Take a block of chars in the original encoding and try to convert
+ * it to an UTF-8 block of chars out.
+ *
+ * Returns the number of byte written, or -1 by lack of space, or -2
+ * if the transcoding failed.
+ * The value of @inlen after return is the number of octets consumed
+ * as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of ocetes consumed.
+ */
+typedef int (* xmlCharEncodingInputFunc)(unsigned char* out, int *outlen,
+ const unsigned char* in, int *inlen);
+
+
+/**
+ * xmlCharEncodingOutputFunc:
+ * @out: a pointer ot an array of bytes to store the result
+ * @outlen: the lenght of @out
+ * @in: a pointer ot an array of UTF-8 chars
+ * @inlen: the lenght of @in
+ *
+ * Take a block of UTF-8 chars in and try to convert it to an other
+ * encoding.
+ * Note: a first call designed to produce heading info is called with
+ * in = NULL. If stateful this should also initialize the encoder state
+ *
+ * Returns the number of byte written, or -1 by lack of space, or -2
+ * if the transcoding failed.
+ * The value of @inlen after return is the number of octets consumed
+ * as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of ocetes consumed.
+ */
+typedef int (* xmlCharEncodingOutputFunc)(unsigned char* out, int *outlen,
+ const unsigned char* in, int *inlen);
+
+
+/*
+ * Block defining the handlers for non UTF-8 encodings.
+ * If iconv is supported, there is two extra fields
+ */
+
+typedef struct _xmlCharEncodingHandler xmlCharEncodingHandler;
+typedef xmlCharEncodingHandler *xmlCharEncodingHandlerPtr;
+struct _xmlCharEncodingHandler {
+ char *name;
+ xmlCharEncodingInputFunc input;
+ xmlCharEncodingOutputFunc output;
+#ifdef LIBXML_ICONV_ENABLED
+ iconv_t iconv_in;
+ iconv_t iconv_out;
+#endif /* LIBXML_ICONV_ENABLED */
+};
+
+typedef int (*xmlInputMatchCallback) (char const *filename);
+typedef void * (*xmlInputOpenCallback) (char const *filename);
+typedef int (*xmlInputReadCallback) (void * context, char * buffer, int len);
+typedef void (*xmlInputCloseCallback) (void * context);
+
+typedef struct _xmlParserInputBuffer xmlParserInputBuffer;
+typedef xmlParserInputBuffer *xmlParserInputBufferPtr;
+struct _xmlParserInputBuffer {
+ void* context;
+ xmlInputReadCallback readcallback;
+ xmlInputCloseCallback closecallback;
+
+ xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */
+
+ xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 */
+ xmlBufferPtr raw; /* if encoder != NULL buffer for raw input */
+};
+
+
+/*
+ * Those are the functions and datatypes for the library output
+ * I/O structures.
+ */
+
+typedef int (*xmlOutputMatchCallback) (char const *filename);
+typedef void * (*xmlOutputOpenCallback) (char const *filename);
+typedef int (*xmlOutputWriteCallback) (void * context, const char * buffer,
+ int len);
+typedef void (*xmlOutputCloseCallback) (void * context);
+
+typedef struct _xmlOutputBuffer xmlOutputBuffer;
+typedef xmlOutputBuffer *xmlOutputBufferPtr;
+struct _xmlOutputBuffer {
+ void* context;
+ xmlOutputWriteCallback writecallback;
+ xmlOutputCloseCallback closecallback;
+
+ xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */
+
+ xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 or ISOLatin */
+ xmlBufferPtr conv; /* if encoder != NULL buffer for output */
+ int written; /* total number of byte written */
+};
+
+#define XML_DEFAULT_VERSION "1.0"
+
+/**
+ * an xmlParserInput is an input flow for the XML processor.
+ * Each entity parsed is associated an xmlParserInput (except the
+ * few predefined ones). This is the case both for internal entities
+ * - in which case the flow is already completely in memory - or
+ * external entities - in which case we use the buf structure for
+ * progressive reading and I18N conversions to the internal UTF-8 format.
+ */
+
+typedef void (* xmlParserInputDeallocate)(xmlChar *);
+typedef struct _xmlParserInput xmlParserInput;
+typedef xmlParserInput *xmlParserInputPtr;
+struct _xmlParserInput {
+ /* Input buffer */
+ xmlParserInputBufferPtr buf; /* UTF-8 encoded buffer */
+
+ const char *filename; /* The file analyzed, if any */
+ const char *directory; /* the directory/base of teh file */
+ const xmlChar *base; /* Base of the array to parse */
+ const xmlChar *cur; /* Current char being parsed */
+ const xmlChar *end; /* end of the arry to parse */
+ int length; /* length if known */
+ int line; /* Current line */
+ int col; /* Current column */
+ int consumed; /* How many xmlChars already consumed */
+ xmlParserInputDeallocate free; /* function to deallocate the base */
+ const xmlChar *encoding; /* the encoding string for entity */
+ const xmlChar *version; /* the version string for entity */
+ int standalone; /* Was that entity marked standalone */
+};
+
+/**
+ * the parser can be asked to collect Node informations, i.e. at what
+ * place in the file they were detected.
+ * NOTE: This is off by default and not very well tested.
+ */
+typedef struct _xmlParserNodeInfo xmlParserNodeInfo;
+typedef xmlParserNodeInfo *xmlParserNodeInfoPtr;
+
+struct _xmlParserNodeInfo {
+ const struct _xmlNode* node;
+ /* Position & line # that text that created the node begins & ends on */
+ unsigned long begin_pos;
+ unsigned long begin_line;
+ unsigned long end_pos;
+ unsigned long end_line;
+};
+
+typedef struct _xmlParserNodeInfoSeq xmlParserNodeInfoSeq;
+typedef xmlParserNodeInfoSeq *xmlParserNodeInfoSeqPtr;
+struct _xmlParserNodeInfoSeq {
+ unsigned long maximum;
+ unsigned long length;
+ xmlParserNodeInfo* buffer;
+};
+
+/*
+ * Validation state added for non-determinist content model
+ */
+typedef struct _xmlValidState xmlValidState;
+typedef xmlValidState *xmlValidStatePtr;
+
+/**
+ * an xmlValidCtxt is used for error reporting when validating
+ */
+
+typedef void (*xmlValidityErrorFunc) (void *ctx, const char *msg, ...);
+typedef void (*xmlValidityWarningFunc) (void *ctx, const char *msg, ...);
+
+typedef struct _xmlValidCtxt xmlValidCtxt;
+typedef xmlValidCtxt *xmlValidCtxtPtr;
+struct _xmlValidCtxt {
+ void *userData; /* user specific data block */
+ xmlValidityErrorFunc error; /* the callback in case of errors */
+ xmlValidityWarningFunc warning; /* the callback in case of warning */
+
+ /* Node analysis stack used when validating within entities */
+ xmlNodePtr node; /* Current parsed Node */
+ int nodeNr; /* Depth of the parsing stack */
+ int nodeMax; /* Max depth of the parsing stack */
+ xmlNodePtr *nodeTab; /* array of nodes */
+
+ int finishDtd; /* finished validating the Dtd ? */
+ xmlDocPtr doc; /* the document */
+ int valid; /* temporary validity check result */
+
+ /* state state used for non-determinist content validation */
+ xmlValidState *vstate; /* current state */
+ int vstateNr; /* Depth of the validation stack */
+ int vstateMax; /* Max depth of the validation stack */
+ xmlValidState *vstateTab; /* array of validation states */
+};
+
+typedef struct _xmlLink xmlLink;
+typedef xmlLink *xmlLinkPtr;
+
+typedef struct _xmlList xmlList;
+typedef xmlList *xmlListPtr;
+
+typedef void (*xmlListDeallocator) (xmlLinkPtr lk);
+typedef int (*xmlListDataCompare) (const void *data0, const void *data1);
+typedef int (*xmlListWalker) (const void *data, const void *user);
+
+/*
+ * ALl notation declarations are stored in a table
+ * there is one table per DTD
+ */
+
+typedef struct _xmlHashTable xmlNotationTable;
+typedef xmlNotationTable *xmlNotationTablePtr;
+
+/*
+ * ALl element declarations are stored in a table
+ * there is one table per DTD
+ */
+
+typedef struct _xmlHashTable xmlElementTable;
+typedef xmlElementTable *xmlElementTablePtr;
+
+/*
+ * ALl attribute declarations are stored in a table
+ * there is one table per DTD
+ */
+
+typedef struct _xmlHashTable xmlAttributeTable;
+typedef xmlAttributeTable *xmlAttributeTablePtr;
+
+/*
+ * ALl IDs attributes are stored in a table
+ * there is one table per document
+ */
+
+typedef struct _xmlHashTable xmlIDTable;
+typedef xmlIDTable *xmlIDTablePtr;
+
+/*
+ * ALl Refs attributes are stored in a table
+ * there is one table per document
+ */
+
+typedef struct _xmlHashTable xmlRefTable;
+typedef xmlRefTable *xmlRefTablePtr;
+
+/* helper */
+xmlChar * xmlSplitQName2 (const xmlChar *name,
+ xmlChar **prefix);
+
+/**
+ * The parser is now working also as a state based parser
+ * The recursive one use the stagte info for entities processing
+ */
+typedef enum {
+ XML_PARSER_EOF = -1, /* nothing is to be parsed */
+ XML_PARSER_START = 0, /* nothing has been parsed */
+ XML_PARSER_MISC, /* Misc* before int subset */
+ XML_PARSER_PI, /* Whithin a processing instruction */
+ XML_PARSER_DTD, /* within some DTD content */
+ XML_PARSER_PROLOG, /* Misc* after internal subset */
+ XML_PARSER_COMMENT, /* within a comment */
+ XML_PARSER_START_TAG, /* within a start tag */
+ XML_PARSER_CONTENT, /* within the content */
+ XML_PARSER_CDATA_SECTION, /* within a CDATA section */
+ XML_PARSER_END_TAG, /* within a closing tag */
+ XML_PARSER_ENTITY_DECL, /* within an entity declaration */
+ XML_PARSER_ENTITY_VALUE, /* within an entity value in a decl */
+ XML_PARSER_ATTRIBUTE_VALUE, /* within an attribute value */
+ XML_PARSER_SYSTEM_LITERAL, /* within a SYSTEM value */
+ XML_PARSER_EPILOG, /* the Misc* after the last end tag */
+ XML_PARSER_IGNORE /* within an IGNORED section */
+} xmlParserInputState;
+
+/**
+ * The parser context.
+ * NOTE This doesn't completely defines the parser state, the (current ?)
+ * design of the parser uses recursive function calls since this allow
+ * and easy mapping from the production rules of the specification
+ * to the actual code. The drawback is that the actual function call
+ * also reflect the parser state. However most of the parsing routines
+ * takes as the only argument the parser context pointer, so migrating
+ * to a state based parser for progressive parsing shouldn't be too hard.
+ */
+typedef struct _xmlParserCtxt xmlParserCtxt;
+typedef xmlParserCtxt *xmlParserCtxtPtr;
+struct _xmlParserCtxt {
+ struct _xmlSAXHandler *sax; /* The SAX handler */
+ void *userData; /* For SAX interface only, used by DOM build */
+ xmlDocPtr myDoc; /* the document being built */
+ int wellFormed; /* is the document well formed */
+ int replaceEntities; /* shall we replace entities ? */
+ const xmlChar *version; /* the XML version string */
+ const xmlChar *encoding; /* the declared encoding, if any */
+ int standalone; /* standalone document */
+ int html; /* an HTML(1)/Docbook(2) document */
+
+ /* Input stream stack */
+ xmlParserInputPtr input; /* Current input stream */
+ int inputNr; /* Number of current input streams */
+ int inputMax; /* Max number of input streams */
+ xmlParserInputPtr *inputTab; /* stack of inputs */
+
+ /* Node analysis stack only used for DOM building */
+ xmlNodePtr node; /* Current parsed Node */
+ int nodeNr; /* Depth of the parsing stack */
+ int nodeMax; /* Max depth of the parsing stack */
+ xmlNodePtr *nodeTab; /* array of nodes */
+
+ int record_info; /* Whether node info should be kept */
+ xmlParserNodeInfoSeq node_seq; /* info about each node parsed */
+
+ int errNo; /* error code */
+
+ int hasExternalSubset; /* reference and external subset */
+ int hasPErefs; /* the internal subset has PE refs */
+ int external; /* are we parsing an external entity */
+
+ int valid; /* is the document valid */
+ int validate; /* shall we try to validate ? */
+ xmlValidCtxt vctxt; /* The validity context */
+
+ xmlParserInputState instate; /* current type of input */
+ int token; /* next char look-ahead */
+
+ char *directory; /* the data directory */
+
+ /* Node name stack */
+ xmlChar *name; /* Current parsed Node */
+ int nameNr; /* Depth of the parsing stack */
+ int nameMax; /* Max depth of the parsing stack */
+ xmlChar * *nameTab; /* array of nodes */
+
+ long nbChars; /* number of xmlChar processed */
+ long checkIndex; /* used by progressive parsing lookup */
+ int keepBlanks; /* ugly but ... */
+ int disableSAX; /* SAX callbacks are disabled */
+ int inSubset; /* Parsing is in int 1/ext 2 subset */
+ xmlChar * intSubName; /* name of subset */
+ xmlChar * extSubURI; /* URI of external subset */
+ xmlChar * extSubSystem; /* SYSTEM ID of external subset */
+
+ /* xml:space values */
+ int * space; /* Should the parser preserve spaces */
+ int spaceNr; /* Depth of the parsing stack */
+ int spaceMax; /* Max depth of the parsing stack */
+ int * spaceTab; /* array of space infos */
+
+ int depth; /* to prevent entity substitution loops */
+ xmlParserInputPtr entity; /* used to check entities boundaries */
+ int charset; /* encoding of the in-memory content
+ actually an xmlCharEncoding */
+ int nodelen; /* Those two fields are there to */
+ int nodemem; /* Speed up large node parsing */
+ int pedantic; /* signal pedantic warnings */
+ void *_private; /* For user data, libxml won't touch it */
+
+ int loadsubset; /* should the external subset be loaded */
+};
+
+/**
+ * a SAX Locator.
+ */
+typedef struct _xmlSAXLocator xmlSAXLocator;
+typedef xmlSAXLocator *xmlSAXLocatorPtr;
+struct _xmlSAXLocator {
+ const xmlChar *(*getPublicId)(void *ctx);
+ const xmlChar *(*getSystemId)(void *ctx);
+ int (*getLineNumber)(void *ctx);
+ int (*getColumnNumber)(void *ctx);
+};
+
+/*
+ * The different valid entity types
+ */
+typedef enum {
+ XML_INTERNAL_GENERAL_ENTITY = 1,
+ XML_EXTERNAL_GENERAL_PARSED_ENTITY = 2,
+ XML_EXTERNAL_GENERAL_UNPARSED_ENTITY = 3,
+ XML_INTERNAL_PARAMETER_ENTITY = 4,
+ XML_EXTERNAL_PARAMETER_ENTITY = 5,
+ XML_INTERNAL_PREDEFINED_ENTITY = 6
+} xmlEntityType;
+
+/*
+ * An unit of storage for an entity, contains the string, the value
+ * and the linkind data needed for the linking in the hash table.
+ */
+
+typedef struct _xmlEntity xmlEntity;
+typedef xmlEntity *xmlEntityPtr;
+struct _xmlEntity {
+#ifndef XML_WITHOUT_CORBA
+ void *_private; /* for Corba, must be first ! */
+#endif
+ xmlElementType type; /* XML_ENTITY_DECL, must be second ! */
+ const xmlChar *name; /* Attribute name */
+ struct _xmlNode *children; /* NULL */
+ struct _xmlNode *last; /* NULL */
+ struct _xmlDtd *parent; /* -> DTD */
+ struct _xmlNode *next; /* next sibling link */
+ struct _xmlNode *prev; /* previous sibling link */
+ struct _xmlDoc *doc; /* the containing document */
+
+ xmlChar *orig; /* content without ref substitution */
+ xmlChar *content; /* content or ndata if unparsed */
+ int length; /* the content length */
+ xmlEntityType etype; /* The entity type */
+ const xmlChar *ExternalID; /* External identifier for PUBLIC */
+ const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC Entity */
+
+ struct _xmlEntity *nexte; /* unused */
+ const xmlChar *URI; /* the full URI as computed */
+};
+
+/*
+ * ALl entities are stored in an hash table
+ * there is 2 separate hash tables for global and parmeter entities
+ */
+
+typedef struct _xmlHashTable xmlEntitiesTable;
+typedef xmlEntitiesTable *xmlEntitiesTablePtr;
+
+/*
+ * External functions :
+ */
+
+/**
+ * a SAX handler is bunch of callbacks called by the parser when processing
+ * of the input generate data or structure informations.
+ */
+
+typedef xmlParserInputPtr (*resolveEntitySAXFunc) (void *ctx,
+ const xmlChar *publicId, const xmlChar *systemId);
+typedef void (*internalSubsetSAXFunc) (void *ctx, const xmlChar *name,
+ const xmlChar *ExternalID, const xmlChar *SystemID);
+typedef void (*externalSubsetSAXFunc) (void *ctx, const xmlChar *name,
+ const xmlChar *ExternalID, const xmlChar *SystemID);
+typedef xmlEntityPtr (*getEntitySAXFunc) (void *ctx,
+ const xmlChar *name);
+typedef xmlEntityPtr (*getParameterEntitySAXFunc) (void *ctx,
+ const xmlChar *name);
+typedef void (*entityDeclSAXFunc) (void *ctx,
+ const xmlChar *name, int type, const xmlChar *publicId,
+ const xmlChar *systemId, xmlChar *content);
+typedef void (*notationDeclSAXFunc)(void *ctx, const xmlChar *name,
+ const xmlChar *publicId, const xmlChar *systemId);
+typedef void (*attributeDeclSAXFunc)(void *ctx, const xmlChar *elem,
+ const xmlChar *name, int type, int def,
+ const xmlChar *defaultValue, xmlEnumerationPtr tree);
+typedef void (*elementDeclSAXFunc)(void *ctx, const xmlChar *name,
+ int type, xmlElementContentPtr content);
+typedef void (*unparsedEntityDeclSAXFunc)(void *ctx,
+ const xmlChar *name, const xmlChar *publicId,
+ const xmlChar *systemId, const xmlChar *notationName);
+typedef void (*setDocumentLocatorSAXFunc) (void *ctx,
+ xmlSAXLocatorPtr loc);
+typedef void (*startDocumentSAXFunc) (void *ctx);
+typedef void (*endDocumentSAXFunc) (void *ctx);
+typedef void (*startElementSAXFunc) (void *ctx, const xmlChar *name,
+ const xmlChar **atts);
+typedef void (*endElementSAXFunc) (void *ctx, const xmlChar *name);
+typedef void (*attributeSAXFunc) (void *ctx, const xmlChar *name,
+ const xmlChar *value);
+typedef void (*referenceSAXFunc) (void *ctx, const xmlChar *name);
+typedef void (*charactersSAXFunc) (void *ctx, const xmlChar *ch,
+ int len);
+typedef void (*ignorableWhitespaceSAXFunc) (void *ctx,
+ const xmlChar *ch, int len);
+typedef void (*processingInstructionSAXFunc) (void *ctx,
+ const xmlChar *target, const xmlChar *data);
+typedef void (*commentSAXFunc) (void *ctx, const xmlChar *value);
+typedef void (*cdataBlockSAXFunc) (void *ctx, const xmlChar *value, int len);
+typedef void (*warningSAXFunc) (void *ctx, const char *msg, ...);
+typedef void (*errorSAXFunc) (void *ctx, const char *msg, ...);
+typedef void (*fatalErrorSAXFunc) (void *ctx, const char *msg, ...);
+typedef int (*isStandaloneSAXFunc) (void *ctx);
+typedef int (*hasInternalSubsetSAXFunc) (void *ctx);
+typedef int (*hasExternalSubsetSAXFunc) (void *ctx);
+
+typedef struct _xmlSAXHandler xmlSAXHandler;
+typedef xmlSAXHandler *xmlSAXHandlerPtr;
+struct _xmlSAXHandler {
+ internalSubsetSAXFunc internalSubset;
+ isStandaloneSAXFunc isStandalone;
+ hasInternalSubsetSAXFunc hasInternalSubset;
+ hasExternalSubsetSAXFunc hasExternalSubset;
+ resolveEntitySAXFunc resolveEntity;
+ getEntitySAXFunc getEntity;
+ entityDeclSAXFunc entityDecl;
+ notationDeclSAXFunc notationDecl;
+ attributeDeclSAXFunc attributeDecl;
+ elementDeclSAXFunc elementDecl;
+ unparsedEntityDeclSAXFunc unparsedEntityDecl;
+ setDocumentLocatorSAXFunc setDocumentLocator;
+ startDocumentSAXFunc startDocument;
+ endDocumentSAXFunc endDocument;
+ startElementSAXFunc startElement;
+ endElementSAXFunc endElement;
+ referenceSAXFunc reference;
+ charactersSAXFunc characters;
+ ignorableWhitespaceSAXFunc ignorableWhitespace;
+ processingInstructionSAXFunc processingInstruction;
+ commentSAXFunc comment;
+ warningSAXFunc warning;
+ errorSAXFunc error;
+ fatalErrorSAXFunc fatalError;
+ getParameterEntitySAXFunc getParameterEntity;
+ cdataBlockSAXFunc cdataBlock;
+ externalSubsetSAXFunc externalSubset;
+};
+
+/**
+ * External entity loaders types
+ */
+typedef xmlParserInputPtr (*xmlExternalEntityLoader)(const char *URL,
+ const char *ID,
+ xmlParserCtxtPtr context);
+
+/*
+ * Compatibility naming layer with libxml1
+ */
+#ifndef xmlChildrenNode
+#define xmlChildrenNode children
+#define xmlRootNode children
+#endif
+
+
+/*********************Xml routines and function pointers */
+#ifdef IN_XMLSTUB
+#define XML_EXTERN
+#else
+#define XML_EXTERN extern
+#endif
+
+typedef struct {
+ /* Functions */
+ xmlDocPtr (*xmlParseFile)(const char *filename);
+ int (*xmlStrcmp)(const xmlChar *str1, const xmlChar *str2);
+ xmlParserCtxtPtr (*xmlCreatePushParserCtxt)(xmlSAXHandlerPtr, void *, const char *,
+ int, const char *);
+ int (*xmlParseChunk)(xmlParserCtxtPtr, const char *, int, int);
+ void (*xmlFreeParserCtxt)(xmlParserCtxtPtr);
+ xmlNodePtr (*xmlDocGetRootElement)(xmlDocPtr);
+ void (*xmlFreeDoc)(xmlDocPtr);
+ char *(*xmlNodeListGetString)(xmlDocPtr, xmlNodePtr, int);
+ char *(*xmlGetProp)(xmlNodePtr, char *);
+ int (*xmlKeepBlanksDefault)(int);
+ int (*xmlSubstituteEntitiesDefault)(int);
+#ifdef ETHEREAL_XML_DO_VALIDITY_CHECKING
+ int *xmlDoValidityCheckingDefaultValue;
+#endif
+} XML_STUB;
+
+XML_EXTERN XML_STUB XmlStub;
+XML_EXTERN int XmlStubInitialized;
+
+#ifdef _WIN32
+/* We're in windows, use the windows filename */
+#define XML_LIBRARY "libxml2.dll"
+#else
+#define XML_LIBRARY "libxml2.so"
+#endif
+
+/*
+ * This needs to be called before the library is used. It
+ * returns zero on success. Any non-zero return means that
+ * either dynamic libraries are not supported, or that libxml
+ * is not installed on the current system. (Or it's not in
+ * the LD path)
+ */
+int loadLibXML(void);
+
+
+