-$Id: README.tapping,v 1.4 2002/11/28 20:29:46 guy Exp $
+$Id$
-The TAP system in ethereal is a powerful and flexible mechanism to get event
+The TAP system in Wireshark is a powerful and flexible mechanism to get event
driven notification on packets matching certain protocols and/or filters.
-In order to use the tapping system, very little knowledge of ethereal
+In order to use the tapping system, very little knowledge of Wireshark
internals are required.
-As examples on how to use the tap system see the implementation of
-tap-rpcstat.c (tethereal version)
-gtk2/gtk2-rpcstat.c (gtk2-ethereal version)
+As examples on how to use the tap system see the implementation of
+tap-rpcstat.c (tshark version)
+gtk/rpc_stat.c (gtk-wireshark version)
+If all you need is to keep some counters, there's the stats_tree API,
+which offers a simple way to make a GUI and tshark tap-listener; see
+README.stats_tree. However, keep reading, as you'll need much of what's
+in this document.
The tap system consists of two parts:
1, code in the actual dissectors to allow tapping data from that particular
First you must decide which protocol you are interested in writing a tap
application for and check if that protocol has already got a tap installed
in it.
-If it already has a tap device installed then you dont have to do anything.
-If not, then you have to add a tap but dont worry, this is extremely easy to
+If it already has a tap device installed then you don't have to do anything.
+If not, then you have to add a tap but don't worry, this is extremely easy to
do and is done in four easy steps;
(see packet-rpc.c and search for tap for an example)
-1, We need tap.h so just add '#include "tap.h"' to the includes.
+1, We need tap.h so just add '#include "tap.h"' (preceded by packet.h) to
+the includes.
2, We need a tap handler so just add 'static int <protocol>_tap = -1;'
4, In the actual dissector for that protocol, after any child dissectors
have returned, just add 'tap_queue_packet(<protocol>_tap, pinfo, <pointer>);'
-<pointer> is used if the tap has any special additional data to provide to
-the tap listeners. What this points to is dependant on the protocol that
-is tapped, or if there are no useful extra data to provide just specify NULL.
-For packet-rpc.c what we specify there is the persistant structure 'rpc_call'
-which contains lots of useful information the rpc layer that a listener might
+<pointer> is used if the tap has any special additional data to provide to the
+tap listeners. What this points to is dependent on the protocol that is tapped,
+or if there are no useful extra data to provide just specify NULL. For
+packet-rpc.c what we specify there is the persistent structure 'rpc_call' which
+contains lots of useful information from the rpc layer that a listener might
need.
The two functions to start or stop tapping are
-register_tap_listener(char *tapname, void *tapdata, char *fstring,
+register_tap_listener(const char *tapname, void *tapdata, const char *fstring,
+ guint flags,
void (*reset)(void *tapdata),
- int (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, void *<pointer>),
- void (*draw)(void *tapdata),
+ gboolean (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data),
+ void (*draw)(void *tapdata));
remove_tap_listener(void *tapdata);
register_tap_listener() is used to register an instance of a tap application
to the tap system.
-*tapname
+*tapname
is the name of the tap we want to listen to. I.e. the name used in
step 3 above.
-*tapdata
+*tapdata
is the instance identifier. The tap system uses the value of this
pointer to distinguish between different instances of a tap.
Just make sure that it is unique by letting it be the pointer to a struct
g_malloc() and use that pointer.
(tap-rpcstat.c use this technique to allow multiple simultaneous instances)
-*fstring
-is a pointer to a filter string.
+*fstring
+is a pointer to a filter string.
If this is NULL, then the tap system will provide ALL packets passing the
tapped protocol to your listener.
If you specify a filter string here the tap system will first try
The syntax for the filter string is identical to normal display filters.
NOTE: Specifying filter strings will have a significant performance impact
-on your application and ethereal. If possible it is MUCH better to take
+on your application and Wireshark. If possible it is MUCH better to take
unfiltered data and just filter it yourself in the packet-callback than
to specify a filter string.
ONLY use a filter string if no other option exist.
+flags
+is a set of flags for the tap listener. The flags that can be set are:
+
+ TL_REQUIRES_PROTO_TREE
+
+ set if your tap listener "packet" routine requires a protocol
+ tree to be built. It will require a protocol tree to be
+ built if either
+
+ 1) it looks at the protocol tree in edt->tree
+
+ or
+
+ 2) the tap-specific data passed to it is constructed only if
+ the protocol tree is being built.
+
+ TL_REQUIRES_COLUMNS
+
+ set if your tap listener "packet" routine requires the column
+ strings to be constructed.
+
+ If no flags are needed, use TL_REQUIRES_NOTHING.
+
void (*reset)(void *tapdata)
-This callback is called whenever ethereal wants to inform your
+This callback is called whenever Wireshark wants to inform your
listener that it is about to start [re]reading a capture file or a new capture
from an interface and that your application should reset any state it has
in the *tapdata instance.
-int (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, void *data)
+gboolean (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data)
This callback is used whenever a new packet has arrived at the tap and that
it has passed the filter (if there were a filter).
The *data structure type is specific to each tap.
-This function returns an int and it should return
- 1, if the data in the packet aused state to be updated
- (asnd thus a redraw of the window would later be required)
- 0, if we dont need to redraw the window.
+This function returns an gboolean and it should return
+ TRUE, if the data in the packet caused state to be updated
+ (and thus a redraw of the window would later be required)
+ FALSE, if we don't need to redraw the window.
NOTE: that (*packet) should be as fast and efficient as possible. Use this
-function ONLY to store data for later and do the cpu-intensive processing
+function ONLY to store data for later and do the CPU-intensive processing
or GUI updates down in (*draw) instead.
-
+
void (*draw)(void *tapdata)
-This callback is used when ethereal wants your application to redraw its
+This callback is used when Wireshark wants your application to redraw its
output. It will usually not be called unless your application has received
new data through the (*packet) callback.
-On some ports of ethereal (gtk2) (*draw) will be called asynchronously
+On some ports of Wireshark (gtk2) (*draw) will be called asynchronously
from a separate thread up to once every 2-3 seconds.
On other ports it might only be called once when the capture is finished
or the file has been [re]read completely.
2, packet to update these state variables.
3, draw to take these state variables and draw them on the screen.
-then just make ethereal call register_tap_listener() when you want to tap
+then just make Wireshark call register_tap_listener() when you want to tap
and call remove_tap_listener() when you are finished.
+WHEN DO TAP LISTENERS GET CALLED?
+===================================
+Tap listeners are only called when Wireshark reads a new capture for
+the first time or whenever Wireshark needs to rescan/redissect
+the capture.
+Redissection occurs when you apply a new display filter or if you
+change and Save/Apply a preference setting that might affect how
+packets are dissected.
+After each individual packet has been completely dissected and all
+dissectors have returned, all the tap listeners that have been flagged
+to receive tap data during the dissection of the frame will be called in
+sequence.
+The order in which the tap listeners will be called is not defined.
+Not until all tap listeners for the frame has been called and returned
+will Wireshark continue to dissect the next packet.
+This is why it is important to make the *_packet() callbacks execute as
+quickly as possible, else we create an extra delay until the next packet
+is dissected.
+
+Keep in mind though: for some protocols, such as IP, the protocol can
+appear multiple times in different layers inside the same packet.
+For example, IP encapsulated over IP which will call the ip dissector
+twice for the same packet.
+IF the tap is going to return private data using the last parameter to
+tap_queue_packet() and IF the protocol can appear multiple times inside the
+same packet, you will have to make sure that each instance of
+tap_queue_packet() is using its own instance of private struct variable
+so they don't overwrite each other.
+
+See packet-ip.c which has a simple solution to the problem. It creates
+a unique instance of the IP header using ep_alloc().
+Previous versions used a static struct of 4 instances of the IP header
+struct and cycled through them each time the dissector was called. (4
+was just a number taken out of the blue but it should be enough for most
+cases.) This would fail if there were more than 4 IP headers in the same
+packet, but that was unlikely.
TIPS
====
Of course, there is nothing that forces you to make (*draw) draw stuff
-on the screen.
+on the screen.
You can hand register_tap_listener() NULL for both (*draw) and (*reset)
(well also for (*packet) but that would be a very boring extension).
Perhaps you want an extension that will execute a certain command
-everytime it sees a certain packet?
+every time it sees a certain packet?
Well, try this :
int packet(void *tapdata,...) {
...
register_tap_listener("tcp", struct, "tcp.port==57", NULL, packet, NULL);
Let struct contain an email address?
- Then you have something simple that will make ethereal send an email
- out automagically for each and every time it dissects
+ Then you have something simple that will make Wireshark send an email
+ out automagically for each and every time it dissects
a packet containing TCP traffic to port 57.
Please put in some rate limitation if you do this.
See tap-rpcstat.c for an example
-See tap.c as well. It contains lots of comments and descriptions on the tap
+See tap.c as well. It contains lots of comments and descriptions on the tap
system.