aboutsummaryrefslogtreecommitdiffstats
path: root/docbook
diff options
context:
space:
mode:
authorJörg Mayer <jmayer@loplof.de>2005-08-02 06:39:04 +0000
committerJörg Mayer <jmayer@loplof.de>2005-08-02 06:39:04 +0000
commitd135654fb5557076cbd2b186102ab8be83182dcb (patch)
tree0e6945e334ff5f2b52823b9c2ea607ed8da863c2 /docbook
parent941922938685a6d82ea62e9951bac0068534aee3 (diff)
Fix svn properties where needed:
Remove svn:executable Add svn:executable Add svn:eol-style Add svn:keywords Add mime-type svn path=/trunk/; revision=15185
Diffstat (limited to 'docbook')
-rw-r--r--docbook/Makefile1
-rw-r--r--docbook/edg_src/EDG_chapter_build_intro.xml134
-rw-r--r--docbook/edg_src/EDG_chapter_capture.xml164
-rw-r--r--docbook/edg_src/EDG_chapter_dissection.xml2270
-rw-r--r--docbook/edg_src/EDG_chapter_works.xml308
-rw-r--r--docbook/release-notes.xml2
6 files changed, 1440 insertions, 1439 deletions
diff --git a/docbook/Makefile b/docbook/Makefile
index 29a10f4845..71e5b0ac56 100644
--- a/docbook/Makefile
+++ b/docbook/Makefile
@@ -21,6 +21,7 @@ FOP=fop-0.20.5/fop.bat
# html help compiler (Win32 only)
# (comment this out, if you don't want chm or don't have hhc installed)
HHC="/cygdrive/c/Program Files/HTML Help Workshop/hhc.exe"
+#HHC="true"
############### YOU SHOULDN'T HAVE TO EDIT ANYTHING BELOW THIS LINE! ################
diff --git a/docbook/edg_src/EDG_chapter_build_intro.xml b/docbook/edg_src/EDG_chapter_build_intro.xml
index 1cf3fa0e66..ecf075d459 100644
--- a/docbook/edg_src/EDG_chapter_build_intro.xml
+++ b/docbook/edg_src/EDG_chapter_build_intro.xml
@@ -1,67 +1,67 @@
-<!-- EDG Chapter Build Introduction -->
-<!-- $Id: EDG_chapter_libraries.xml 11816 2004-08-23 19:46:18Z ulfl $ -->
-
-<chapter id="ChapterBuildIntro">
- <title>Introduction</title>
-
- <section id="ChCodeOverview">
- <title>Source overview</title>
- <para>
- Ethereal consists of the following major parts:
- <itemizedlist>
- <listitem><para>
- Packet dissection - in the / and /epan directory
- </para></listitem>
- <listitem><para>
- File I/O - using Ethereal's own wiretap library
- </para></listitem>
- <listitem><para>
- Capture - using the libpcap/winpcap library
- </para></listitem>
- <listitem><para>
- User interface - using the GTK (and corresponding) libraries
- </para></listitem>
- <listitem><para>
- Help - using an external webbrowser and GTK text output
- </para></listitem>
- </itemizedlist>
- Beside this, some other minor parts and additional helpers exist.
- </para>
- <para>
- Currently there's no clean seperation of the modules in the code.
- However, as the development team switched from CVS to SVN some time ago,
- directory cleanup are much easier now. So there's a chance that
- the directory structure will become clean in the future.
- </para>
- </section>
-
- <section id="ChCodeStyle">
- <title>Coding styleguides</title>
- <para>
- The coding styleguides for Ethereal can be found in the "Code style"
- section of the file <filename>doc/README.developer</filename>.
- </para>
- </section>
-
- <section id="ChCodeGLib">
- <title>The GLib library</title>
- <para>
- Glib is used as a basic platform abstraction library, it's not related to
- GUI things.
- </para>
- <para>
- To quote the Glib documentation: <quote>GLib is a general-purpose utility
- library, which provides many useful
- data types, macros, type conversions, string utilities, file utilities,
- a main loop abstraction, and so on. It works on many UNIX-like platforms,
- Windows, OS/2 and BeOS. GLib is released under the GNU Library General
- Public License (GNU LGPL).</quote>
- </para>
- <para>
- GLib contains lot's of useful things for platform independant development.
- See XXX for details about GLib.
- </para>
- </section>
-
-</chapter>
-<!-- End of EUG Chapter Build Introduction -->
+<!-- EDG Chapter Build Introduction -->
+<!-- $Id$ -->
+
+<chapter id="ChapterBuildIntro">
+ <title>Introduction</title>
+
+ <section id="ChCodeOverview">
+ <title>Source overview</title>
+ <para>
+ Ethereal consists of the following major parts:
+ <itemizedlist>
+ <listitem><para>
+ Packet dissection - in the / and /epan directory
+ </para></listitem>
+ <listitem><para>
+ File I/O - using Ethereal's own wiretap library
+ </para></listitem>
+ <listitem><para>
+ Capture - using the libpcap/winpcap library
+ </para></listitem>
+ <listitem><para>
+ User interface - using the GTK (and corresponding) libraries
+ </para></listitem>
+ <listitem><para>
+ Help - using an external webbrowser and GTK text output
+ </para></listitem>
+ </itemizedlist>
+ Beside this, some other minor parts and additional helpers exist.
+ </para>
+ <para>
+ Currently there's no clean seperation of the modules in the code.
+ However, as the development team switched from CVS to SVN some time ago,
+ directory cleanup are much easier now. So there's a chance that
+ the directory structure will become clean in the future.
+ </para>
+ </section>
+
+ <section id="ChCodeStyle">
+ <title>Coding styleguides</title>
+ <para>
+ The coding styleguides for Ethereal can be found in the "Code style"
+ section of the file <filename>doc/README.developer</filename>.
+ </para>
+ </section>
+
+ <section id="ChCodeGLib">
+ <title>The GLib library</title>
+ <para>
+ Glib is used as a basic platform abstraction library, it's not related to
+ GUI things.
+ </para>
+ <para>
+ To quote the Glib documentation: <quote>GLib is a general-purpose utility
+ library, which provides many useful
+ data types, macros, type conversions, string utilities, file utilities,
+ a main loop abstraction, and so on. It works on many UNIX-like platforms,
+ Windows, OS/2 and BeOS. GLib is released under the GNU Library General
+ Public License (GNU LGPL).</quote>
+ </para>
+ <para>
+ GLib contains lot's of useful things for platform independant development.
+ See XXX for details about GLib.
+ </para>
+ </section>
+
+</chapter>
+<!-- End of EUG Chapter Build Introduction -->
diff --git a/docbook/edg_src/EDG_chapter_capture.xml b/docbook/edg_src/EDG_chapter_capture.xml
index 65b531acf3..544f422829 100644
--- a/docbook/edg_src/EDG_chapter_capture.xml
+++ b/docbook/edg_src/EDG_chapter_capture.xml
@@ -1,82 +1,82 @@
-<!-- EDG Chapter Capture -->
-<!-- $Id: EDG_chapter_capture.xml 11816 2004-08-23 19:46:18Z ulfl $ -->
-
-<chapter id="ChapterCapture">
- <title>Packet capturing</title>
-
- <para>
- XXX - this chapter has to be reviewed and extended!
- </para>
-
- <section id="ChCaptureAddLibpcap">
- <title>How to add a new capture type to libpcap</title>
- <para>
- The following is an excerpt from a developer mailing list mail, about
- adding ISO 9141 and 14230 (simple serial line car diagnostics) to
- Ethereal:
- </para>
- <para>
- For libpcap, the first thing you'd need to do would be to get DLT_ values
- for all the link-layer protocols you'd need. If ISO 9141 and 14230 use
- the same link-layer protocol, they might be able to share a DLT_ value,
- unless the only way to know what protocols are running above the link
- layer is to know which link-layer protocol is being used, in which case
- you might want separate DLT_ values.
- </para>
- <para>
- For the rest of the libpcap discussion, I'll assume you're working with
- the current top-of-tree CVS version of libpcap, and that this is on a
- UN*X platform. You probably don't want to work with a version older than
- 0.8, even if whatever OS you're using happens to include libpcap - older
- versions are not as friendly towards adding support for devices other than
- standard network interfaces.
- </para>
- <para>
- Then you'd probably add to the "pcap_open_live()" routine, for whatever
- platform or platforms this code should work, something such as a check
- for device names that look like serial port names and, if the check
- succeeds, a call to a routine to open the serial port.
- </para>
- <para>
- See, for example, the "#ifdef HAVE_DAG_API" code in pcap-linux.c and
- pcap-bpf.c.
- </para>
- <para>
- The serial port open routine would open the serial port device, set the
- baud rate and do anything else needed to open the device. It'd allocate
- a pcap_t, set its "fd" member to the file descriptor for the serial
- device, set the "snapshot" member to the argument passed to the open
- routine, set the "linktype" member to one of the DLT_ values, and set the
- "selectable_fd" member to the same value as the "fd" member. It should
- also set the "dlt_count" member to the number of DLT_ values to support,
- and allocate an array of "dlt_count" "u_int"s, assign it to the "dlt_list"
- member, and fill in that list with all the DLT_ values.
- </para>
- <para>
- You'd then set the various _op fields to routines to handle the
- operations in question. read_op is the routine that'd read packets from
- the device. inject_op would be for sending packets; if you don't care
- about that, you'd set it to a routine that returns an error indication.
- setfilter_op can probably just be set to install_bpf_program. set_datalink
- would just set the "linktype" member to the specified value if it's one
- of the values for OBD, otherwise it should return an error. getnonblock_op
- can probably be set to pcap_getnonblock_fd; setnonblock_op can probably be
- set to pcap_setnonblock_fd. stats_op would be set to a routine that
- reports statistics. close_op can probably be set to pcap_close_common.
- </para>
- <para>
- If there's more than one DLT_ value, you definitely want a set_datalink
- routine, so that the user can select the appropriate link-layer type.
- </para>
- <para>
- For Ethereal, you'd add support for those DLT_ values to wiretap/libpcap.c,
- which might mean adding one or more WTAP_ENCAP types to wtap.h and to the
- encap_table[] table in wiretap/wtap.c. You'd then have to write a
- dissector or dissectors for the link-layer protocols or protocols and have
- them register themselves with the "wtap_encap" dissector table, with the
- appropriate WTAP_ENCAP values, by calling "dissector_add()".
- </para>
- </section>
-
-</chapter>
-<!-- End of EUG Chapter Dissection -->
+<!-- EDG Chapter Capture -->
+<!-- $Id$ -->
+
+<chapter id="ChapterCapture">
+ <title>Packet capturing</title>
+
+ <para>
+ XXX - this chapter has to be reviewed and extended!
+ </para>
+
+ <section id="ChCaptureAddLibpcap">
+ <title>How to add a new capture type to libpcap</title>
+ <para>
+ The following is an excerpt from a developer mailing list mail, about
+ adding ISO 9141 and 14230 (simple serial line car diagnostics) to
+ Ethereal:
+ </para>
+ <para>
+ For libpcap, the first thing you'd need to do would be to get DLT_ values
+ for all the link-layer protocols you'd need. If ISO 9141 and 14230 use
+ the same link-layer protocol, they might be able to share a DLT_ value,
+ unless the only way to know what protocols are running above the link
+ layer is to know which link-layer protocol is being used, in which case
+ you might want separate DLT_ values.
+ </para>
+ <para>
+ For the rest of the libpcap discussion, I'll assume you're working with
+ the current top-of-tree CVS version of libpcap, and that this is on a
+ UN*X platform. You probably don't want to work with a version older than
+ 0.8, even if whatever OS you're using happens to include libpcap - older
+ versions are not as friendly towards adding support for devices other than
+ standard network interfaces.
+ </para>
+ <para>
+ Then you'd probably add to the "pcap_open_live()" routine, for whatever
+ platform or platforms this code should work, something such as a check
+ for device names that look like serial port names and, if the check
+ succeeds, a call to a routine to open the serial port.
+ </para>
+ <para>
+ See, for example, the "#ifdef HAVE_DAG_API" code in pcap-linux.c and
+ pcap-bpf.c.
+ </para>
+ <para>
+ The serial port open routine would open the serial port device, set the
+ baud rate and do anything else needed to open the device. It'd allocate
+ a pcap_t, set its "fd" member to the file descriptor for the serial
+ device, set the "snapshot" member to the argument passed to the open
+ routine, set the "linktype" member to one of the DLT_ values, and set the
+ "selectable_fd" member to the same value as the "fd" member. It should
+ also set the "dlt_count" member to the number of DLT_ values to support,
+ and allocate an array of "dlt_count" "u_int"s, assign it to the "dlt_list"
+ member, and fill in that list with all the DLT_ values.
+ </para>
+ <para>
+ You'd then set the various _op fields to routines to handle the
+ operations in question. read_op is the routine that'd read packets from
+ the device. inject_op would be for sending packets; if you don't care
+ about that, you'd set it to a routine that returns an error indication.
+ setfilter_op can probably just be set to install_bpf_program. set_datalink
+ would just set the "linktype" member to the specified value if it's one
+ of the values for OBD, otherwise it should return an error. getnonblock_op
+ can probably be set to pcap_getnonblock_fd; setnonblock_op can probably be
+ set to pcap_setnonblock_fd. stats_op would be set to a routine that
+ reports statistics. close_op can probably be set to pcap_close_common.
+ </para>
+ <para>
+ If there's more than one DLT_ value, you definitely want a set_datalink
+ routine, so that the user can select the appropriate link-layer type.
+ </para>
+ <para>
+ For Ethereal, you'd add support for those DLT_ values to wiretap/libpcap.c,
+ which might mean adding one or more WTAP_ENCAP types to wtap.h and to the
+ encap_table[] table in wiretap/wtap.c. You'd then have to write a
+ dissector or dissectors for the link-layer protocols or protocols and have
+ them register themselves with the "wtap_encap" dissector table, with the
+ appropriate WTAP_ENCAP values, by calling "dissector_add()".
+ </para>
+ </section>
+
+</chapter>
+<!-- End of EUG Chapter Dissection -->
diff --git a/docbook/edg_src/EDG_chapter_dissection.xml b/docbook/edg_src/EDG_chapter_dissection.xml
index ee2503a7ae..0e91c59b69 100644
--- a/docbook/edg_src/EDG_chapter_dissection.xml
+++ b/docbook/edg_src/EDG_chapter_dissection.xml
@@ -1,1135 +1,1135 @@
-<!-- EDG Chapter Dissection -->
-<!-- $Id: EDG_chapter_libraries.xml 11816 2004-08-23 19:46:18Z ulfl $ -->
-
-<chapter id="ChapterDissection">
- <title>Packet dissection</title>
- <!-- Julian Onions additions -->
- <section id="ChDissectWorks">
- <title>How it works</title>
- <para>
- Each dissector decodes it's part of the protocol, and then hand off
- decoding to subsequent dissectors for an encapsulated protocol.
- </para>
- <para>
- So it might all start with a Frame dissector which dissects the packet details
- of the capture file itself (e.g. timestamps), passes the data on to an
- Ethernet frame dissector that decodes the Ethernet header,
- and then passes the payload to the next dissector (e.g. IP) and so on.
- At each stage, details of the packet will be decoded and displayed.
- </para>
- <para>
- Dissection can be implemented in two possible ways. One is to have a dissector
- module compiled into the main program, which means its always available.
- Another way is to make a plugin (a shared library/DLL) that registers itself
- to handle dissection. - XXX add a special explanation section for this?
- </para>
- </section>
-
- <section id="ChDissectAdd">
- <title>Adding a basic dissector</title>
- <para>
- Lets step through adding a basic dissector. We'll start with the made up
- "foo" protocol. It consists of the following basic items.
- </para>
- <itemizedlist>
- <listitem><para>
- A packet type - 8 bits, possible values: 1 - initialisation, 2 - terminate, 3 - data.
- </para></listitem>
- <listitem><para>
- A set of flags stored in 8 bits, 0x01 - start packet, 0x02 - end packet, 0x04 - priority packet.
- </para></listitem>
- <listitem><para>
- A sequence number - 16 bits.
- </para></listitem>
- <listitem><para>
- An IP address.
- </para></listitem>
- </itemizedlist>
- <section id="ChDissectSetup">
- <title>Setting up the dissector</title>
- <para>
- The first decision you need to make is if this dissector will be a
- built in dissector, included in the main program, or a plugin.
- </para>
- <para>
- Plugins are the easiest to write initially as they don't need
- write permission on the main code base. So lets start with that.
- With a little care, the plugin can be made to run as a built in
- easily too - so we haven't lost anything.
- </para>
- <example><title>Basic Plugin setup.</title>
- <programlisting>
- <![CDATA[
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <gmodule.h>
-#include <epan/packet.h>
-#include <epan/prefs.h>
-
-/* forward reference */
-void proto_register_foo();
-void proto_reg_handoff_foo();
-void dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
-
-/* Define version if we are not building ethereal statically */
-#ifndef ENABLE_STATIC
-G_MODULE_EXPORT const gchar version[] = "0.0";
-#endif
-
-static int proto_foo = -1;
-static int global_foo_port = 1234;
-static dissector_handle_t foo_handle;
-
-#ifndef ENABLE_STATIC
-G_MODULE_EXPORT void
-plugin_register(void)
-{
- /* register the new protocol, protocol fields, and subtrees */
- if (proto_foo == -1) { /* execute protocol initialization only once */
- proto_register_foo();
- }
-}
-
-G_MODULE_EXPORT void
-plugin_reg_handoff(void){
- proto_reg_handoff_foo();
-}
-#endif]]>
- </programlisting>
- </example>
- <para>
- Lets go through this a bit at a time. First we have some boiler plate
- include files. These will be pretty constant to start with. Here we also
- pre-declare some functions that we'll be writing shortly.
- </para>
- <para>
- Next we have a section surrounded by #ifdef ENABLE_STATIC. This is what
- makes this a plugin rather than a built in dissector.
- </para>
- <para>
- The version is a simple string that is used to report on the version of this
- dissector. You should increase this number each time you make changes that you
- need to keep track of.
- </para>
- <para>
- Next we have an int that is initialised to -1 that records our protocol.
- This will get updated when we register this plugin with the main program.
- We can use this as a handy way to detect if we've been initialised yet.
- Its good practice to make all variables and functions that aren't exported
- static to keep name space pollution. Normally this isn't a problem unless your
- dissector gets so big it has to span multiple files.
- </para>
- <para>
- Then a global variable which contains the UDP port that we'll assume we are dissecting traffic for.
- </para>
- <para>
- Next a dissector reference that we'll initialise later.
- </para>
- <para>
- Next, the first plugin entry point. The function plugin_register() is called
- when the plugin is loaded and allows you to do some initialisation stuff,
- which will include communicating with the main program what you're plugins
- capabilities are.
- </para>
- <para>
- The plugin_reg_handoff routine is used when dissecting sub protocols. As our
- hypothetical protocol will be hypothetically carried over UDP then we will
- need to do this.
- </para>
- <para>
- Now we have the basics in place to interact with the main program, we had
- better fill in those missing functions. Lets start with register function.
- </para>
- <example><title>Plugin Initialisation.</title>
- <programlisting>
- <![CDATA[
-void
-proto_register_foo(void)
-{
- module_t *foo_module;
-
- if (proto_foo == -1) {
- proto_foo = proto_register_protocol (
- "FOO Protocol", /* name */
- "FOO", /* short name */
- "foo" /* abbrev */
- );
- }
- foo_module = prefs_register_protocol(proto_foo, proto_reg_handoff_foo);
-}]]>
- </programlisting></example>
- <para>
- First a call to proto_register_protocol that
- registers the protocol. We can give it three names that
- will be used in various places to display it.
- - XXX explain where, this can be confusing
- </para>
- <para>
- Then we call the preference register function. At the moment we have
- no specific protocol preferences so this will be all that we need.
- This takes a function parameter which is our handoff function.
- I guess we'd better write that next.
- </para>
- <example><title>Plugin Handoff.</title>
- <programlisting>
- <![CDATA[
-void
-proto_reg_handoff_foo(void)
-{
- static int Initialized=FALSE;
-
- if (!Initialized) {
- foo_handle = create_dissector_handle(dissect_foo, proto_foo);
- dissector_add("udp.port", global_foo_port, foo_handle);
- }
-}]]>
- </programlisting></example>
- <para>
- What's happening here? We are initialising the dissector if it hasn't
- been initialised yet.
- First we create the dissector. This registers a routine
- to be called to do the actual dissecting.
- Then we associate it with a udp port number
- so that the main program will know to call us when it gets UDP traffic on that port.
- </para>
- <para>
- Now at last we finally get to write some dissecting code. For the moment we'll
- leave it as a basic placeholder.
- </para>
- <example><title>Plugin Dissection.</title>
- <programlisting>
- <![CDATA[
-static void
-dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
-{
-
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "FOO");
- /* Clear out stuff in the info column */
- if(check_col(pinfo->cinfo,COL_INFO)){
- col_clear(pinfo->cinfo,COL_INFO);
- }
-}]]>
- </programlisting></example>
- <para>
- This function is called to dissect the packets presented to it.
- The packet data is held in a special buffer referenced here as tvb.
- We shall become fairly familiar with this as we get deeper into the details
- of the protocol.
- The packet info structure contains general data about the protocol, and we
- can update information here.
- The tree parameter is where the detail dissection takes place.
- </para>
- <para>
- For now we'll do the minimum we can get away with.
- The first two lines check to see if the Protocol column is being displayed in
- the UI. If it is, we set the text of this to our protocol, so everyone
- can see its been recognised.
- The only other thing we do is to clear out any data in the INFO column
- if its being displayed.
- </para>
- <para>
- At this point we should have a basic dissector ready to compile and install.
- It doesn't do much at present, than identify the protocol and label it.
- Compile the dissector to a dll or shared library, and copy it into the plugin
- directory of the installation. To finish this off a Makefile of some sort will be
- required. A Makefile.nmake for Windows platforms and a Makefile.am for unix/linux
- types.
- </para>
-
- <example><title>Makefile.nmake for Windows.</title>
- <programlisting>
- <![CDATA[
-include ..\..\config.nmake
-
-############### no need to modify below this line #########
-
-CFLAGS=/DHAVE_CONFIG_H /I../.. /I../../wiretap $(GLIB_CFLAGS) \
- /I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS)
-
-LDFLAGS = /NOLOGO /INCREMENTAL:no /MACHINE:I386 $(LOCAL_LDFLAGS)
-
-!IFDEF ENABLE_LIBETHEREAL
-LINK_PLUGIN_WITH=..\..\epan\libethereal.lib
-CFLAGS=/DHAVE_WIN32_LIBETHEREAL_LIB /D_NEED_VAR_IMPORT_ $(CFLAGS)
-
-OBJECTS=foo.obj
-
-foo.dll foo.exp foo.lib : $(OBJECTS) $(LINK_PLUGIN_WITH)
- link -dll /out:foo.dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \
- $(GLIB_LIBS)
-
-!ENDIF
-
-clean:
- rm -f $(OBJECTS) foo.dll foo.exp foo.lib *.pdb
-
-distclean: clean
-
-maintainer-clean: distclean]]>
- </programlisting></example>
- <example><title>Makefile.am for unix/linux.</title>
- <programlisting>
- <![CDATA[
-INCLUDES = -I$(top_srcdir)
-
-plugindir = @plugindir@
-
-plugin_LTLIBRARIES = foo.la
-foo_la_SOURCES = foo.c moduleinfo.h
-foo_la_LDFLAGS = -module -avoid-version
-foo_la_LIBADD = @PLUGIN_LIBS@
-
-# Libs must be cleared, or else libtool won't create a shared module.
-# If your module needs to be linked against any particular libraries,
-# add them here.
-LIBS =
-
-CLEANFILES = \
- foo \
- *~
-
-EXTRA_DIST = \
- Makefile.nmake
-]]>
- </programlisting></example>
- </section>
-
- <section id="ChDissectDetails">
- <title>Dissecting the details of the protocol</title>
- <para>
- Now we have our basic dissector up and running, lets do something with it.
- The simplest thing to do to start with is to just label the payload.
- This will allow us to set up some of the parts we will need.
- </para>
- <para>
- The first thing we will do is to build a subtree to decode our results into.
- This helps to keep things looking nice in the detailed display.
- Now the dissector is called in two different cases. In one case
- it is called to get a summary of the packet, in the other case it is
- called to look into details of the packet. These two cases can be
- distinguished by the tree pointer. If the tree pointer is NULL, then
- we are being asked for a summary. If it is non null, we can pick apart
- the protocol for display. So with that in mind, lets enhance our dissector.
- </para>
- <example><title>Plugin Packet Dissection.</title>
- <programlisting>
- <![CDATA[
-static void
-dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
-{
-
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "FOO");
- /* Clear out stuff in the info column */
- if(check_col(pinfo->cinfo,COL_INFO)){
- col_clear(pinfo->cinfo,COL_INFO);
- }
-
- if (tree) { /* we are being asked for details */
- proto_item *ti = NULL;
- ti = proto_tree_add_item(tree, proto_foo, tvb, 0, -1, FALSE);
- }
-}]]>
- </programlisting></example>
- <para>
- What we're doing here is adding a subtree to the dissection.
- This subtree will hold all the details of this protocol and so not clutter
- up the display when not required.
- </para>
- <para>
- We are also marking the area of data that is being consumed by this
- protocol. In our cases its all that has been passed to us, as we're assuming
- this protocol does not encapsulate another.
- Therefore, we add the new tree node with proto_tree_add_item, adding
- it to the passed in tree, label it with the protocol, use the passed in
- tvb buffer as the data, and consume from 0 to the end (-1) of this data.
- The FALSE we'll ignore for now.
- </para>
- <para>
- After this change, there should be a label in the detailed display for the protocol,
- and selecting this will highlight the remaining contents of the packet.
- </para>
- <para>
- Now lets go to the next step and add some protocol dissection.
- For this step we'll need to construct a couple of tables that help with dissection.
- This needs some changes to proto_register_foo. First a couple of statically
- declare arrays.
- </para>
- <example><title>Plugin Registering data structures.</title>
- <programlisting>
- <![CDATA[
-static hf_register_info hf[] = {
- { &hf_foo_pdu_type,
- { "FOO PDU Type", "foo.type",
- FT_UINT8, BASE_DEC, NULL, 0x0,
- "", HFILL }
- },
-
-};
-
-
-/* Setup protocol subtree array */
-static gint *ett[] = {
- &ett_foo,
-};
-]]>
- </programlisting></example>
- <para>
- Then, after the registration code, we register these arrays.
- </para>
- <example><title>Plugin Registering data structures.</title>
- <programlisting>
- <![CDATA[
-
- proto_register_field_array(proto_foo, hf, array_length(hf));
- proto_register_subtree_array(ett, array_length(ett));
-]]>
- </programlisting></example>
- <para>
- The variables hf_foo_pdu_type and ett_foo also need to be declared
- somewhere near the top of the file.
- </para>
- <example><title>Plugin data structure globals.</title>
- <programlisting>
- <![CDATA[
-static int hf_foo_pdu_type = -1;
-
-static gint ett_foo = -1;
-]]>
- </programlisting></example>
- <para>
- Now we can enhance the protocol display with some detail.
- </para>
- <example><title>Plugin starting to dissect the packets.</title>
- <programlisting>
- <![CDATA[
- if (tree) { /* we are being asked for details */
- proto_item *ti = NULL;
- proto_tree *foo_tree = NULL;
-
- ti = proto_tree_add_item(tree, proto_foo, tvb, 0, -1, FALSE);
- foo_tree = proto_item_add_subtree(ti, ett_foo);
- proto_tree_add_item(foo_tree, hf_foo_pdu_type, tvb, 0, 1, FALSE);
- }
-]]>
- </programlisting></example>
- <para>
- Now the dissection is starting to look more interesting. We have picked apart
- our first bit of the protocol. One byte of data at the start of the packet
- that defines the packet type for foo protocol.
- </para>
- <para>
- The proto_item_add_subtree call has added a child node to the protocol tree
- which is where we will do our detail dissection. The expansion of this
- node is controlled by the ett_foo variable. This remembers if the node should
- be expanded or not as you move between packets.
- All subsequent dissection will be added to this tree, as you can see from the next call.
- A call to proto_tree_add_item in the foo_tree, this time using the
- hf_foo_pdu_type to control the formatting of the item. The pdu type
- is one byte of data, starting at 0. We assume it is in network order,
- so that is why we use FALSE. Although for 1 byte there is no order issues
- its best to keep right.
- </para>
- <para>
- If we look in detail at the hf_foo_pdu_type declaration in the static array
- we can see the details of the definition.
- </para>
- <itemizedlist>
- <listitem><para>
- hf_foo_pdu_type - the index for this node.
- </para></listitem>
- <listitem><para>
- FOO PDU Type - the label for this item.
- </para></listitem>
- <listitem><para>
- foo.type - this is the filter string. It enables us to type constructs such
- as foo.type=1 into the filter box.
- </para></listitem>
- <listitem><para>
- FT_UNIT8 - this specifies this item is an 8bit unsigned integer.
- This tallies with our call above where we tell it to only look at one byte.
- </para></listitem>
- <listitem><para>
- BASE_DEC - for an integer type, this tells it to be printed as a decimal
- number. It could be BASE_HEX or BASE_OCT if that made more sense.
- </para></listitem>
- </itemizedlist>
- <para>
- We'll ignore the rest of the structure for now.
- </para>
- <para>
- If you install this plugin and try it out, you'll see something that begins to look
- useful.
- </para>
- <para>
- Now lets finish off dissecting the simple protocol. We need to add a few
- more variables to the hf array, and a couple more procedure calls.
- </para>
- <example><title>Plugin wrapping up the packet dissection.</title>
- <programlisting>
- <![CDATA[
-static int hf_foo_flags = -1;
-static int hf_foo_sequenceno = -1;
-static int hf_foo_initialip = -1;
-...
- { &hf_foo_flags,
- { "FOO PDU Flags", "foo.flags",
- FT_UINT8, BASE_HEX, NULL, 0x0,
- "", HFILL }
- },
- { &hf_foo_sequenceno,
- { "FOO PDU Sequence Number", "foo.seqn",
- FT_UINT16, BASE_DEC, NULL, 0x0,
- "", HFILL }
- },
- { &hf_foo_initialip,
- { "FOO PDU Initial IP", "foo.initialip",
- FT_IPv4, BASE_NONE, NULL, 0x0,
- "", HFILL }
- },
-...
- gint offset = 0;
-
- ti = proto_tree_add_item(tree, proto_foo, tvb, 0, -1, FALSE);
- foo_tree = proto_item_add_subtree(ti, ett_foo);
- proto_tree_add_item(foo_tree, hf_foo_pdu_type, tvb, offset, 1, FALSE); offset += 1;
- proto_tree_add_item(foo_tree, hf_foo_flags, tvb, offset, 1, FALSE); offset += 1;
- proto_tree_add_item(foo_tree, hf_foo_sequenceno, tvb, offset, 2, FALSE); offset += 2;
- proto_tree_add_item(foo_tree, hf_foo_initialip, tvb, offset, 4, FALSE); offset += 4;
-
-]]>
- </programlisting></example>
- <para>
- This dissects all the bits of this simple hypothetical protocol. We've introduced a new
- variable offset into the mix to help keep track of where we are in the packet dissection.
- With these extra bits in place, the whole protocol is now dissected.
- </para>
- </section>
- <section><title>Improving the dissection information</title>
- <para>
- We can certainly improve the display of the proto with a bit of extra data.
- The first step is to add some text labels. Lets start by labelling the packet types.
- There is some useful support for this sort of thing by adding a couple of extra things.
- First we add a simple table of type to name.
- </para>
- <example><title>Naming the packet types.</title>
- <programlisting>
- <![CDATA[
-static const value_string packettypenames[] = {
- { 1, "Initialise" },
- { 2, "Terminate" },
- { 3, "Data" },
- { 0, NULL },
-};
-]]>
- </programlisting></example>
- <para>
- This is a handy data structure that can be used to look up value to names.
- There are routines to directly access this lookup table, but we don't need to
- do that, as the support code already has that added in. We just have to give
- these details to the appropriate part of data, using the VALS macro.
- </para>
- <example><title>Adding Names to the protocol.</title>
- <programlisting>
- <![CDATA[
- { &hf_foo_pdu_type,
- { "FOO PDU Type", "foo.type",
- FT_UINT8, BASE_DEC, VALS(packettypenames), 0x0,
- "", HFILL }
- },
-]]>
- </programlisting></example>
- <para>
- This helps in deciphering the packets, and we can do a similar thing for the
- flags structure. For this we need to add some more data to the table though.
- </para>
- <example><title>Adding Flags to the protocol.</title>
- <programlisting>
- <![CDATA[
-#define FOO_START_FLAG 0x01
-#define FOO_END_FLAG 0x02
-#define FOO_PRIORITY_FLAG 0x04
-
-static int hf_foo_startflag = -1;
-static int hf_foo_endflag = -1;
-static int hf_foo_priorityflag = -1;
-...
- { &hf_foo_startflag,
- { "FOO PDU Start Flags", "foo.flags.start",
- FT_BOOLEAN, 8, NULL, FOO_START_FLAG,
- "", HFILL }
- },
- { &hf_foo_endflag,
- { "FOO PDU End Flags", "foo.flags.end",
- FT_BOOLEAN, 8, NULL, FOO_END_FLAG,
- "", HFILL }
- },
- { &hf_foo_priorityflag,
- { "FOO PDU Priority Flags", "foo.flags.priority",
- FT_BOOLEAN, 8, NULL, FOO_PRIORITY_FLAG,
- "", HFILL }
- },
-...
- proto_tree_add_item(foo_tree, hf_foo_flags, tvb, offset, 1, FALSE);
- proto_tree_add_item(foo_tree, hf_foo_startflag, tvb, offset, 1, FALSE);
- proto_tree_add_item(foo_tree, hf_foo_endflag, tvb, offset, 1, FALSE);
- proto_tree_add_item(foo_tree, hf_foo_priorityflag, tvb, offset, 1, FALSE); offset += 1;
-]]>
- </programlisting></example>
- <para>
- Some things to note here. For the flags, as each bit is a different flag, we use
- the type FT_BOOLEAN, as the flag is either on or off. Second, we include the flag
- mask in the 7th field of the data, which allows the system to mask the relevant bit.
- We've also changed the 5th field to 8, to indicate that we are looking at an 8 bit
- quantity when the flags are extracted. Then finally we add the extra constructs
- to the dissection routine. Note we keep the same offset for each of the flags.
- </para>
- <para>
- This is starting to look fairly full featured now, but there are a couple of other
- things we can do to make things look even more pretty. At the moment our dissection
- shows the packets as "Foo Protocol" which whilst correct is a little uninformative.
- We can enhance this by adding a little more detail.
- First, lets get hold of the actual value of the protocol type. We can use the handy
- function tvb_get_guint8 to do this.
- With this value in hand, there are a couple of things we can do.
- First we can set the INFO column of the non-detailed view to show what sort of
- PDU it is - which is extremely helpful when looking at protocol traces.
- Second, we can also display this information in the dissection window.
- </para>
- <example><title>Enhancing the display.</title>
- <programlisting>
- <![CDATA[
-static void
-dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
-{
- guint8 packet_type = tvb_get_guint8(tvb, 0);
-
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "FOO");
- /* Clear out stuff in the info column */
- if(check_col(pinfo->cinfo,COL_INFO)){
- col_clear(pinfo->cinfo,COL_INFO);
- }
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_add_fstr(pinfo->cinfo, COL_INFO, "Type %s",
- val_to_str(packet_type, packettypenames, "Unknown (0x%02x)"));
- }
-
- if (tree) { /* we are being asked for details */
- proto_item *ti = NULL;
- proto_tree *foo_tree = NULL;
- gint offset = 0;
-
- ti = proto_tree_add_item(tree, proto_foo, tvb, 0, -1, FALSE);
- proto_item_append_text(ti, ", Type %s",
- val_to_str(packet_type, packettypenames, "Unknown (0x%02x)"));
- foo_tree = proto_item_add_subtree(ti, ett_foo);
- proto_tree_add_item(foo_tree, hf_foo_pdu_type, tvb, offset, 1, FALSE); offset += 1;
-...
-]]>
- </programlisting></example>
- <para>
- So here, after grabbing the value of the first 8 bits, we use it with one of the
- built in utility routines val_to_str, to lookup the value. If the value isn't
- found we provide a fallback which just prints the value in hex.
- We use this twice, once in the INFO field of the columns - if its displayed, and
- similarly we append this data to the base of our dissecting tree.
- </para>
-
- </section>
- </section>
-
- <section id="ChDissectTransformed">
- <title>How to handle transformed data</title>
- <para>
- Some protocols do clever things with data. They might possibly
- encrypt the data, or compress data, or part of it. If you know
- how these steps are taken it is possible to reverse them within the
- dissector.
- </para>
- <para>
- As encryption can be tricky, lets consider the case of compression.
- These techniques can also work for other transformations of data,
- where some step is required before the data can be examined.
- </para>
- <para>
- What basically needs to happen here, is to identify the data that
- needs conversion, take that data and transform it into a new stream,
- and then call a dissector on it.
- Often this needs to be done "on-the-fly" based on clues in the packet.
- Sometimes this needs to be used in conjunction with other techniques,
- such as packet reassembly. The following shows a technique to
- achieve this effect.
- </para>
- <example><title>Decompressing data packets for dissection.</title>
- <programlisting>
- <![CDATA[
- guint8 flags = tvb_get_guint8(tvb, offset); offset ++;
- if (flags & FLAG_COMPRESSED) { /* the remainder of the packet is compressed */
- guint16 orig_size = tvb_get_ntohs(tvb, offset); offset += 2;
- guchar *decompressed_buffer; /* Buffers for decompression */
- decompressed_buffer = (guchar*) malloc (orig_size);
- decompress_packet (tvb_get_ptr(tvb, offset, -1), tvb_length_remaining(tvb, offset),
- decompressed_buffer, orig_size);
- /* Now re-setup the tvb buffer to have the new data */
- next_tvb = tvb_new_real_data(decompressed_buffer, orig_size, orig_size);
- tvb_set_child_real_data_tvbuff(tvb, next_tvb);
- add_new_data_source(pinfo, next_tvb, "Decompressed Data");
- tvb_set_free_cb(next_tvb, free);
- } else {
- next_tvb = tvb_new_subset(tvb, offset, -1, -1);
- }
- offset = 0;
- /* process next_tvb from here on */
-]]>
- </programlisting></example>
- <para>
- The first steps here are to recognise the compression. In this case
- a flag byte alerts us to the fact the remainder of the packet is compressed.
- Next we retrieve the original size of the packet, which in this case
- is conveniently within the protocol. If its not, it may be part of the
- compression routine to work it out for you, in which case the logic would
- be different.
- </para>
- <para>
- So armed with the size, a buffer is allocated to receive the uncompressed
- data using malloc, and the packet is decompressed into it.
- The tvb_get_ptr function is useful to get a pointer to the raw data of
- the packet from the offset onwards. In this case the
- decompression routine also needs to know the length, which is
- given by the tvb_length_remaining function.
- </para>
- <para>
- Next we build a new tvb buffer from this data, using the tvb_new_real_data
- call. This data is a child of our original data, so we acknowledge that
- in the next call to tvb_set_child_real_data_tvbuff.
- Finally we add this data as a new data source, so that
- the detailed display can show the decompressed bytes as well as the original.
- One procedural step is to add a handler to free the data when its no longer needed.
- In this case as malloc was used to allocate the memory, free is the appropriate
- function.
- </para>
- <para>
- After this has been set up the remainder of the dissector can dissect the
- buffer next_tvb, as its a new buffer the offset needs to be 0 as we start
- again from the beginning of this buffer. To make the rest of the dissector
- work regardless of whether compression was involved or not, in the case that
- compression was not signaled, we use the tvb_new_subset to deliver us
- a new buffer based on the old one but starting at the current offset, and
- extending to the end. This makes dissecting the packet from this point on
- exactly the same regardless of compression.
- </para>
- </section>
- <section id="ChDissectReassemble">
- <title>How to reassemble split packets</title>
- <para>
- Some protocols have times when they have to split a large packet across
- multiple other packets. In this case the dissection can't be carried out correctly
- until you have all the data. The first packet doesn't have enough data,
- and the subsequent packets don't have the expect format.
- To dissect these packets you need to wait until all the parts have
- arrived and then start the dissection.
- </para>
- <section id="ChDissectReassembleUdp">
- <title>How to reassemble split UDP packets</title>
- <para>
- As an example, lets examine a protocol that is layered on
- top of UDP that splits up its own data stream.
- If a packet is bigger than some given size, it will be split into
- chunks, and somehow signaled within its protocol.
- </para>
- <para>
- To deal with such streams, we need several things to trigger
- from. We need to know that this is packet is part of a multi-packet
- sequence. We need to know how many packets are in the sequence.
- We need to also know when we have all the packets.
- </para>
- <para>
- For this example we'll assume there is a simple in-protocol
- signaling mechanism to give details. A flag byte that signals
- the presence of a multi-packet and also the last packet,
- followed by an ID of the sequence,
- a packet sequence number.
- </para>
- <example><title>Reassembling fragments - Part 1</title>
- <programlisting>
- <![CDATA[
-#include <epan/reassemble.h>
- ...
-save_fragmented = pinfo->fragmented;
-flags = tvb_get_guint8(tvb, offset); offset++;
-if (flags & FL_FRAGMENT) { // fragmented
- tvbuff_t* new_tvb = NULL;
- fragment_data *frag_msg = NULL;
- guint16 msg_seqid = tvb_get_ntohs(tvb, offset); offset += 2;
- guint16 msg_num = tvb_get_ntohs(tvb, offset); offset += 2;
-
- pinfo->fragmented = TRUE;
- frag_msg = fragment_add_seq_check (tvb, offset, pinfo,
- msg_seqid, /* guint32 ID for fragments belonging together */
- msg_fragment_table, /* list of message fragments */
- msg_reassembled_table, /* list of reassembled messages */
- msg_num, /* guint32 fragment sequence number */
- -1, /* guint32 fragment length - to the end */
- flags & FL_FRAG_LAST); /* More fragments? */
-]]>
- </programlisting></example>
- <para>
- We start by saving the fragmented state of this packet, so we can restore it later.
- Next comes some protocol specific stuff, to dig the fragment data
- out of the stream if it's present. Having decided it is present, we
- let the function fragment_add_seq_check do its work.
- We need to provide this with a certain amount of data.
- </para>
- <itemizedlist>
- <listitem><para>
- The tvb buffer we are dissecting.
- </para></listitem>
- <listitem><para>
- The offset where the partial packet starts.
- </para></listitem>
- <listitem><para>
- The provided packet info.
- </para></listitem>
- <listitem><para>
- The sequence number of the fragment stream. There may be several
- streams of fragments in flight, and this is used to key the
- relevant one to be used for reassembly.
- </para></listitem>
- <listitem><para>
- The msg_fragment_table and the msg_reassembled_table are variables
- we need to declare. We'll consider these in detail later.
- </para></listitem>
- <listitem><para>
- msg_num is the packet number within the sequence.
- </para></listitem>
- <listitem><para>
- The length here is specified as -1, as we want the rest of the packet data.
- </para></listitem>
- <listitem><para>
- Finally a parameter that signals if this is the last fragment or not.
- This might be a flag as in this case, or there may be a counter in the
- protocol.
- </para></listitem>
- </itemizedlist>
- <example><title>Reassembling fragments part 2</title>
- <programlisting>
- <![CDATA[
- if (msg_tree)
- new_tvb = process_reassembled_data(tvb, offset, pinfo,
- "Reassembled Message", frag_msg, &msg_frag_items,
- NULL, msg_tree);
-
- if (frag_msg) { /* Reassembled */
- if (check_col (pinfo->cinfo, COL_INFO))
- col_append_str (pinfo->cinfo, COL_INFO,
- " (Message Reassembled)");
- } else {
- /* Not last packet of reassembled Short Message */
- if (check_col (pinfo->cinfo, COL_INFO))
- col_append_fstr (pinfo->cinfo, COL_INFO,
- " (Message fragment %u)", msg_num);
- }
- if (new_tvb) { // take it all
- next_tvb = new_tvb;
- }
- else // make a new subset
- next_tvb = tvb_new_subset(next_tvb, offset, -1, -1);
-}
-else {
- next_tvb = tvb_new_subset(next_tvb, offset, -1, -1);
-}
-
-offset = 0;
-pinfo->fragmented = save_fragmented;
- ]]>
- </programlisting></example>
- <para>
- Having passed the fragment data to the reassembly handler, we can
- now check if we have the whole message. We can only do this if were
- in the display mode, as we need to pass the display tree parameter into this
- routine. If there is enough information, this routine will return the
- newly reassembled data buffer.
- </para>
- <para>
- After that, we add a couple of informative messages to the display
- to show that this is part of a sequence. Then a bit of manipulation
- of the buffers and the dissection can proceed.
- Normally you will probably not bother dissecting further unless the
- fragments have been reassembled as there won't be much to find. Sometimes
- the first packet in the sequence can be partially decoded though if you wish.
- </para>
- <para>
- Now the mysterious data we passed into the fragment_add_seq_check.
- </para>
- <example><title>Reassembling fragments - Initialisation</title>
- <programlisting>
- <![CDATA[
-static GHashTable *msg_fragment_table = NULL;
-static GHashTable *msg_reassembled_table = NULL;
-
-
-static void
-msg_init_protocol(void)
-{
- fragment_table_init (&msg_fragment_table);
- reassembled_table_init(&msg_reassembled_table);
-}
-]]>
- </programlisting></example>
- <para>
- First a couple of hash tables are declared, and these are initialised
- in the protocol initialisation routine.
- Following that, a fragment_items structure is allocated and filled
- in with a series of ett items, hf data items, and a string tag.
- The ett and hf values should be included in the relevant tables like
- all the other variables your protocol may use. The hf variables
- need to be placed in the structure something like the following.
- Of course the names may need to be adjusted.
- </para>
- <example><title>Reassembling fragments - Data</title>
- <programlisting>
- <![CDATA[
-static const fragment_items msg_frag_items = {
- /* Fragment subtrees */
- &ett_msg_fragment,
- &ett_msg_fragments,
- /* Fragment fields */
- &hf_msg_fragments,
- &hf_msg_fragment,
- &hf_msg_fragment_overlap,
- &hf_msg_fragment_overlap_conflicts,
- &hf_msg_fragment_multiple_tails,
- &hf_msg_fragment_too_long_fragment,
- &hf_msg_fragment_error,
- /* Reassembled in field */
- &hf_msg_reassembled_in,
- /* Tag */
- "Message fragments"
-};
-...
-{&hf_msg_fragments,
- {"Message fragments", "msg.fragments",
- FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
-{&hf_msg_fragment,
- {"Message fragment", "msg.fragment",
- FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
-{&hf_msg_fragment_overlap,
- {"Message fragment overlap", "msg.fragment.overlap",
- FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
-{&hf_msg_fragment_overlap_conflicts,
- {"Message fragment overlapping with conflicting data",
- "msg.fragment.overlap.conflicts",
- FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
-{&hf_msg_fragment_multiple_tails,
- {"Message has multiple tail fragments",
- "msg.fragment.multiple_tails",
- FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
-{&hf_msg_fragment_too_long_fragment,
- {"Message fragment too long", "msg.fragment.too_long_fragment",
- FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
-{&hf_msg_fragment_error,
- {"Message defragmentation error", "msg.fragment.error",
- FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
-{&hf_msg_reassembled_in,
- {"Reassembled in", "msg.reassembled.in",
- FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
-]]>
- </programlisting></example>
- <para>
- These hf variables are used internally within the reassembly routines
- to make useful links, and to add data to the dissection. It produces
- links from one packet to another - such as a partial packet having
- a link to the fully reassembled packet. Likewise there are back pointers
- to the individual packets from the reassembled one.
- The other variables are used for flagging up errors.
- </para>
- </section>
- </section>
- <section id="ChDissectTap">
- <title>How to tap protocols</title>
- <para>
- Adding a Tap interface to a protocol allows it to do some useful things.
- In particular you can produce protocol statistics from teh tap interface.
- </para>
- <para>
- A tap is basically a way of allowing other items to see whats happening as
- a protocol is dissected. A tap is registered with the main program, and
- then called on each dissection. Some arbritary protocol specific data
- is provided with the routine that can be used.
- </para>
- <para>
- To create a tap, you first need to register a tap.
- A tap is registered with an integer handle, and registered
- with the routine register_tap. This takes a string name
- with which to find it again.
- </para>
- <example><title>Initialising a tap</title>
- <programlisting>
- <![CDATA[
-#include <epan/tap.h>
-
-static int foo_tap = -1;
-
-struct FooTap {
- gint packet_type;
- gint priorty;
- ...
-};
-...
- foo_tap = register_tap("foo");
-]]>
- </programlisting></example>
- <para>
- Whilst you can program a tap without protocol specific data, it
- is generally not very useful. Therefore its a good idea
- to declare a structure that can be passed through the tap.
- This needs to be a static structure as it will be used after the
- dissection routine has returned. Its generally best to pick out some
- generic parts of the protocol you are dissecting into the tap data.
- A packet type, a priority, a status code maybe.
- The structure really needs to be included in a header file so
- that it can be included by other components that want to listen in
- to the tap.
- </para>
- <para>
- Once you have these defined, its simply a case of populating the
- protocol specific structure and then calling tap_queue_packet probably
- as the last part of the dissector.
- </para>
- <example><title>Calling a protocol tap</title>
- <programlisting>
- <![CDATA[
- static struct FooTap pinfo;
-
- pinfo.packet_type = tvb_get_guint8(tvb, 0);
- pinfo.priority = tvb_get_ntohs(tvb, 8);
- ...
- tap_queue_packet(foo_tap, pinfo, &pinfo);
-]]>
- </programlisting></example>
- <para>
- This now enables those interested parties to listen in on the details
- of this protocol conversation.
- </para>
- </section>
- <section id="ChDissectStats">
- <title>How to produce protocol stats</title>
- <para>
- Given that you have a tap interface for the protocol, you can use this
- to produce some interesting statistics (well presumably interesting!) from
- protocol traces.
- </para>
- <para>
- This can be done in a separate plugin, or in the same plugin that is
- doing the dissection. The latter scheme is better, as the tap and stats
- module typically rely on sharing protocol specific data, which might get out
- of step between two different plugins.
- </para>
- <para>
- Here is a mechanism to produce statistics from the above TAP interface.
- </para>
- <example><title>Initialising a stats interface</title>
- <programlisting>
- <![CDATA[
-/* register all http trees */
-static void register_foo_stat_trees(void) {
- stats_tree_register("foo","foo","Foo/Packet Types",
- foo_stats_tree_packet, foo_stats_tree_init, NULL );
-}
-#ifndef ENABLE_STATIC
-//G_MODULE_EXPORT const gchar version[] = "0.0";
-
-G_MODULE_EXPORT void plugin_register_tap_listener(void)
-{
- register_foo_stat_trees();
-}
-
-#endif
-]]>
- </programlisting></example>
- <para>
- Working from the bottom up, first the plugin interface entry point is defined,
- plugin_register_tap_listener. This simply calls the initialisation function
- register_foo_stat_trees.
- </para>
- <para>
- This in turn calls the stats_tree_register function, which takes
- three strings, and three functions.
- </para>
- <orderedlist>
- <listitem><para>
- This is the tap name that is registered.
- </para></listitem>
- <listitem><para>
- An abbreviation of the stats name.
- </para></listitem>
- <listitem><para>
- The name of the stats module. A '/' character can be used to make sub menus.
- </para></listitem>
- <listitem><para>
- The function that will called to generate the stats.
- </para></listitem>
- <listitem><para>
- A function that can be called to initialise the stats data.
- </para></listitem>
- <listitem><para>
- A function that will be called to clean up the stats data.
- </para></listitem>
- </orderedlist>
- <para>
- In this case we only need the first two functions, as there is nothing specific to clean up.
- </para>
- <example><title>Initialising a stats session</title>
- <programlisting>
- <![CDATA[
-static const guint8* st_str_packets = "Total Packets";
-static const guint8* st_str_packet_types = "FOO Packet Types";
-static int st_node_packets = -1;
-static int st_node_packet_types = -1;
-
-static void foo_stats_tree_init(stats_tree* st) {
- st_node_packets = stats_tree_create_node(st, st_str_packets, 0, TRUE);
- st_node_packet_types = stats_tree_create_pivot(st, st_str_packet_types, st_node_packets);
-}
-]]>
- </programlisting></example>
- <para>
- In this case we create a new tree node, to handle the total packets,
- and as a child of that we create a pivot table to handle the stats about
- different packet types.
- </para>
- <example><title>Generating the stats</title>
- <programlisting>
- <![CDATA[
-static int foo_stats_tree_packet(stats_tree* st, packet_info* pinfo , epan_dissect_t* edt , const void* p) {
- struct FooTap *pi = (struct FooTap *)p;
- tick_stat_node(st, st_str_packets, 0, FALSE);
- stats_tree_tick_pivot(st, st_node_packet_types,
- val_to_str(pi->packet_type, msgtypevalues, "Unknown packet type (%d)"));
- return 1;
-}
-]]>
- </programlisting></example>
- <para>
- In this case the processing of the stats is quite simple.
- First we call the tick_stat_node for the st_str_packets packet node, to count
- packets.
- Then a call to stats_tree_tick_pivot on the st_node_packet_types subtree
- allows us to record statistics by packet type.
- </para>
- </section>
-
- <section id="ChDissectConversation">
- <title>How to use conversations</title>
- <para>
- Some info about how to use conversations in a dissector can be
- found in the file doc/README.developer.
- </para>
- </section>
-
-</chapter>
-<!-- End of EUG Chapter Dissection -->
+<!-- EDG Chapter Dissection -->
+<!-- $Id$ -->
+
+<chapter id="ChapterDissection">
+ <title>Packet dissection</title>
+ <!-- Julian Onions additions -->
+ <section id="ChDissectWorks">
+ <title>How it works</title>
+ <para>
+ Each dissector decodes it's part of the protocol, and then hand off
+ decoding to subsequent dissectors for an encapsulated protocol.
+ </para>
+ <para>
+ So it might all start with a Frame dissector which dissects the packet details
+ of the capture file itself (e.g. timestamps), passes the data on to an
+ Ethernet frame dissector that decodes the Ethernet header,
+ and then passes the payload to the next dissector (e.g. IP) and so on.
+ At each stage, details of the packet will be decoded and displayed.
+ </para>
+ <para>
+ Dissection can be implemented in two possible ways. One is to have a dissector
+ module compiled into the main program, which means its always available.
+ Another way is to make a plugin (a shared library/DLL) that registers itself
+ to handle dissection. - XXX add a special explanation section for this?
+ </para>
+ </section>
+
+ <section id="ChDissectAdd">
+ <title>Adding a basic dissector</title>
+ <para>
+ Lets step through adding a basic dissector. We'll start with the made up
+ "foo" protocol. It consists of the following basic items.
+ </para>
+ <itemizedlist>
+ <listitem><para>
+ A packet type - 8 bits, possible values: 1 - initialisation, 2 - terminate, 3 - data.
+ </para></listitem>
+ <listitem><para>
+ A set of flags stored in 8 bits, 0x01 - start packet, 0x02 - end packet, 0x04 - priority packet.
+ </para></listitem>
+ <listitem><para>
+ A sequence number - 16 bits.
+ </para></listitem>
+ <listitem><para>
+ An IP address.
+ </para></listitem>
+ </itemizedlist>
+ <section id="ChDissectSetup">
+ <title>Setting up the dissector</title>
+ <para>
+ The first decision you need to make is if this dissector will be a
+ built in dissector, included in the main program, or a plugin.
+ </para>
+ <para>
+ Plugins are the easiest to write initially as they don't need
+ write permission on the main code base. So lets start with that.
+ With a little care, the plugin can be made to run as a built in
+ easily too - so we haven't lost anything.
+ </para>
+ <example><title>Basic Plugin setup.</title>
+ <programlisting>
+ <![CDATA[
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gmodule.h>
+#include <epan/packet.h>
+#include <epan/prefs.h>
+
+/* forward reference */
+void proto_register_foo();
+void proto_reg_handoff_foo();
+void dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+
+/* Define version if we are not building ethereal statically */
+#ifndef ENABLE_STATIC
+G_MODULE_EXPORT const gchar version[] = "0.0";
+#endif
+
+static int proto_foo = -1;
+static int global_foo_port = 1234;
+static dissector_handle_t foo_handle;
+
+#ifndef ENABLE_STATIC
+G_MODULE_EXPORT void
+plugin_register(void)
+{
+ /* register the new protocol, protocol fields, and subtrees */
+ if (proto_foo == -1) { /* execute protocol initialization only once */
+ proto_register_foo();
+ }
+}
+
+G_MODULE_EXPORT void
+plugin_reg_handoff(void){
+ proto_reg_handoff_foo();
+}
+#endif]]>
+ </programlisting>
+ </example>
+ <para>
+ Lets go through this a bit at a time. First we have some boiler plate
+ include files. These will be pretty constant to start with. Here we also
+ pre-declare some functions that we'll be writing shortly.
+ </para>
+ <para>
+ Next we have a section surrounded by #ifdef ENABLE_STATIC. This is what
+ makes this a plugin rather than a built in dissector.
+ </para>
+ <para>
+ The version is a simple string that is used to report on the version of this
+ dissector. You should increase this number each time you make changes that you
+ need to keep track of.
+ </para>
+ <para>
+ Next we have an int that is initialised to -1 that records our protocol.
+ This will get updated when we register this plugin with the main program.
+ We can use this as a handy way to detect if we've been initialised yet.
+ Its good practice to make all variables and functions that aren't exported
+ static to keep name space pollution. Normally this isn't a problem unless your
+ dissector gets so big it has to span multiple files.
+ </para>
+ <para>
+ Then a global variable which contains the UDP port that we'll assume we are dissecting traffic for.
+ </para>
+ <para>
+ Next a dissector reference that we'll initialise later.
+ </para>
+ <para>
+ Next, the first plugin entry point. The function plugin_register() is called
+ when the plugin is loaded and allows you to do some initialisation stuff,
+ which will include communicating with the main program what you're plugins
+ capabilities are.
+ </para>
+ <para>
+ The plugin_reg_handoff routine is used when dissecting sub protocols. As our
+ hypothetical protocol will be hypothetically carried over UDP then we will
+ need to do this.
+ </para>
+ <para>
+ Now we have the basics in place to interact with the main program, we had
+ better fill in those missing functions. Lets start with register function.
+ </para>
+ <example><title>Plugin Initialisation.</title>
+ <programlisting>
+ <![CDATA[
+void
+proto_register_foo(void)
+{
+ module_t *foo_module;
+
+ if (proto_foo == -1) {
+ proto_foo = proto_register_protocol (
+ "FOO Protocol", /* name */
+ "FOO", /* short name */
+ "foo" /* abbrev */
+ );
+ }
+ foo_module = prefs_register_protocol(proto_foo, proto_reg_handoff_foo);
+}]]>
+ </programlisting></example>
+ <para>
+ First a call to proto_register_protocol that
+ registers the protocol. We can give it three names that
+ will be used in various places to display it.
+ - XXX explain where, this can be confusing
+ </para>
+ <para>
+ Then we call the preference register function. At the moment we have
+ no specific protocol preferences so this will be all that we need.
+ This takes a function parameter which is our handoff function.
+ I guess we'd better write that next.
+ </para>
+ <example><title>Plugin Handoff.</title>
+ <programlisting>
+ <![CDATA[
+void
+proto_reg_handoff_foo(void)
+{
+ static int Initialized=FALSE;
+
+ if (!Initialized) {
+ foo_handle = create_dissector_handle(dissect_foo, proto_foo);
+ dissector_add("udp.port", global_foo_port, foo_handle);
+ }
+}]]>
+ </programlisting></example>
+ <para>
+ What's happening here? We are initialising the dissector if it hasn't
+ been initialised yet.
+ First we create the dissector. This registers a routine
+ to be called to do the actual dissecting.
+ Then we associate it with a udp port number
+ so that the main program will know to call us when it gets UDP traffic on that port.
+ </para>
+ <para>
+ Now at last we finally get to write some dissecting code. For the moment we'll
+ leave it as a basic placeholder.
+ </para>
+ <example><title>Plugin Dissection.</title>
+ <programlisting>
+ <![CDATA[
+static void
+dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FOO");
+ /* Clear out stuff in the info column */
+ if(check_col(pinfo->cinfo,COL_INFO)){
+ col_clear(pinfo->cinfo,COL_INFO);
+ }
+}]]>
+ </programlisting></example>
+ <para>
+ This function is called to dissect the packets presented to it.
+ The packet data is held in a special buffer referenced here as tvb.
+ We shall become fairly familiar with this as we get deeper into the details
+ of the protocol.
+ The packet info structure contains general data about the protocol, and we
+ can update information here.
+ The tree parameter is where the detail dissection takes place.
+ </para>
+ <para>
+ For now we'll do the minimum we can get away with.
+ The first two lines check to see if the Protocol column is being displayed in
+ the UI. If it is, we set the text of this to our protocol, so everyone
+ can see its been recognised.
+ The only other thing we do is to clear out any data in the INFO column
+ if its being displayed.
+ </para>
+ <para>
+ At this point we should have a basic dissector ready to compile and install.
+ It doesn't do much at present, than identify the protocol and label it.
+ Compile the dissector to a dll or shared library, and copy it into the plugin
+ directory of the installation. To finish this off a Makefile of some sort will be
+ required. A Makefile.nmake for Windows platforms and a Makefile.am for unix/linux
+ types.
+ </para>
+
+ <example><title>Makefile.nmake for Windows.</title>
+ <programlisting>
+ <![CDATA[
+include ..\..\config.nmake
+
+############### no need to modify below this line #########
+
+CFLAGS=/DHAVE_CONFIG_H /I../.. /I../../wiretap $(GLIB_CFLAGS) \
+ /I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS)
+
+LDFLAGS = /NOLOGO /INCREMENTAL:no /MACHINE:I386 $(LOCAL_LDFLAGS)
+
+!IFDEF ENABLE_LIBETHEREAL
+LINK_PLUGIN_WITH=..\..\epan\libethereal.lib
+CFLAGS=/DHAVE_WIN32_LIBETHEREAL_LIB /D_NEED_VAR_IMPORT_ $(CFLAGS)
+
+OBJECTS=foo.obj
+
+foo.dll foo.exp foo.lib : $(OBJECTS) $(LINK_PLUGIN_WITH)
+ link -dll /out:foo.dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \
+ $(GLIB_LIBS)
+
+!ENDIF
+
+clean:
+ rm -f $(OBJECTS) foo.dll foo.exp foo.lib *.pdb
+
+distclean: clean
+
+maintainer-clean: distclean]]>
+ </programlisting></example>
+ <example><title>Makefile.am for unix/linux.</title>
+ <programlisting>
+ <![CDATA[
+INCLUDES = -I$(top_srcdir)
+
+plugindir = @plugindir@
+
+plugin_LTLIBRARIES = foo.la
+foo_la_SOURCES = foo.c moduleinfo.h
+foo_la_LDFLAGS = -module -avoid-version
+foo_la_LIBADD = @PLUGIN_LIBS@
+
+# Libs must be cleared, or else libtool won't create a shared module.
+# If your module needs to be linked against any particular libraries,
+# add them here.
+LIBS =
+
+CLEANFILES = \
+ foo \
+ *~
+
+EXTRA_DIST = \
+ Makefile.nmake
+]]>
+ </programlisting></example>
+ </section>
+
+ <section id="ChDissectDetails">
+ <title>Dissecting the details of the protocol</title>
+ <para>
+ Now we have our basic dissector up and running, lets do something with it.
+ The simplest thing to do to start with is to just label the payload.
+ This will allow us to set up some of the parts we will need.
+ </para>
+ <para>
+ The first thing we will do is to build a subtree to decode our results into.
+ This helps to keep things looking nice in the detailed display.
+ Now the dissector is called in two different cases. In one case
+ it is called to get a summary of the packet, in the other case it is
+ called to look into details of the packet. These two cases can be
+ distinguished by the tree pointer. If the tree pointer is NULL, then
+ we are being asked for a summary. If it is non null, we can pick apart
+ the protocol for display. So with that in mind, lets enhance our dissector.
+ </para>
+ <example><title>Plugin Packet Dissection.</title>
+ <programlisting>
+ <![CDATA[
+static void
+dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FOO");
+ /* Clear out stuff in the info column */
+ if(check_col(pinfo->cinfo,COL_INFO)){
+ col_clear(pinfo->cinfo,COL_INFO);
+ }
+
+ if (tree) { /* we are being asked for details */
+ proto_item *ti = NULL;
+ ti = proto_tree_add_item(tree, proto_foo, tvb, 0, -1, FALSE);
+ }
+}]]>
+ </programlisting></example>
+ <para>
+ What we're doing here is adding a subtree to the dissection.
+ This subtree will hold all the details of this protocol and so not clutter
+ up the display when not required.
+ </para>
+ <para>
+ We are also marking the area of data that is being consumed by this
+ protocol. In our cases its all that has been passed to us, as we're assuming
+ this protocol does not encapsulate another.
+ Therefore, we add the new tree node with proto_tree_add_item, adding
+ it to the passed in tree, label it with the protocol, use the passed in
+ tvb buffer as the data, and consume from 0 to the end (-1) of this data.
+ The FALSE we'll ignore for now.
+ </para>
+ <para>
+ After this change, there should be a label in the detailed display for the protocol,
+ and selecting this will highlight the remaining contents of the packet.
+ </para>
+ <para>
+ Now lets go to the next step and add some protocol dissection.
+ For this step we'll need to construct a couple of tables that help with dissection.
+ This needs some changes to proto_register_foo. First a couple of statically
+ declare arrays.
+ </para>
+ <example><title>Plugin Registering data structures.</title>
+ <programlisting>
+ <![CDATA[
+static hf_register_info hf[] = {
+ { &hf_foo_pdu_type,
+ { "FOO PDU Type", "foo.type",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "", HFILL }
+ },
+
+};
+
+
+/* Setup protocol subtree array */
+static gint *ett[] = {
+ &ett_foo,
+};
+]]>
+ </programlisting></example>
+ <para>
+ Then, after the registration code, we register these arrays.
+ </para>
+ <example><title>Plugin Registering data structures.</title>
+ <programlisting>
+ <![CDATA[
+
+ proto_register_field_array(proto_foo, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+]]>
+ </programlisting></example>
+ <para>
+ The variables hf_foo_pdu_type and ett_foo also need to be declared
+ somewhere near the top of the file.
+ </para>
+ <example><title>Plugin data structure globals.</title>
+ <programlisting>
+ <![CDATA[
+static int hf_foo_pdu_type = -1;
+
+static gint ett_foo = -1;
+]]>
+ </programlisting></example>
+ <para>
+ Now we can enhance the protocol display with some detail.
+ </para>
+ <example><title>Plugin starting to dissect the packets.</title>
+ <programlisting>
+ <![CDATA[
+ if (tree) { /* we are being asked for details */
+ proto_item *ti = NULL;
+ proto_tree *foo_tree = NULL;
+
+ ti = proto_tree_add_item(tree, proto_foo, tvb, 0, -1, FALSE);
+ foo_tree = proto_item_add_subtree(ti, ett_foo);
+ proto_tree_add_item(foo_tree, hf_foo_pdu_type, tvb, 0, 1, FALSE);
+ }
+]]>
+ </programlisting></example>
+ <para>
+ Now the dissection is starting to look more interesting. We have picked apart
+ our first bit of the protocol. One byte of data at the start of the packet
+ that defines the packet type for foo protocol.
+ </para>
+ <para>
+ The proto_item_add_subtree call has added a child node to the protocol tree
+ which is where we will do our detail dissection. The expansion of this
+ node is controlled by the ett_foo variable. This remembers if the node should
+ be expanded or not as you move between packets.
+ All subsequent dissection will be added to this tree, as you can see from the next call.
+ A call to proto_tree_add_item in the foo_tree, this time using the
+ hf_foo_pdu_type to control the formatting of the item. The pdu type
+ is one byte of data, starting at 0. We assume it is in network order,
+ so that is why we use FALSE. Although for 1 byte there is no order issues
+ its best to keep right.
+ </para>
+ <para>
+ If we look in detail at the hf_foo_pdu_type declaration in the static array
+ we can see the details of the definition.
+ </para>
+ <itemizedlist>
+ <listitem><para>
+ hf_foo_pdu_type - the index for this node.
+ </para></listitem>
+ <listitem><para>
+ FOO PDU Type - the label for this item.
+ </para></listitem>
+ <listitem><para>
+ foo.type - this is the filter string. It enables us to type constructs such
+ as foo.type=1 into the filter box.
+ </para></listitem>
+ <listitem><para>
+ FT_UNIT8 - this specifies this item is an 8bit unsigned integer.
+ This tallies with our call above where we tell it to only look at one byte.
+ </para></listitem>
+ <listitem><para>
+ BASE_DEC - for an integer type, this tells it to be printed as a decimal
+ number. It could be BASE_HEX or BASE_OCT if that made more sense.
+ </para></listitem>
+ </itemizedlist>
+ <para>
+ We'll ignore the rest of the structure for now.
+ </para>
+ <para>
+ If you install this plugin and try it out, you'll see something that begins to look
+ useful.
+ </para>
+ <para>
+ Now lets finish off dissecting the simple protocol. We need to add a few
+ more variables to the hf array, and a couple more procedure calls.
+ </para>
+ <example><title>Plugin wrapping up the packet dissection.</title>
+ <programlisting>
+ <![CDATA[
+static int hf_foo_flags = -1;
+static int hf_foo_sequenceno = -1;
+static int hf_foo_initialip = -1;
+...
+ { &hf_foo_flags,
+ { "FOO PDU Flags", "foo.flags",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "", HFILL }
+ },
+ { &hf_foo_sequenceno,
+ { "FOO PDU Sequence Number", "foo.seqn",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL }
+ },
+ { &hf_foo_initialip,
+ { "FOO PDU Initial IP", "foo.initialip",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ "", HFILL }
+ },
+...
+ gint offset = 0;
+
+ ti = proto_tree_add_item(tree, proto_foo, tvb, 0, -1, FALSE);
+ foo_tree = proto_item_add_subtree(ti, ett_foo);
+ proto_tree_add_item(foo_tree, hf_foo_pdu_type, tvb, offset, 1, FALSE); offset += 1;
+ proto_tree_add_item(foo_tree, hf_foo_flags, tvb, offset, 1, FALSE); offset += 1;
+ proto_tree_add_item(foo_tree, hf_foo_sequenceno, tvb, offset, 2, FALSE); offset += 2;
+ proto_tree_add_item(foo_tree, hf_foo_initialip, tvb, offset, 4, FALSE); offset += 4;
+
+]]>
+ </programlisting></example>
+ <para>
+ This dissects all the bits of this simple hypothetical protocol. We've introduced a new
+ variable offset into the mix to help keep track of where we are in the packet dissection.
+ With these extra bits in place, the whole protocol is now dissected.
+ </para>
+ </section>
+ <section><title>Improving the dissection information</title>
+ <para>
+ We can certainly improve the display of the proto with a bit of extra data.
+ The first step is to add some text labels. Lets start by labelling the packet types.
+ There is some useful support for this sort of thing by adding a couple of extra things.
+ First we add a simple table of type to name.
+ </para>
+ <example><title>Naming the packet types.</title>
+ <programlisting>
+ <![CDATA[
+static const value_string packettypenames[] = {
+ { 1, "Initialise" },
+ { 2, "Terminate" },
+ { 3, "Data" },
+ { 0, NULL },
+};
+]]>
+ </programlisting></example>
+ <para>
+ This is a handy data structure that can be used to look up value to names.
+ There are routines to directly access this lookup table, but we don't need to
+ do that, as the support code already has that added in. We just have to give
+ these details to the appropriate part of data, using the VALS macro.
+ </para>
+ <example><title>Adding Names to the protocol.</title>
+ <programlisting>
+ <![CDATA[
+ { &hf_foo_pdu_type,
+ { "FOO PDU Type", "foo.type",
+ FT_UINT8, BASE_DEC, VALS(packettypenames), 0x0,
+ "", HFILL }
+ },
+]]>
+ </programlisting></example>
+ <para>
+ This helps in deciphering the packets, and we can do a similar thing for the
+ flags structure. For this we need to add some more data to the table though.
+ </para>
+ <example><title>Adding Flags to the protocol.</title>
+ <programlisting>
+ <![CDATA[
+#define FOO_START_FLAG 0x01
+#define FOO_END_FLAG 0x02
+#define FOO_PRIORITY_FLAG 0x04
+
+static int hf_foo_startflag = -1;
+static int hf_foo_endflag = -1;
+static int hf_foo_priorityflag = -1;
+...
+ { &hf_foo_startflag,
+ { "FOO PDU Start Flags", "foo.flags.start",
+ FT_BOOLEAN, 8, NULL, FOO_START_FLAG,
+ "", HFILL }
+ },
+ { &hf_foo_endflag,
+ { "FOO PDU End Flags", "foo.flags.end",
+ FT_BOOLEAN, 8, NULL, FOO_END_FLAG,
+ "", HFILL }
+ },
+ { &hf_foo_priorityflag,
+ { "FOO PDU Priority Flags", "foo.flags.priority",
+ FT_BOOLEAN, 8, NULL, FOO_PRIORITY_FLAG,
+ "", HFILL }
+ },
+...
+ proto_tree_add_item(foo_tree, hf_foo_flags, tvb, offset, 1, FALSE);
+ proto_tree_add_item(foo_tree, hf_foo_startflag, tvb, offset, 1, FALSE);
+ proto_tree_add_item(foo_tree, hf_foo_endflag, tvb, offset, 1, FALSE);
+ proto_tree_add_item(foo_tree, hf_foo_priorityflag, tvb, offset, 1, FALSE); offset += 1;
+]]>
+ </programlisting></example>
+ <para>
+ Some things to note here. For the flags, as each bit is a different flag, we use
+ the type FT_BOOLEAN, as the flag is either on or off. Second, we include the flag
+ mask in the 7th field of the data, which allows the system to mask the relevant bit.
+ We've also changed the 5th field to 8, to indicate that we are looking at an 8 bit
+ quantity when the flags are extracted. Then finally we add the extra constructs
+ to the dissection routine. Note we keep the same offset for each of the flags.
+ </para>
+ <para>
+ This is starting to look fairly full featured now, but there are a couple of other
+ things we can do to make things look even more pretty. At the moment our dissection
+ shows the packets as "Foo Protocol" which whilst correct is a little uninformative.
+ We can enhance this by adding a little more detail.
+ First, lets get hold of the actual value of the protocol type. We can use the handy
+ function tvb_get_guint8 to do this.
+ With this value in hand, there are a couple of things we can do.
+ First we can set the INFO column of the non-detailed view to show what sort of
+ PDU it is - which is extremely helpful when looking at protocol traces.
+ Second, we can also display this information in the dissection window.
+ </para>
+ <example><title>Enhancing the display.</title>
+ <programlisting>
+ <![CDATA[
+static void
+dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ guint8 packet_type = tvb_get_guint8(tvb, 0);
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FOO");
+ /* Clear out stuff in the info column */
+ if(check_col(pinfo->cinfo,COL_INFO)){
+ col_clear(pinfo->cinfo,COL_INFO);
+ }
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Type %s",
+ val_to_str(packet_type, packettypenames, "Unknown (0x%02x)"));
+ }
+
+ if (tree) { /* we are being asked for details */
+ proto_item *ti = NULL;
+ proto_tree *foo_tree = NULL;
+ gint offset = 0;
+
+ ti = proto_tree_add_item(tree, proto_foo, tvb, 0, -1, FALSE);
+ proto_item_append_text(ti, ", Type %s",
+ val_to_str(packet_type, packettypenames, "Unknown (0x%02x)"));
+ foo_tree = proto_item_add_subtree(ti, ett_foo);
+ proto_tree_add_item(foo_tree, hf_foo_pdu_type, tvb, offset, 1, FALSE); offset += 1;
+...
+]]>
+ </programlisting></example>
+ <para>
+ So here, after grabbing the value of the first 8 bits, we use it with one of the
+ built in utility routines val_to_str, to lookup the value. If the value isn't
+ found we provide a fallback which just prints the value in hex.
+ We use this twice, once in the INFO field of the columns - if its displayed, and
+ similarly we append this data to the base of our dissecting tree.
+ </para>
+
+ </section>
+ </section>
+
+ <section id="ChDissectTransformed">
+ <title>How to handle transformed data</title>
+ <para>
+ Some protocols do clever things with data. They might possibly
+ encrypt the data, or compress data, or part of it. If you know
+ how these steps are taken it is possible to reverse them within the
+ dissector.
+ </para>
+ <para>
+ As encryption can be tricky, lets consider the case of compression.
+ These techniques can also work for other transformations of data,
+ where some step is required before the data can be examined.
+ </para>
+ <para>
+ What basically needs to happen here, is to identify the data that
+ needs conversion, take that data and transform it into a new stream,
+ and then call a dissector on it.
+ Often this needs to be done "on-the-fly" based on clues in the packet.
+ Sometimes this needs to be used in conjunction with other techniques,
+ such as packet reassembly. The following shows a technique to
+ achieve this effect.
+ </para>
+ <example><title>Decompressing data packets for dissection.</title>
+ <programlisting>
+ <![CDATA[
+ guint8 flags = tvb_get_guint8(tvb, offset); offset ++;
+ if (flags & FLAG_COMPRESSED) { /* the remainder of the packet is compressed */
+ guint16 orig_size = tvb_get_ntohs(tvb, offset); offset += 2;
+ guchar *decompressed_buffer; /* Buffers for decompression */
+ decompressed_buffer = (guchar*) malloc (orig_size);
+ decompress_packet (tvb_get_ptr(tvb, offset, -1), tvb_length_remaining(tvb, offset),
+ decompressed_buffer, orig_size);
+ /* Now re-setup the tvb buffer to have the new data */
+ next_tvb = tvb_new_real_data(decompressed_buffer, orig_size, orig_size);
+ tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+ add_new_data_source(pinfo, next_tvb, "Decompressed Data");
+ tvb_set_free_cb(next_tvb, free);
+ } else {
+ next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+ }
+ offset = 0;
+ /* process next_tvb from here on */
+]]>
+ </programlisting></example>
+ <para>
+ The first steps here are to recognise the compression. In this case
+ a flag byte alerts us to the fact the remainder of the packet is compressed.
+ Next we retrieve the original size of the packet, which in this case
+ is conveniently within the protocol. If its not, it may be part of the
+ compression routine to work it out for you, in which case the logic would
+ be different.
+ </para>
+ <para>
+ So armed with the size, a buffer is allocated to receive the uncompressed
+ data using malloc, and the packet is decompressed into it.
+ The tvb_get_ptr function is useful to get a pointer to the raw data of
+ the packet from the offset onwards. In this case the
+ decompression routine also needs to know the length, which is
+ given by the tvb_length_remaining function.
+ </para>
+ <para>
+ Next we build a new tvb buffer from this data, using the tvb_new_real_data
+ call. This data is a child of our original data, so we acknowledge that
+ in the next call to tvb_set_child_real_data_tvbuff.
+ Finally we add this data as a new data source, so that
+ the detailed display can show the decompressed bytes as well as the original.
+ One procedural step is to add a handler to free the data when its no longer needed.
+ In this case as malloc was used to allocate the memory, free is the appropriate
+ function.
+ </para>
+ <para>
+ After this has been set up the remainder of the dissector can dissect the
+ buffer next_tvb, as its a new buffer the offset needs to be 0 as we start
+ again from the beginning of this buffer. To make the rest of the dissector
+ work regardless of whether compression was involved or not, in the case that
+ compression was not signaled, we use the tvb_new_subset to deliver us
+ a new buffer based on the old one but starting at the current offset, and
+ extending to the end. This makes dissecting the packet from this point on
+ exactly the same regardless of compression.
+ </para>
+ </section>
+ <section id="ChDissectReassemble">
+ <title>How to reassemble split packets</title>
+ <para>
+ Some protocols have times when they have to split a large packet across
+ multiple other packets. In this case the dissection can't be carried out correctly
+ until you have all the data. The first packet doesn't have enough data,
+ and the subsequent packets don't have the expect format.
+ To dissect these packets you need to wait until all the parts have
+ arrived and then start the dissection.
+ </para>
+ <section id="ChDissectReassembleUdp">
+ <title>How to reassemble split UDP packets</title>
+ <para>
+ As an example, lets examine a protocol that is layered on
+ top of UDP that splits up its own data stream.
+ If a packet is bigger than some given size, it will be split into
+ chunks, and somehow signaled within its protocol.
+ </para>
+ <para>
+ To deal with such streams, we need several things to trigger
+ from. We need to know that this is packet is part of a multi-packet
+ sequence. We need to know how many packets are in the sequence.
+ We need to also know when we have all the packets.
+ </para>
+ <para>
+ For this example we'll assume there is a simple in-protocol
+ signaling mechanism to give details. A flag byte that signals
+ the presence of a multi-packet and also the last packet,
+ followed by an ID of the sequence,
+ a packet sequence number.
+ </para>
+ <example><title>Reassembling fragments - Part 1</title>
+ <programlisting>
+ <![CDATA[
+#include <epan/reassemble.h>
+ ...
+save_fragmented = pinfo->fragmented;
+flags = tvb_get_guint8(tvb, offset); offset++;
+if (flags & FL_FRAGMENT) { // fragmented
+ tvbuff_t* new_tvb = NULL;
+ fragment_data *frag_msg = NULL;
+ guint16 msg_seqid = tvb_get_ntohs(tvb, offset); offset += 2;
+ guint16 msg_num = tvb_get_ntohs(tvb, offset); offset += 2;
+
+ pinfo->fragmented = TRUE;
+ frag_msg = fragment_add_seq_check (tvb, offset, pinfo,
+ msg_seqid, /* guint32 ID for fragments belonging together */
+ msg_fragment_table, /* list of message fragments */
+ msg_reassembled_table, /* list of reassembled messages */
+ msg_num, /* guint32 fragment sequence number */
+ -1, /* guint32 fragment length - to the end */
+ flags & FL_FRAG_LAST); /* More fragments? */
+]]>
+ </programlisting></example>
+ <para>
+ We start by saving the fragmented state of this packet, so we can restore it later.
+ Next comes some protocol specific stuff, to dig the fragment data
+ out of the stream if it's present. Having decided it is present, we
+ let the function fragment_add_seq_check do its work.
+ We need to provide this with a certain amount of data.
+ </para>
+ <itemizedlist>
+ <listitem><para>
+ The tvb buffer we are dissecting.
+ </para></listitem>
+ <listitem><para>
+ The offset where the partial packet starts.
+ </para></listitem>
+ <listitem><para>
+ The provided packet info.
+ </para></listitem>
+ <listitem><para>
+ The sequence number of the fragment stream. There may be several
+ streams of fragments in flight, and this is used to key the
+ relevant one to be used for reassembly.
+ </para></listitem>
+ <listitem><para>
+ The msg_fragment_table and the msg_reassembled_table are variables
+ we need to declare. We'll consider these in detail later.
+ </para></listitem>
+ <listitem><para>
+ msg_num is the packet number within the sequence.
+ </para></listitem>
+ <listitem><para>
+ The length here is specified as -1, as we want the rest of the packet data.
+ </para></listitem>
+ <listitem><para>
+ Finally a parameter that signals if this is the last fragment or not.
+ This might be a flag as in this case, or there may be a counter in the
+ protocol.
+ </para></listitem>
+ </itemizedlist>
+ <example><title>Reassembling fragments part 2</title>
+ <programlisting>
+ <![CDATA[
+ if (msg_tree)
+ new_tvb = process_reassembled_data(tvb, offset, pinfo,
+ "Reassembled Message", frag_msg, &msg_frag_items,
+ NULL, msg_tree);
+
+ if (frag_msg) { /* Reassembled */
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_str (pinfo->cinfo, COL_INFO,
+ " (Message Reassembled)");
+ } else {
+ /* Not last packet of reassembled Short Message */
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr (pinfo->cinfo, COL_INFO,
+ " (Message fragment %u)", msg_num);
+ }
+ if (new_tvb) { // take it all
+ next_tvb = new_tvb;
+ }
+ else // make a new subset
+ next_tvb = tvb_new_subset(next_tvb, offset, -1, -1);
+}
+else {
+ next_tvb = tvb_new_subset(next_tvb, offset, -1, -1);
+}
+
+offset = 0;
+pinfo->fragmented = save_fragmented;
+ ]]>
+ </programlisting></example>
+ <para>
+ Having passed the fragment data to the reassembly handler, we can
+ now check if we have the whole message. We can only do this if were
+ in the display mode, as we need to pass the display tree parameter into this
+ routine. If there is enough information, this routine will return the
+ newly reassembled data buffer.
+ </para>
+ <para>
+ After that, we add a couple of informative messages to the display
+ to show that this is part of a sequence. Then a bit of manipulation
+ of the buffers and the dissection can proceed.
+ Normally you will probably not bother dissecting further unless the
+ fragments have been reassembled as there won't be much to find. Sometimes
+ the first packet in the sequence can be partially decoded though if you wish.
+ </para>
+ <para>
+ Now the mysterious data we passed into the fragment_add_seq_check.
+ </para>
+ <example><title>Reassembling fragments - Initialisation</title>
+ <programlisting>
+ <![CDATA[
+static GHashTable *msg_fragment_table = NULL;
+static GHashTable *msg_reassembled_table = NULL;
+
+
+static void
+msg_init_protocol(void)
+{
+ fragment_table_init (&msg_fragment_table);
+ reassembled_table_init(&msg_reassembled_table);
+}
+]]>
+ </programlisting></example>
+ <para>
+ First a couple of hash tables are declared, and these are initialised
+ in the protocol initialisation routine.
+ Following that, a fragment_items structure is allocated and filled
+ in with a series of ett items, hf data items, and a string tag.
+ The ett and hf values should be included in the relevant tables like
+ all the other variables your protocol may use. The hf variables
+ need to be placed in the structure something like the following.
+ Of course the names may need to be adjusted.
+ </para>
+ <example><title>Reassembling fragments - Data</title>
+ <programlisting>
+ <![CDATA[
+static const fragment_items msg_frag_items = {
+ /* Fragment subtrees */
+ &ett_msg_fragment,
+ &ett_msg_fragments,
+ /* Fragment fields */
+ &hf_msg_fragments,
+ &hf_msg_fragment,
+ &hf_msg_fragment_overlap,
+ &hf_msg_fragment_overlap_conflicts,
+ &hf_msg_fragment_multiple_tails,
+ &hf_msg_fragment_too_long_fragment,
+ &hf_msg_fragment_error,
+ /* Reassembled in field */
+ &hf_msg_reassembled_in,
+ /* Tag */
+ "Message fragments"
+};
+...
+{&hf_msg_fragments,
+ {"Message fragments", "msg.fragments",
+ FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+{&hf_msg_fragment,
+ {"Message fragment", "msg.fragment",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+{&hf_msg_fragment_overlap,
+ {"Message fragment overlap", "msg.fragment.overlap",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+{&hf_msg_fragment_overlap_conflicts,
+ {"Message fragment overlapping with conflicting data",
+ "msg.fragment.overlap.conflicts",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+{&hf_msg_fragment_multiple_tails,
+ {"Message has multiple tail fragments",
+ "msg.fragment.multiple_tails",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+{&hf_msg_fragment_too_long_fragment,
+ {"Message fragment too long", "msg.fragment.too_long_fragment",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+{&hf_msg_fragment_error,
+ {"Message defragmentation error", "msg.fragment.error",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+{&hf_msg_reassembled_in,
+ {"Reassembled in", "msg.reassembled.in",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
+]]>
+ </programlisting></example>
+ <para>
+ These hf variables are used internally within the reassembly routines
+ to make useful links, and to add data to the dissection. It produces
+ links from one packet to another - such as a partial packet having
+ a link to the fully reassembled packet. Likewise there are back pointers
+ to the individual packets from the reassembled one.
+ The other variables are used for flagging up errors.
+ </para>
+ </section>
+ </section>
+ <section id="ChDissectTap">
+ <title>How to tap protocols</title>
+ <para>
+ Adding a Tap interface to a protocol allows it to do some useful things.
+ In particular you can produce protocol statistics from teh tap interface.
+ </para>
+ <para>
+ A tap is basically a way of allowing other items to see whats happening as
+ a protocol is dissected. A tap is registered with the main program, and
+ then called on each dissection. Some arbritary protocol specific data
+ is provided with the routine that can be used.
+ </para>
+ <para>
+ To create a tap, you first need to register a tap.
+ A tap is registered with an integer handle, and registered
+ with the routine register_tap. This takes a string name
+ with which to find it again.
+ </para>
+ <example><title>Initialising a tap</title>
+ <programlisting>
+ <![CDATA[
+#include <epan/tap.h>
+
+static int foo_tap = -1;
+
+struct FooTap {
+ gint packet_type;
+ gint priorty;
+ ...
+};
+...
+ foo_tap = register_tap("foo");
+]]>
+ </programlisting></example>
+ <para>
+ Whilst you can program a tap without protocol specific data, it
+ is generally not very useful. Therefore its a good idea
+ to declare a structure that can be passed through the tap.
+ This needs to be a static structure as it will be used after the
+ dissection routine has returned. Its generally best to pick out some
+ generic parts of the protocol you are dissecting into the tap data.
+ A packet type, a priority, a status code maybe.
+ The structure really needs to be included in a header file so
+ that it can be included by other components that want to listen in
+ to the tap.
+ </para>
+ <para>
+ Once you have these defined, its simply a case of populating the
+ protocol specific structure and then calling tap_queue_packet probably
+ as the last part of the dissector.
+ </para>
+ <example><title>Calling a protocol tap</title>
+ <programlisting>
+ <![CDATA[
+ static struct FooTap pinfo;
+
+ pinfo.packet_type = tvb_get_guint8(tvb, 0);
+ pinfo.priority = tvb_get_ntohs(tvb, 8);
+ ...
+ tap_queue_packet(foo_tap, pinfo, &pinfo);
+]]>
+ </programlisting></example>
+ <para>
+ This now enables those interested parties to listen in on the details
+ of this protocol conversation.
+ </para>
+ </section>
+ <section id="ChDissectStats">
+ <title>How to produce protocol stats</title>
+ <para>
+ Given that you have a tap interface for the protocol, you can use this
+ to produce some interesting statistics (well presumably interesting!) from
+ protocol traces.
+ </para>
+ <para>
+ This can be done in a separate plugin, or in the same plugin that is
+ doing the dissection. The latter scheme is better, as the tap and stats
+ module typically rely on sharing protocol specific data, which might get out
+ of step between two different plugins.
+ </para>
+ <para>
+ Here is a mechanism to produce statistics from the above TAP interface.
+ </para>
+ <example><title>Initialising a stats interface</title>
+ <programlisting>
+ <![CDATA[
+/* register all http trees */
+static void register_foo_stat_trees(void) {
+ stats_tree_register("foo","foo","Foo/Packet Types",
+ foo_stats_tree_packet, foo_stats_tree_init, NULL );
+}
+#ifndef ENABLE_STATIC
+//G_MODULE_EXPORT const gchar version[] = "0.0";
+
+G_MODULE_EXPORT void plugin_register_tap_listener(void)
+{
+ register_foo_stat_trees();
+}
+
+#endif
+]]>
+ </programlisting></example>
+ <para>
+ Working from the bottom up, first the plugin interface entry point is defined,
+ plugin_register_tap_listener. This simply calls the initialisation function
+ register_foo_stat_trees.
+ </para>
+ <para>
+ This in turn calls the stats_tree_register function, which takes
+ three strings, and three functions.
+ </para>
+ <orderedlist>
+ <listitem><para>
+ This is the tap name that is registered.
+ </para></listitem>
+ <listitem><para>
+ An abbreviation of the stats name.
+ </para></listitem>
+ <listitem><para>
+ The name of the stats module. A '/' character can be used to make sub menus.
+ </para></listitem>
+ <listitem><para>
+ The function that will called to generate the stats.
+ </para></listitem>
+ <listitem><para>
+ A function that can be called to initialise the stats data.
+ </para></listitem>
+ <listitem><para>
+ A function that will be called to clean up the stats data.
+ </para></listitem>
+ </orderedlist>
+ <para>
+ In this case we only need the first two functions, as there is nothing specific to clean up.
+ </para>
+ <example><title>Initialising a stats session</title>
+ <programlisting>
+ <![CDATA[
+static const guint8* st_str_packets = "Total Packets";
+static const guint8* st_str_packet_types = "FOO Packet Types";
+static int st_node_packets = -1;
+static int st_node_packet_types = -1;
+
+static void foo_stats_tree_init(stats_tree* st) {
+ st_node_packets = stats_tree_create_node(st, st_str_packets, 0, TRUE);
+ st_node_packet_types = stats_tree_create_pivot(st, st_str_packet_types, st_node_packets);
+}
+]]>
+ </programlisting></example>
+ <para>
+ In this case we create a new tree node, to handle the total packets,
+ and as a child of that we create a pivot table to handle the stats about
+ different packet types.
+ </para>
+ <example><title>Generating the stats</title>
+ <programlisting>
+ <![CDATA[
+static int foo_stats_tree_packet(stats_tree* st, packet_info* pinfo , epan_dissect_t* edt , const void* p) {
+ struct FooTap *pi = (struct FooTap *)p;
+ tick_stat_node(st, st_str_packets, 0, FALSE);
+ stats_tree_tick_pivot(st, st_node_packet_types,
+ val_to_str(pi->packet_type, msgtypevalues, "Unknown packet type (%d)"));
+ return 1;
+}
+]]>
+ </programlisting></example>
+ <para>
+ In this case the processing of the stats is quite simple.
+ First we call the tick_stat_node for the st_str_packets packet node, to count
+ packets.
+ Then a call to stats_tree_tick_pivot on the st_node_packet_types subtree
+ allows us to record statistics by packet type.
+ </para>
+ </section>
+
+ <section id="ChDissectConversation">
+ <title>How to use conversations</title>
+ <para>
+ Some info about how to use conversations in a dissector can be
+ found in the file doc/README.developer.
+ </para>
+ </section>
+
+</chapter>
+<!-- End of EUG Chapter Dissection -->
diff --git a/docbook/edg_src/EDG_chapter_works.xml b/docbook/edg_src/EDG_chapter_works.xml
index f01673f553..48d78a8baa 100644
--- a/docbook/edg_src/EDG_chapter_works.xml
+++ b/docbook/edg_src/EDG_chapter_works.xml
@@ -1,154 +1,154 @@
-<!-- EDG Chapter Works -->
-<!-- $Id: EDG_chapter_works.xml 11908 2004-09-05 21:22:14Z ulfl $ -->
-
-<chapter id="ChapterWorks">
- <title>How Ethereal Works</title>
-
- <section id="ChWorksIntro">
- <title>Introduction</title>
- <para>
- This chapter will give you a short overview, how Ethereal is working.
- </para>
- </section>
-
- <section id="ChWorksOverview">
- <title>Overview</title>
- <para>
- The following will give you a simplified overview of Ethereals function blocks:
- <figure id="ChWorksFigOverview">
- <title>
- <application>Ethereal</application> function blocks.
- </title>
- <graphic entityref="EtherealFunctionBlocks" format="PNG"/>
- </figure>
- </para>
- <para>
- The function blocks in more detail:
- <variablelist>
- <varlistentry><term><command>GTK 1/2</command></term>
- <listitem>
- <para>
- Handling of all user input/output (all windows, dialogs and such).
- Source code can be found in the <filename>gtk</filename> directory.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry><term><command>Core</command></term>
- <listitem>
- <para>
- Main "glue code" that holds the other blocks together, source
- code can be found in the root directory.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry><term><command>Epan</command></term>
- <listitem>
- <para>
- Ethereal Package ANalyzing (XXX - is this correct?) the packet
- analyzing engine, source code can be found in the
- <filename>epan</filename> directory.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Protocol-Tree - Keep data of the capture file protocol information.
- </para>
- </listitem>
- <listitem>
- <para>
- Dissectors - The various protocol dissectors in
- <filename>epan/dissectors</filename>.
- </para>
- </listitem>
- <listitem>
- <para>
- Plugins - Some of the protocol dissectors are implemented as plugins, source
- code at <filename>plugins</filename>.
- </para>
- </listitem>
- <listitem>
- <para>
- Display-Filters - the display filter engine at
- <filename>epan/dfilter</filename>.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </varlistentry>
- <varlistentry><term><command>Capture</command></term>
- <listitem>
- <para>
- Capture engine.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry><term><command>Wiretap</command></term>
- <listitem>
- <para>
- The wiretap library is used to read/write capture files in libpcap
- and a lot of other file formats, the source code is in the
- <filename>wiretap</filename> directory.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><command>Win-/libpcap (not part of the Ethereal package)</command></term>
- <listitem>
- <para>
- The platform dependant packet capture library, including the capture
- filter engine. That's the reason why we still have different display
- and capture filter syntax, as two different filtering engines used.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </para>
- </section>
-
- <section id="ChWorksCapturePackets">
- <title>Capturing packets</title>
- <para>
- Capturing will take packets from a network adapter, and save them to a file
- on your harddisk.
- </para>
- <para>
- To hide all the lowlevel machine dependant details from
- Ethereal, the libpcap/WinPcap (see <xref linkend="ChLibsPcap"/>) library
- is used. This library provides a general purpose interface to capture
- packets from a lot of different network interface types (Ethernet,
- Token Ring, ...).
- </para>
- </section>
-
- <section id="ChWorksCaptureFiles">
- <title>Capture Files</title>
- <para>
- Ethereal can read and write capture files in it's natural file format, the
- libpcap format, which is used by many other network capturing tools,
- e.g. tcpdump. In addition to this, as one of it's strengths,
- Ethereal can read/write files in many different file formats of other
- network capturing tools. The wiretap library, developed together with
- Ethereal, provides a general purpose interface to read/write all the file
- formats. If you need to add another capture file format, this is the place
- to start.
- </para>
- </section>
-
- <section id="ChWorksDissectPackets">
- <title>Dissect packets</title>
- <para>
- While Ethereal is loading packets from a file, each packet is dissected.
- Ethereal tries to detect what kind of packet it is and getting as much
- information from it as possible. In this run, only the information showed
- in the packet list pane is needed though.
- </para>
- <para>
- As the user selects a specific packet in the packet list pane, this packet
- will be dissected again. This time, Ethereal tries to
- get every single piece of information and put it into
- the packet details pane then.
- </para>
- </section>
-
-</chapter>
-<!-- End of EUG Chapter Works -->
+<!-- EDG Chapter Works -->
+<!-- $Id$ -->
+
+<chapter id="ChapterWorks">
+ <title>How Ethereal Works</title>
+
+ <section id="ChWorksIntro">
+ <title>Introduction</title>
+ <para>
+ This chapter will give you a short overview, how Ethereal is working.
+ </para>
+ </section>
+
+ <section id="ChWorksOverview">
+ <title>Overview</title>
+ <para>
+ The following will give you a simplified overview of Ethereals function blocks:
+ <figure id="ChWorksFigOverview">
+ <title>
+ <application>Ethereal</application> function blocks.
+ </title>
+ <graphic entityref="EtherealFunctionBlocks" format="PNG"/>
+ </figure>
+ </para>
+ <para>
+ The function blocks in more detail:
+ <variablelist>
+ <varlistentry><term><command>GTK 1/2</command></term>
+ <listitem>
+ <para>
+ Handling of all user input/output (all windows, dialogs and such).
+ Source code can be found in the <filename>gtk</filename> directory.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><command>Core</command></term>
+ <listitem>
+ <para>
+ Main "glue code" that holds the other blocks together, source
+ code can be found in the root directory.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><command>Epan</command></term>
+ <listitem>
+ <para>
+ Ethereal Package ANalyzing (XXX - is this correct?) the packet
+ analyzing engine, source code can be found in the
+ <filename>epan</filename> directory.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Protocol-Tree - Keep data of the capture file protocol information.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Dissectors - The various protocol dissectors in
+ <filename>epan/dissectors</filename>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Plugins - Some of the protocol dissectors are implemented as plugins, source
+ code at <filename>plugins</filename>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Display-Filters - the display filter engine at
+ <filename>epan/dfilter</filename>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><command>Capture</command></term>
+ <listitem>
+ <para>
+ Capture engine.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><command>Wiretap</command></term>
+ <listitem>
+ <para>
+ The wiretap library is used to read/write capture files in libpcap
+ and a lot of other file formats, the source code is in the
+ <filename>wiretap</filename> directory.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><command>Win-/libpcap (not part of the Ethereal package)</command></term>
+ <listitem>
+ <para>
+ The platform dependant packet capture library, including the capture
+ filter engine. That's the reason why we still have different display
+ and capture filter syntax, as two different filtering engines used.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </section>
+
+ <section id="ChWorksCapturePackets">
+ <title>Capturing packets</title>
+ <para>
+ Capturing will take packets from a network adapter, and save them to a file
+ on your harddisk.
+ </para>
+ <para>
+ To hide all the lowlevel machine dependant details from
+ Ethereal, the libpcap/WinPcap (see <xref linkend="ChLibsPcap"/>) library
+ is used. This library provides a general purpose interface to capture
+ packets from a lot of different network interface types (Ethernet,
+ Token Ring, ...).
+ </para>
+ </section>
+
+ <section id="ChWorksCaptureFiles">
+ <title>Capture Files</title>
+ <para>
+ Ethereal can read and write capture files in it's natural file format, the
+ libpcap format, which is used by many other network capturing tools,
+ e.g. tcpdump. In addition to this, as one of it's strengths,
+ Ethereal can read/write files in many different file formats of other
+ network capturing tools. The wiretap library, developed together with
+ Ethereal, provides a general purpose interface to read/write all the file
+ formats. If you need to add another capture file format, this is the place
+ to start.
+ </para>
+ </section>
+
+ <section id="ChWorksDissectPackets">
+ <title>Dissect packets</title>
+ <para>
+ While Ethereal is loading packets from a file, each packet is dissected.
+ Ethereal tries to detect what kind of packet it is and getting as much
+ information from it as possible. In this run, only the information showed
+ in the packet list pane is needed though.
+ </para>
+ <para>
+ As the user selects a specific packet in the packet list pane, this packet
+ will be dissected again. This time, Ethereal tries to
+ get every single piece of information and put it into
+ the packet details pane then.
+ </para>
+ </section>
+
+</chapter>
+<!-- End of EUG Chapter Works -->
diff --git a/docbook/release-notes.xml b/docbook/release-notes.xml
index c8a1c53b0b..11d87f00c3 100644
--- a/docbook/release-notes.xml
+++ b/docbook/release-notes.xml
@@ -2,7 +2,7 @@
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
-<!-- $Id: user-guide.xml 15094 2005-07-26 18:01:25Z ulfl $ -->
+<!-- $Id$ -->
<!--
DOCUMENT SECTION