5 It is often useful to enhance dissectors for request/response style protocols
6 to match requests with responses.
7 This allows you to display useful information in the decode tree such as which
8 requests are matched to which response and the response time for individual
11 This is also useful if you want to pass some data from the request onto the
12 dissection of the actual response. The RPC dissector for example does
13 something like this to pass the actual command opcode from the request onto
14 the response dissector since the opcode itself is not part of the response
15 packet and without the opcode we would not know how to decode the data.
17 It is also useful when you need to track information on a per conversation
18 basis such as when some parameters are negotiated during a login phase of the
19 protocol and when these parameters affect how future commands on that session
20 are to be decoded. The iSCSI dissector does something similar to that to track
21 which sessions that HeaderDigest is activated for and which ones it is not.
25 The example below shows how simple this is to add to the dissector IF:
26 1. there is something like a transaction id in the header,
27 2. it is very unlikely that the transaction identifier is reused for the
30 The example is taken from the PANA dissector:
32 First we need to include the definitions for conversations and memory
35 #include <epan/conversation.h>
36 #include <epan/wmem/wmem.h>
38 Then we also need a few header fields to show the relations between request
39 and response as well as the response time.
41 static int hf_pana_response_in = -1;
42 static int hf_pana_response_to = -1;
43 static int hf_pana_response_time = -1;
45 We need a structure that holds all the information we need to remember
46 between the request and the responses. One such structure will be allocated
47 for each unique transaction.
48 In the example we only keep the frame numbers of the request and the response
49 as well as the timestamp for the request.
50 But since this structure is persistent and also a unique one is allocated for
51 each request/response pair, this is a good place to store other additional
52 data you may want to keep track of from a request to a response.
54 typedef struct _pana_transaction_t {
60 We also need a structure that holds persistent information for each
61 conversation. A conversation is identified by SRC/DST address, protocol and
62 SRC/DST port, see README.developer.
63 In this case we only want to have a binary tree to track the actual
64 transactions that occur for this unique conversation.
65 Some protocols negotiate session parameters during a login phase and those
66 parameters may affect how later commands on the same session is to be decoded,
67 this would be a good place to store that additional info you may want to keep
70 typedef struct _pana_conv_info_t {
74 Finally for the meat of it, add the conversation and tracking code to the
79 conversation_t *conversation;
80 pana_conv_info_t *pana_info;
81 pana_transaction_t *pana_trans;
84 /* Get the transaction identifier */
85 seq_num = tvb_get_ntohl(tvb, 8);
89 * We need to track some state for this protocol on a per conversation
90 * basis so we can do neat things like request/response tracking
92 conversation = find_or_create_conversation(pinfo);
95 * Do we already have a state structure for this conv
97 pana_info = conversation_get_proto_data(conversation, proto_pana);
100 * No. Attach that information to the conversation, and add
101 * it to the list of information structures.
103 pana_info = wmem_new(wmem_file_scope(), pana_conv_info_t);
104 pana_info->pdus=wmem_tree_new(wmem_file_scope());
106 conversation_add_proto_data(conversation, proto_pana, pana_info);
108 if (!pinfo->fd->flags.visited) {
109 if (flags&PANA_FLAG_R) {
110 /* This is a request */
111 pana_trans=wmem_new(wmem_file_scope(), pana_transaction_t);
112 pana_trans->req_frame = pinfo->fd->num;
113 pana_trans->rep_frame = 0;
114 pana_trans->req_time = pinfo->fd->abs_ts;
115 wmem_tree_insert32(pana_info->pdus, seq_num, (void *)pana_trans);
117 pana_trans=(pana_transaction_t *)wmem_tree_lookup32(pana_info->pdus, seq_num);
119 pana_trans->rep_frame = pinfo->fd->num;
123 pana_trans=(pana_transaction_t *)wmem_tree_lookup32(pana_info->pdus, seq_num);
126 /* create a "fake" pana_trans structure */
127 pana_trans=wmem_new(wmem_packet_scope(), pana_transaction_t);
128 pana_trans->req_frame = 0;
129 pana_trans->rep_frame = 0;
130 pana_trans->req_time = pinfo->fd->abs_ts;
133 /* print state tracking in the tree */
134 if (flags&PANA_FLAG_R) {
135 /* This is a request */
136 if (pana_trans->rep_frame) {
139 it = proto_tree_add_uint(pana_tree, hf_pana_response_in,
140 tvb, 0, 0, pana_trans->rep_frame);
141 PROTO_ITEM_SET_GENERATED(it);
144 /* This is a reply */
145 if (pana_trans->req_frame) {
149 it = proto_tree_add_uint(pana_tree, hf_pana_response_to,
150 tvb, 0, 0, pana_trans->req_frame);
151 PROTO_ITEM_SET_GENERATED(it);
153 nstime_delta(&ns, &pinfo->fd->abs_ts, &pana_trans->req_time);
154 it = proto_tree_add_time(pana_tree, hf_pana_response_time, tvb, 0, 0, &ns);
155 PROTO_ITEM_SET_GENERATED(it);
159 Then we just need to declare the hf fields we used.
161 { &hf_pana_response_in,
162 { "Response In", "pana.response_in",
163 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
164 "The response to this PANA request is in this frame", HFILL }
166 { &hf_pana_response_to,
167 { "Request In", "pana.response_to",
168 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
169 "This is a response to the PANA request in this frame", HFILL }
171 { &hf_pana_response_time,
172 { "Response Time", "pana.response_time",
173 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
174 "The time between the Call and the Reply", HFILL }