HTTPS (almost) everywhere.
[metze/wireshark/wip.git] / plugins / epan / transum / packet-transum.c
1 /* packet-transum.c
2  * Routines for the TRANSUM response time analyzer post-dissector
3  * By Paul Offord <paul.offord@advance7.com>
4  * Copyright 2016 Advance Seven Limited
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later
11  */
12
13 /* ToDo: Test handling of multiple SMB2 messages within a packet */
14 /* ToDo: Rework the Summarizer code (future release) */
15
16 #include "config.h"
17
18 #include <epan/proto.h>
19 #include <epan/packet.h>
20 #include <epan/prefs.h>
21 #include <wsutil/ws_printf.h>
22 #include "packet-transum.h"
23 #include "preferences.h"
24 #include "extractors.h"
25 #include "decoders.h"
26
27 void proto_register_transum(void);
28 void proto_reg_handoff_transum(void);
29
30 static dissector_handle_t transum_handle;
31
32 #define CAPTURE_CLIENT 0
33 #define CAPTURE_INTERMEDIATE 1
34 #define CAPTURE_SERVICE 2
35
36 #define RTE_TIME_SEC  1
37 #define RTE_TIME_MSEC 1000
38 #define RTE_TIME_USEC 1000000
39
40 /* The following are the field ids for the protocol values used by TRANSUM.
41     Make sure they line up with ehf_of_interest order */
42 HF_OF_INTEREST_INFO hf_of_interest[HF_INTEREST_END_OF_LIST] = {
43     { -1, "ip.proto" },
44     { -1, "ipv6.nxt" },
45
46     { -1, "tcp.analysis.retransmission" },
47     { -1, "tcp.analysis.keep_alive" },
48     { -1, "tcp.flags.syn" },
49     { -1, "tcp.flags.ack" },
50     { -1, "tcp.flags.reset" },
51     { -1, "tcp.flags.urg" },
52     { -1, "tcp.seq" },
53     { -1, "tcp.srcport" },
54     { -1, "tcp.dstport" },
55     { -1, "tcp.stream" },
56     { -1, "tcp.len" },
57
58     { -1, "udp.srcport" },
59     { -1, "udp.dstport" },
60     { -1, "udp.stream" },
61     { -1, "udp.length" },
62
63     { -1, "tls.record.content_type" },
64
65     { -1, "tds.type" },
66     { -1, "tds.length" },
67
68     { -1, "smb.mid" },
69
70     { -1, "smb2.sesid" },
71     { -1, "smb2.msg_id" },
72     { -1, "smb2.cmd" },
73
74     { -1, "dcerpc.ver" },
75     { -1, "dcerpc.pkt_type" },
76     { -1, "dcerpc.cn_call_id" },
77     { -1, "dcerpc.cn_ctx_id" },
78
79     { -1, "dns.id"},
80 };
81
82
83 static range_t *tcp_svc_port_range_values;
84
85 static range_t *udp_svc_port_range_values;
86
87 TSUM_PREFERENCES preferences;
88
89
90 static wmem_map_t *detected_tcp_svc;  /* this array is used to track services detected during the syn/syn-ack process */
91
92 static wmem_map_t *dcerpc_req_pkt_type;  /* used to indicate if a DCE-RPC pkt_type is a request */
93
94 static wmem_map_t *dcerpc_streams = NULL;  /* used to record TCP stream numbers that are carrying DCE-RPC data */
95
96 /*
97 This array contains calls and returns that have no TRUE context_id
98 This is needed to overcome an apparent bug in Wireshark where
99 the field name of context id in parameters is the same as context id
100 in a message header
101 */
102 static wmem_map_t *dcerpc_context_zero;
103
104 /*
105     The rrpd_list holds information about all of the APDU Request-Response Pairs seen in the trace.
106  */
107 static wmem_list_t *rrpd_list = NULL;
108
109 /*
110     output_rrpd is a hash of pointers to RRPDs on the rrpd_list.  The index is the frame number.  This hash is
111     used during Wireshark's second scan.  As each packet is processed, TRANSUM uses the packet's frame number to index into
112     this hash to determine if we have RTE data for this particular packet, and if so the write_rte function is called.
113  */
114 static wmem_map_t *output_rrpd;
115
116 /*
117     The temp_rsp_rrpd_list holds RRPDs for APDUs where we have not yet seen the header information and so we can't
118     fully qualify the identification of the RRPD (the identification being ip_proto:stream_no:session_id:msg_id).
119     This only occurs when a) we are using one of the decode_based calculations (such as SMB2), and b) when we have
120     TCP Reassembly enabled.  Once we receive a header packet for an APDU we migrate the entry from this array to the
121     main rrpd_list.
122  */
123 static wmem_list_t *temp_rsp_rrpd_list = NULL;  /* Reuse these for speed and efficient memory use - issue a warning if we run out */
124
125 /* Optimisation data - the following is used for various optimisation measures */
126 static int highest_tcp_stream_no;
127 static int highest_udp_stream_no;
128 wmem_map_t *tcp_stream_exceptions;
129
130
131 static gint ett_transum = -1;
132 static gint ett_transum_header = -1;
133 static gint ett_transum_data = -1;
134
135 static int proto_transum = -1;
136
137 static int hf_tsum_status = -1;
138 //static int hf_tsum_time_units = -1;
139 static int hf_tsum_req_first_seg = -1;
140 static int hf_tsum_req_last_seg = -1;
141 static int hf_tsum_rsp_first_seg = -1;
142 static int hf_tsum_rsp_last_seg = -1;
143 static int hf_tsum_apdu_rsp_time = -1;
144 static int hf_tsum_service_time = -1;
145 static int hf_tsum_req_spread = -1;
146 static int hf_tsum_rsp_spread = -1;
147 static int hf_tsum_clip_filter = -1;
148 static int hf_tsum_calculation = -1;
149 static int hf_tsum_summary = -1;
150 static int hf_tsum_req_search = -1;
151 static int hf_tsum_rsp_search = -1;
152
153 static const enum_val_t capture_position_vals[] = {
154     { "TRACE_CAP_CLIENT", "Client", TRACE_CAP_CLIENT },
155     { "TRACE_CAP_INTERMEDIATE", "Intermediate", TRACE_CAP_INTERMEDIATE },
156     { "TRACE_CAP_SERVICE", "Service", TRACE_CAP_SERVICE },
157     { NULL, NULL, 0}
158 };
159
160 static const value_string rrdp_calculation_vals[] = {
161    { RTE_CALC_GTCP,       "Generic TCP"  },
162    { RTE_CALC_SYN,        "SYN and SYN/ACK" },
163    { RTE_CALC_DCERPC,     "DCE-RPC" },
164    { RTE_CALC_SMB2,       "SMB2" },
165    { RTE_CALC_GUDP,       "Generic UDP" },
166    { RTE_CALC_DNS,        "DNS" },
167
168    { 0,        NULL }
169 };
170
171 /*static const enum_val_t time_multiplier_vals[] = {
172     { "RTE_TIME_SEC", "seconds", RTE_TIME_SEC },
173     { "RTE_TIME_MSEC", "milliseconds", RTE_TIME_MSEC },
174     { "RTE_TIME_USEC", "microseconds", RTE_TIME_USEC },
175     { NULL, NULL, 0}
176 };*/
177
178 void add_detected_tcp_svc(guint16 port)
179 {
180     wmem_map_insert(detected_tcp_svc, GUINT_TO_POINTER(port), GUINT_TO_POINTER(port));
181 }
182
183
184 static void init_dcerpc_data(void)
185 {
186     wmem_map_insert(dcerpc_req_pkt_type, GUINT_TO_POINTER(0), GUINT_TO_POINTER(1));
187     wmem_map_insert(dcerpc_req_pkt_type, GUINT_TO_POINTER(11), GUINT_TO_POINTER(1));
188     wmem_map_insert(dcerpc_req_pkt_type, GUINT_TO_POINTER(14), GUINT_TO_POINTER(1));
189
190     wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(11), GUINT_TO_POINTER(11));
191     wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(12), GUINT_TO_POINTER(12));
192     wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(14), GUINT_TO_POINTER(14));
193     wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(15), GUINT_TO_POINTER(15));
194 }
195
196 static void register_dcerpc_stream(guint32 stream_no)
197 {
198     wmem_map_insert(dcerpc_streams, GUINT_TO_POINTER(stream_no), GUINT_TO_POINTER(1));
199 }
200
201 /* This function should be called before any change to RTE data. */
202 static void null_output_rrpd_entries(RRPD *in_rrpd)
203 {
204     wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_first_frame));
205     wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_last_frame));
206     wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_first_frame));
207     wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_last_frame));
208 }
209
210 /* This function should be called after any change to RTE data. */
211 static void update_output_rrpd(RRPD *in_rrpd)
212 {
213     if (preferences.rte_on_first_req)
214         wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_first_frame), in_rrpd);
215
216     if (preferences.rte_on_last_req)
217         wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_last_frame), in_rrpd);
218
219     if (preferences.rte_on_first_rsp)
220         wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_first_frame), in_rrpd);
221
222     if (preferences.rte_on_last_rsp)
223         wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_last_frame), in_rrpd);
224 }
225
226 /* Return the index of the RRPD that has been appended */
227 static RRPD* append_to_rrpd_list(RRPD *in_rrpd)
228 {
229     RRPD *next_rrpd = (RRPD*)wmem_memdup(wmem_file_scope(), in_rrpd, sizeof(RRPD));
230
231     update_output_rrpd(next_rrpd);
232
233     wmem_list_append(rrpd_list, next_rrpd);
234
235     return next_rrpd;
236 }
237
238 static RRPD *find_latest_rrpd_dcerpc(RRPD *in_rrpd)
239 {
240     RRPD *rrpd;
241     wmem_list_frame_t* i;
242
243     for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
244     {
245         rrpd = (RRPD*)wmem_list_frame_data(i);
246
247         if (rrpd->calculation != RTE_CALC_DCERPC && rrpd->calculation != RTE_CALC_SYN)
248             continue;
249
250         /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
251         if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
252         {
253             /* if we can match on session_id and msg_id must be a retransmission of the last request packet or the response */
254             /* this logic works whether or not we are using reassembly */
255             if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id)
256                 return rrpd;
257
258             /* If this is a retransmission, we assume it relates to this rrpd_list entry.
259                This is a bit of a kludge and not ideal but a compromise.*/
260             /* ToDo: look at using TCP sequence number to allocate a retransmission to the correct APDU */
261             if (in_rrpd->is_retrans)
262                 return rrpd;
263
264             if (preferences.reassembly)
265             {
266                 if (in_rrpd->c2s)
267                 {
268                     /* if the input rrpd is for c2s and the one we have found already has response information, then the
269                     in_rrpd represents a new RR Pair. */
270                     if (rrpd->rsp_first_frame)
271                         return NULL;
272
273                     /* If the current rrpd_list entry doesn't have a msg_id then we assume we are mid Request APDU and so we have a match. */
274                     if (!rrpd->msg_id)
275                         return rrpd;
276                 }
277                 else  /* The in_rrpd relates to a packet going s2c */
278                 {
279                     /* When reassembly is enabled, multi-packet response information is actually migrated from the temp_rsp_rrpd_list
280                     to the rrpd_list and so we won't come through here. */
281                     ;
282                 }
283             }
284             else /* we are not using reassembly */
285             {
286                 if (in_rrpd->c2s)
287                 {
288                     if (in_rrpd->msg_id)
289                         /* if we have a message id this is a new Request APDU */
290                         return NULL;
291                     else  /* No msg_id */
292                     {
293                         return rrpd;  /* add this packet to the matching stream */
294                     }
295                 }
296                 else  /* this packet is going s2c */
297                 {
298                     if (!in_rrpd->msg_id && rrpd->rsp_first_frame)
299                         /* we need to add this frame to the response APDU of the most recent rrpd_list entry that has already had response packets */
300                         return rrpd;
301                 }
302             }
303         }  /* this is the end of the 5-tuple check */
304
305         if (in_rrpd->c2s)
306             in_rrpd->req_search_total++;
307         else
308             in_rrpd->rsp_search_total++;
309     } /* end of the for loop */
310
311     return NULL;
312 }
313
314 static RRPD *find_latest_rrpd_dns(RRPD *in_rrpd)
315 {
316     RRPD *rrpd;
317     wmem_list_frame_t* i;
318
319     for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
320     {
321         rrpd = (RRPD*)wmem_list_frame_data(i);
322
323         if (rrpd->calculation != RTE_CALC_DNS)
324             continue;
325
326         /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
327         if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
328         {
329             if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id)
330             {
331                 if (in_rrpd->c2s && rrpd->rsp_first_frame)
332                     return NULL;  /* this is new */
333                 else
334                     return rrpd;
335             }
336         }  /* this is the end of the 5-tuple check */
337
338         if (in_rrpd->c2s)
339             in_rrpd->req_search_total++;
340         else
341             in_rrpd->rsp_search_total++;
342     } /* this is the end of the for loop */
343
344     return NULL;
345 }
346
347 static RRPD *find_latest_rrpd_gtcp(RRPD *in_rrpd)
348 {
349     RRPD *rrpd;
350     wmem_list_frame_t* i;
351
352     for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
353     {
354         rrpd = (RRPD*)wmem_list_frame_data(i);
355
356         if (rrpd->calculation != RTE_CALC_GTCP && rrpd->calculation != RTE_CALC_SYN)
357             continue;
358
359         /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
360         if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
361         {
362             if (in_rrpd->c2s && rrpd->rsp_first_frame)
363                 return NULL;  /* this is new */
364             else
365                 return rrpd;
366         }  /* this is the end of the 5-tuple check */
367
368         if (in_rrpd->c2s)
369             in_rrpd->req_search_total++;
370         else
371             in_rrpd->rsp_search_total++;
372     } /* this is the end of the for loop */
373
374     return NULL;
375 }
376
377 static RRPD *find_latest_rrpd_gudp(RRPD *in_rrpd)
378 {
379     RRPD *rrpd;
380     wmem_list_frame_t* i;
381
382     for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
383     {
384         rrpd = (RRPD*)wmem_list_frame_data(i);
385
386         if (rrpd->calculation != RTE_CALC_GUDP)
387             continue;
388
389         /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
390         if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
391         {
392             if (in_rrpd->c2s && rrpd->rsp_first_frame)
393                 return NULL;  /* this is new */
394             else
395                 return rrpd;
396         }  /* this is the end of the 5-tuple check */
397
398         if (in_rrpd->c2s)
399             in_rrpd->req_search_total++;
400         else
401             in_rrpd->rsp_search_total++;
402     } /* this is the end of the for loop */
403
404     return NULL;
405 }
406
407 static RRPD *find_latest_rrpd_smb2(RRPD *in_rrpd)
408 {
409     RRPD *rrpd;
410     wmem_list_frame_t* i;
411
412     for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
413     {
414         rrpd = (RRPD*)wmem_list_frame_data(i);
415
416         if (rrpd->calculation != RTE_CALC_SMB2 && rrpd->calculation != RTE_CALC_SYN)
417             continue;
418
419         /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
420         if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
421         {
422             /* if we can match on session_id and msg_id must be a retransmission of the last request packet or the response */
423             /* this logic works whether or not we are using reassembly */
424             if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id)
425                 return rrpd;
426
427             /* If this is a retransmission, we assume it relates to this rrpd_list entry.
428             This is a bit of a kludge and not ideal but a compromise.*/
429             /* ToDo: look at using TCP sequence number to allocate a retransmission to the correct APDU */
430             if (in_rrpd->is_retrans)
431                 return rrpd;
432
433             if (preferences.reassembly)
434             {
435                 if (in_rrpd->c2s)
436                 {
437                     /* if the input rrpd is for c2s and the one we have found already has response information, then the
438                     in_rrpd represents a new RR Pair. */
439                     if (rrpd->rsp_first_frame)
440                         return NULL;
441
442                     /* If the current rrpd_list entry doesn't have a msg_id then we assume we are mid Request APDU and so we have a match. */
443                     if (!rrpd->msg_id)
444                         return rrpd;
445                 }
446                 else  /* The in_rrpd relates to a packet going s2c */
447                 {
448                     /* When reassembly is enabled, multi-packet response information is actually migrated from the temp_rsp_rrpd_list
449                     to the rrpd_list and so we won't come through here. */
450                     ;
451                 }
452             }
453             else /* we are not using reassembly */
454             {
455                 if (in_rrpd->c2s)
456                 {
457                     if (in_rrpd->msg_id)
458                         /* if we have a message id this is a new Request APDU */
459                         return NULL;
460                     else  /* No msg_id */
461                     {
462                         return rrpd;  /* add this packet to the matching stream */
463                     }
464                 }
465                 else  /* this packet is going s2c */
466                 {
467                     if (!in_rrpd->msg_id && rrpd->rsp_first_frame)
468                         /* we need to add this frame to the response APDU of the most recent rrpd_list entry that has already had response packets */
469                         return rrpd;
470                 }
471             }
472         }  /* this is the end of the 5-tuple check */
473
474         if (in_rrpd->c2s)
475             in_rrpd->req_search_total++;
476         else
477             in_rrpd->rsp_search_total++;
478     } /* end of the for loop */
479
480     return NULL;
481 }
482
483 static RRPD *find_latest_rrpd_syn(RRPD *in_rrpd)
484 {
485     RRPD *rrpd;
486     wmem_list_frame_t* i;
487
488     for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
489     {
490         rrpd = (RRPD*)wmem_list_frame_data(i);
491
492         if (rrpd->calculation != RTE_CALC_SYN)
493             continue;
494
495         /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
496         if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
497         {
498             return rrpd;
499         }  /* this is the end of the 5-tuple check */
500
501         if (in_rrpd->c2s)
502             in_rrpd->req_search_total++;
503         else
504             in_rrpd->rsp_search_total++;
505     } /* this is the end of the for loop */
506
507     return NULL;
508 }
509
510 static RRPD *find_latest_rrpd(RRPD *in_rrpd)
511 {
512     /* Optimisation Code */
513     if (in_rrpd->ip_proto == IP_PROTO_TCP && (int)in_rrpd->stream_no > highest_tcp_stream_no)
514     {
515         highest_tcp_stream_no = in_rrpd->stream_no;
516         return NULL;
517     }
518     else if (in_rrpd->ip_proto == IP_PROTO_UDP && (int)in_rrpd->stream_no > highest_udp_stream_no)
519     {
520         highest_udp_stream_no = in_rrpd->stream_no;
521         return NULL;
522     }
523     /* End of Optimisation Code */
524
525     switch (in_rrpd->calculation)
526     {
527     case RTE_CALC_DCERPC:
528         return find_latest_rrpd_dcerpc(in_rrpd);
529         break;
530
531     case RTE_CALC_DNS:
532         return find_latest_rrpd_dns(in_rrpd);
533         break;
534
535     case RTE_CALC_GTCP:
536         return find_latest_rrpd_gtcp(in_rrpd);
537         break;
538
539     case RTE_CALC_GUDP:
540         return find_latest_rrpd_gudp(in_rrpd);
541         break;
542
543     case RTE_CALC_SMB2:
544         return find_latest_rrpd_smb2(in_rrpd);
545         break;
546
547     case RTE_CALC_SYN:
548         return find_latest_rrpd_syn(in_rrpd);
549         break;
550     }
551
552     return NULL;
553 }
554
555 static void update_rrpd_list_entry(RRPD *match, RRPD *in_rrpd)
556 {
557     null_output_rrpd_entries(match);
558
559     if (preferences.debug_enabled)
560     {
561         match->req_search_total += in_rrpd->req_search_total;
562         match->rsp_search_total += in_rrpd->rsp_search_total;
563     }
564
565     if (in_rrpd->c2s)
566     {
567         match->req_last_frame = in_rrpd->req_last_frame;
568         match->req_last_rtime = in_rrpd->req_last_rtime;
569         if (in_rrpd->msg_id)
570         {
571             match->session_id = in_rrpd->session_id;
572             match->msg_id = in_rrpd->msg_id;
573         }
574     }
575     else
576     {
577         if (!match->rsp_first_frame)
578         {
579             match->rsp_first_frame = in_rrpd->rsp_first_frame;
580             match->rsp_first_rtime = in_rrpd->rsp_first_rtime;
581         }
582         match->rsp_last_frame = in_rrpd->rsp_last_frame;
583         match->rsp_last_rtime = in_rrpd->rsp_last_rtime;
584     }
585
586     update_output_rrpd(match);
587 }
588
589 /*
590     This function processes a sub-packet that is going from client-to-service.
591  */
592 static void update_rrpd_list_entry_req(RRPD *in_rrpd)
593 {
594     RRPD *match;
595
596     match = find_latest_rrpd(in_rrpd);
597
598     if (match != NULL)
599         update_rrpd_list_entry(match, in_rrpd);
600     else
601         append_to_rrpd_list(in_rrpd);
602 }
603
604 /*
605     This function inserts an RRPD into the temp_rsp_rrpd_list.  If this is
606     successful return a pointer to the entry, else return NULL.
607  */
608 static RRPD* insert_into_temp_rsp_rrpd_list(RRPD *in_rrpd)
609 {
610     RRPD *rrpd = (RRPD*)wmem_memdup(wmem_file_scope(), in_rrpd, sizeof(RRPD));
611
612     wmem_list_append(temp_rsp_rrpd_list, rrpd);
613
614     return rrpd;
615 }
616
617 static RRPD* find_temp_rsp_rrpd(RRPD *in_rrpd)
618 {
619     wmem_list_frame_t *i;
620     RRPD* rrpd;
621
622     for (i = wmem_list_head(temp_rsp_rrpd_list); i; i = wmem_list_frame_next(i))
623     {
624         rrpd = (RRPD*)wmem_list_frame_data(i);
625         if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
626             return rrpd;
627     }
628
629     return NULL;
630 }
631
632 static void update_temp_rsp_rrpd(RRPD *temp_list, RRPD *in_rrpd)
633 {
634     temp_list->rsp_last_frame = in_rrpd->rsp_last_frame;
635     temp_list->rsp_last_rtime = in_rrpd->rsp_last_rtime;
636 }
637
638 /* This function migrates an entry from the temp_rsp_rrpd_list to the main rrpd_list. */
639 static void migrate_temp_rsp_rrpd(RRPD *main_list, RRPD *temp_list)
640 {
641     update_rrpd_list_entry(main_list, temp_list);
642
643     wmem_list_remove(temp_rsp_rrpd_list, temp_list);
644 }
645
646 static void update_rrpd_list_entry_rsp(RRPD *in_rrpd)
647 {
648     RRPD *match, *temp_list;
649
650     if (in_rrpd->decode_based)
651     {
652         if (preferences.reassembly)
653         {
654             if (in_rrpd->msg_id)
655             {
656                 /* If we have a msg_id in the input RRPD we must have header information. */
657                 temp_list = find_temp_rsp_rrpd(in_rrpd);
658
659                 if (temp_list != NULL)
660                 {
661                     update_temp_rsp_rrpd(temp_list, in_rrpd);
662
663                     /* Migrate the temp_rsp_rrpd_list entry to the main rrpd_list */
664                     match = find_latest_rrpd(in_rrpd);
665                     if (match != NULL)
666                         migrate_temp_rsp_rrpd(match, temp_list);
667                 }
668                 else
669                 {
670                     match = find_latest_rrpd(in_rrpd);
671                     /* There isn't an entry in the temp_rsp_rrpd_list so update the master rrpd_list entry */
672                     if (match != NULL)
673                         update_rrpd_list_entry(match, in_rrpd);
674                 }
675             }
676             else
677             {
678                 /* Update an existing entry to the temp_rsp_rrpd_list or add a new one. */
679                 temp_list = find_temp_rsp_rrpd(in_rrpd);
680
681                 if (temp_list != NULL)
682                     update_temp_rsp_rrpd(temp_list, in_rrpd);
683                 else
684                 {
685                     /* If this is a retransmission we need to add it to the last completed rrpd_list entry for this stream */
686                     if (in_rrpd->is_retrans)
687                     {
688                         match = find_latest_rrpd(in_rrpd);
689
690                         if (match != NULL)
691                             update_rrpd_list_entry(match, in_rrpd);
692                         else
693                             insert_into_temp_rsp_rrpd_list(in_rrpd);
694                     }
695                     else
696                         /* As it's not a retransmission, just create a new entry on the temp list */
697                         insert_into_temp_rsp_rrpd_list(in_rrpd);
698                 }
699             }
700         }
701         else
702         {
703             /* Reassembly isn't set and so just go ahead and use the list function */
704             match = find_latest_rrpd(in_rrpd);
705             if (match != NULL)
706                 update_rrpd_list_entry(match, in_rrpd);
707         }
708     }
709     else
710     {
711         /* if this isn't decode_based then just go ahead and update the RTE data */
712         match = find_latest_rrpd(in_rrpd);
713         if (match != NULL)
714             update_rrpd_list_entry(match, in_rrpd);
715     }
716
717     return;
718 }
719
720
721 /*
722     This function updates the RTE data of an RRPD on the rrpd_list.  The
723     frame_no values in the input RRPD double up as a mask.  If the frame_no
724     is > 0 then the frame_no value and rtime values are updated.  If the
725     frame_no is 0 then that particular frame_no and rtime value is not updated.
726  */
727 static void update_rrpd_rte_data(RRPD *in_rrpd)
728 {
729     if (in_rrpd->c2s)
730         update_rrpd_list_entry_req(in_rrpd);
731     else
732         update_rrpd_list_entry_rsp(in_rrpd);
733 }
734
735 gboolean is_dcerpc_context_zero(guint32 pkt_type)
736 {
737     return (wmem_map_lookup(dcerpc_context_zero, GUINT_TO_POINTER(pkt_type)) != NULL);
738 }
739
740 gboolean is_dcerpc_req_pkt_type(guint32 pkt_type)
741 {
742     return (wmem_map_lookup(dcerpc_req_pkt_type, GUINT_TO_POINTER(pkt_type)) != NULL);
743 }
744
745 static gboolean is_dcerpc_stream(guint32 stream_no)
746 {
747     return (wmem_map_lookup(dcerpc_streams, GUINT_TO_POINTER(stream_no)) != NULL);
748 }
749
750 /*
751     This function initialises the global variables and populates the
752     [tcp|udp]_svc_ports tables with information from the preference settings
753  */
754 static void init_globals(void)
755 {
756     if (!proto_is_protocol_enabled(find_protocol_by_id(proto_transum)))
757         return;
758
759     highest_tcp_stream_no = -1;
760     highest_udp_stream_no = -1;
761
762     /* Create and initialise some dynamic memory areas */
763     tcp_stream_exceptions = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
764     detected_tcp_svc = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
765     rrpd_list = wmem_list_new(wmem_file_scope());
766     temp_rsp_rrpd_list = wmem_list_new(wmem_file_scope());
767
768     /* Indicate what fields we're interested in. */
769     GArray *wanted_fields = g_array_sized_new(FALSE, FALSE, (guint)sizeof(int), HF_INTEREST_END_OF_LIST);
770     for (int i = 0; i < HF_INTEREST_END_OF_LIST; i++)
771     {
772         if (hf_of_interest[i].hf != -1)
773             g_array_append_val(wanted_fields, hf_of_interest[i].hf);
774         else
775             g_warning("TRANSUM: unknown field %s", hf_of_interest[i].proto_name);
776     }
777     set_postdissector_wanted_hfids(transum_handle, wanted_fields);
778
779     preferences.tcp_svc_ports = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
780     preferences.udp_svc_ports = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
781
782     /* use the range values to populate the tcp_svc_ports list*/
783     for (guint i = 0; i < tcp_svc_port_range_values->nranges; i++)
784     {
785         for (guint32 j = tcp_svc_port_range_values->ranges[i].low; j <= tcp_svc_port_range_values->ranges[i].high; j++)
786         {
787             wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(j), GUINT_TO_POINTER(RTE_CALC_GTCP));
788         }
789     }
790
791     /* use the range values to populate the udp_svc_ports list*/
792     for (guint i = 0; i < udp_svc_port_range_values->nranges; i++)
793     {
794         for (guint32 j = udp_svc_port_range_values->ranges[i].low; j <= udp_svc_port_range_values->ranges[i].high; j++)
795         {
796             wmem_map_insert(preferences.udp_svc_ports, GUINT_TO_POINTER(j), GUINT_TO_POINTER(RTE_CALC_GUDP));
797         }
798     }
799
800     /* create arrays to hold some DCE-RPC values */
801     dcerpc_context_zero = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
802     dcerpc_req_pkt_type = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
803     dcerpc_streams      = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
804     init_dcerpc_data();
805
806     wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(445), GUINT_TO_POINTER(RTE_CALC_SMB2));
807     wmem_map_insert(preferences.udp_svc_ports, GUINT_TO_POINTER(53), GUINT_TO_POINTER(RTE_CALC_DNS));
808 }
809
810 /* Undo capture file-specific initializations. */
811 static void cleanup_globals(void)
812 {
813     /* Clear the list of wanted fields as it will be reinitialized. */
814     set_postdissector_wanted_hfids(transum_handle, NULL);
815 }
816
817 /* This function adds the RTE data to the tree.  The summary ptr is currently
818    not used but will be used for summariser information once this feature has
819    been ported from the LUA code. */
820 static void write_rte(RRPD *in_rrpd, tvbuff_t *tvb, proto_tree *tree, char *summary)
821 {
822     nstime_t rte_art;
823     nstime_t rte_st;
824     nstime_t rte_reqspread;
825     nstime_t rte_rspspread;
826     proto_tree *rte_tree;
827     proto_item *pi;
828     wmem_strbuf_t *temp_string = wmem_strbuf_new(wmem_packet_scope(), "");
829
830     if (in_rrpd->req_first_frame)
831     {
832         pi = proto_tree_add_item(tree, proto_transum, tvb, 0, -1, ENC_NA);
833         rte_tree = proto_item_add_subtree(pi, ett_transum);
834
835         nstime_delta(&rte_reqspread, &(in_rrpd->req_last_rtime), &(in_rrpd->req_first_rtime));
836         if (in_rrpd->rsp_first_frame)
837         {
838             /* calculate the RTE times */
839             nstime_delta(&rte_art, &(in_rrpd->rsp_last_rtime), &(in_rrpd->req_first_rtime));
840             nstime_delta(&rte_st, &(in_rrpd->rsp_first_rtime), &(in_rrpd->req_last_rtime));
841             nstime_delta(&rte_rspspread, &(in_rrpd->rsp_last_rtime), &(in_rrpd->rsp_first_rtime));
842
843             pi = proto_tree_add_string(rte_tree, hf_tsum_status, tvb, 0, 0, "OK");
844         }
845         else
846         {
847             pi = proto_tree_add_string(rte_tree, hf_tsum_status, tvb, 0, 0, "Response missing");
848         }
849         proto_item_set_generated(pi);
850
851
852         pi = proto_tree_add_uint(rte_tree, hf_tsum_req_first_seg, tvb, 0, 0, in_rrpd->req_first_frame);
853         proto_item_set_generated(pi);
854         pi = proto_tree_add_uint(rte_tree, hf_tsum_req_last_seg, tvb, 0, 0, in_rrpd->req_last_frame);
855         proto_item_set_generated(pi);
856
857         if (in_rrpd->rsp_first_frame)
858         {
859             pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_first_seg, tvb, 0, 0, in_rrpd->rsp_first_frame);
860             proto_item_set_generated(pi);
861             pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_last_seg, tvb, 0, 0, in_rrpd->rsp_last_frame);
862             proto_item_set_generated(pi);
863
864             pi = proto_tree_add_time(rte_tree, hf_tsum_apdu_rsp_time, tvb, 0, 0, &rte_art);
865             proto_item_set_generated(pi);
866             pi = proto_tree_add_time(rte_tree, hf_tsum_service_time, tvb, 0, 0, &rte_st);
867             proto_item_set_generated(pi);
868         }
869
870         pi = proto_tree_add_time(rte_tree, hf_tsum_req_spread, tvb, 0, 0, &rte_reqspread);
871         proto_item_set_generated(pi);
872
873         if (in_rrpd->rsp_first_frame)
874         {
875             pi = proto_tree_add_time(rte_tree, hf_tsum_rsp_spread, tvb, 0, 0, &rte_rspspread);
876             proto_item_set_generated(pi);
877         }
878
879         if (in_rrpd->ip_proto == IP_PROTO_TCP)
880             wmem_strbuf_append_printf(temp_string, "tcp.stream==%d", in_rrpd->stream_no);
881         else if (in_rrpd->ip_proto == IP_PROTO_UDP)
882             wmem_strbuf_append_printf(temp_string, "udp.stream==%d", in_rrpd->stream_no);
883
884         if (in_rrpd->rsp_first_frame)
885             wmem_strbuf_append_printf(temp_string, " && frame.number>=%d && frame.number<=%d", in_rrpd->req_first_frame, in_rrpd->rsp_last_frame);
886         else
887             wmem_strbuf_append_printf(temp_string, " && frame.number>=%d && frame.number<=%d", in_rrpd->req_first_frame, in_rrpd->req_last_frame);
888
889         if (in_rrpd->calculation == RTE_CALC_GTCP)
890             wmem_strbuf_append_printf(temp_string, " && tcp.len>0");
891
892         pi = proto_tree_add_string(rte_tree, hf_tsum_clip_filter, tvb, 0, 0, wmem_strbuf_get_str(temp_string));
893         proto_item_set_generated(pi);
894
895         pi = proto_tree_add_string(rte_tree, hf_tsum_calculation, tvb, 0, 0, val_to_str(in_rrpd->calculation, rrdp_calculation_vals, "Unknown calculation type: %d"));
896         proto_item_set_generated(pi);
897
898         if (in_rrpd->rsp_first_frame)
899         {
900             if (preferences.summarisers_enabled)
901             {
902                 if (summary)
903                 {
904                     pi = proto_tree_add_string(tree, hf_tsum_summary, tvb, 0, 0, summary);
905                     proto_item_set_generated(pi);
906                 }
907             }
908         }
909
910         if (preferences.debug_enabled)
911         {
912             pi = proto_tree_add_uint(rte_tree, hf_tsum_req_search, tvb, 0, 0, in_rrpd->req_search_total);
913             proto_item_set_generated(pi);
914             pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_search, tvb, 0, 0, in_rrpd->rsp_search_total);
915             proto_item_set_generated(pi);
916         }
917     }
918 }
919
920 /*
921     This function sets initial values in the current_pkt structure and checks
922     the xxx_svc_port arrays to see if they contain a match for the source or
923     destination port.  This function also adds tcp_svc_ports entries when it
924     discovers DCE-RPC traffic.
925
926     Returns the number of sub-packets to be processed.
927 */
928 static void set_proto_values(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info, PKT_INFO* subpackets)
929 {
930     guint32 field_uint[MAX_RETURNED_ELEMENTS];  /* An extracted field array for unsigned integers */
931     size_t field_value_count;  /* How many entries are there in the extracted field array */
932
933     pkt_info->frame_number = pinfo->fd->num;   /* easy access to frame number */
934     pkt_info->relative_time = pinfo->rel_ts;
935
936     int number_sub_pkts_of_interest = 0; /* default */
937
938     if (pinfo->ptype == PT_TCP)
939         pkt_info->rrpd.ip_proto = IP_PROTO_TCP;
940     else if (pinfo->ptype == PT_UDP)
941         pkt_info->rrpd.ip_proto = IP_PROTO_UDP;
942
943     if (pkt_info->rrpd.ip_proto == IP_PROTO_TCP)
944     {
945         number_sub_pkts_of_interest = decode_gtcp(pinfo, tree, pkt_info);
946         /* decode_gtcp may return 0 but we need to keep processing because we
947         calculate RTE figures for all SYNs and also we may detect DCE-RPC later
948         (even though we don't currently have an entry in the tcp_svc_ports list). */
949
950         /* Optimisation code */
951         if (pkt_info->len || pkt_info->tcp_flags_syn)
952         {
953             if (pkt_info->ssl_content_type == 21)  /* this is an SSL Alert */
954             {
955                 pkt_info->pkt_of_interest = FALSE;
956                 return;
957             }
958
959             if ((int)pkt_info->rrpd.stream_no > highest_tcp_stream_no && !pkt_info->rrpd.c2s)
960             {
961                 /* first packet on the stream is s2c and so add to exception list */
962                 if (wmem_map_lookup(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no)) == NULL)
963                     wmem_map_insert(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no), GUINT_TO_POINTER(1));
964             }
965
966             if (wmem_map_lookup(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no)) != NULL)
967             {
968                 if (pkt_info->rrpd.c2s)
969                     wmem_map_remove(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no));
970                 else
971                     pkt_info->pkt_of_interest = FALSE;
972             }
973         }
974         /* End of Optimisation Code */
975
976         if (pkt_info->tcp_retran)
977         {
978             /* we may not want to continue with this packet if it's a retransmission */
979
980             /* If this is a server-side trace we need to ignore client-to-service TCP retransmissions
981             the rationale being that if we saw the original in the trace the service process saw it too */
982             if (pkt_info->rrpd.c2s && preferences.capture_position == CAPTURE_SERVICE)
983             {
984                 pkt_info->pkt_of_interest = FALSE;
985                 return;
986             }
987
988             /* If this is a client-side trace we need to ignore service-to-client TCP retransmissions
989             the rationale being that if we saw the original in the trace the client process saw it too */
990             else if (!pkt_info->rrpd.c2s && preferences.capture_position == CAPTURE_CLIENT)
991             {
992                 pkt_info->pkt_of_interest = FALSE;
993                 return;
994             }
995         }
996
997         /* We are not interested in TCP Keep-Alive */
998         if (pkt_info->tcp_keep_alive)
999         {
1000             pkt_info->pkt_of_interest = FALSE;
1001             return;
1002         }
1003
1004         if (pkt_info->len == 1)
1005         {
1006             if (preferences.orphan_ka_discard && pkt_info->tcp_flags_ack && pkt_info->rrpd.c2s)
1007             {
1008                 pkt_info->pkt_of_interest = FALSE;
1009                 return;  /* It's a KEEP-ALIVE -> stop processing this packet */
1010             }
1011         }
1012
1013         /* check if SYN */
1014         if (pkt_info->tcp_flags_syn)
1015             number_sub_pkts_of_interest = decode_syn(pinfo, tree, pkt_info);
1016
1017         if (pkt_info->len > 0)
1018         {
1019             /* check if SMB2 */
1020             if (pkt_info->dstport == 445 || pkt_info->srcport == 445)
1021                 number_sub_pkts_of_interest = decode_smb(pinfo, tree, pkt_info, subpackets);
1022
1023             else
1024             {
1025                 /* check if DCE-RPC */
1026                 /* We need to set RTE_CALC_DCERPC even when we don't have header info. */
1027                 if (is_dcerpc_stream(pkt_info->rrpd.stream_no))
1028                 {
1029                     pkt_info->rrpd.calculation = RTE_CALC_DCERPC;
1030                     pkt_info->rrpd.decode_based = TRUE;
1031                     pkt_info->pkt_of_interest = TRUE;
1032                 }
1033
1034                 if (!extract_uint(tree, hf_of_interest[HF_INTEREST_DCERPC_VER].hf, field_uint, &field_value_count))
1035                 {
1036                     if (field_value_count)
1037                     {
1038                         if (pkt_info->rrpd.calculation != RTE_CALC_DCERPC)
1039                             register_dcerpc_stream(pkt_info->rrpd.stream_no);
1040
1041                         number_sub_pkts_of_interest = decode_dcerpc(pinfo, tree, pkt_info);
1042                     }
1043                 }
1044             }
1045         }
1046
1047     }
1048     else if (pkt_info->rrpd.ip_proto == IP_PROTO_UDP)
1049     {
1050         /* It's UDP */
1051         number_sub_pkts_of_interest = decode_gudp(pinfo, tree, pkt_info);
1052
1053         if (pkt_info->srcport == 53 || pkt_info->dstport == 53)
1054             number_sub_pkts_of_interest = decode_dns(pinfo, tree, pkt_info);
1055     }
1056
1057     /* Set appropriate RTE values in the sub-packets */
1058     for (int i = 0; (i < number_sub_pkts_of_interest) && (i < MAX_SUBPKTS_PER_PACKET); i++)
1059     {
1060         if (pkt_info->rrpd.c2s)
1061         {
1062             subpackets[i].rrpd.req_first_frame = pkt_info->frame_number;
1063             subpackets[i].rrpd.req_first_rtime = pkt_info->relative_time;
1064             subpackets[i].rrpd.req_last_frame = pkt_info->frame_number;
1065             subpackets[i].rrpd.req_last_rtime = pkt_info->relative_time;
1066
1067             subpackets[i].frame_number = pkt_info->frame_number;  /* this acts as a switch later */
1068         }
1069         else
1070         {
1071             subpackets[i].rrpd.rsp_first_frame = pkt_info->frame_number;
1072             subpackets[i].rrpd.rsp_first_rtime = pkt_info->relative_time;
1073             subpackets[i].rrpd.rsp_last_frame = pkt_info->frame_number;
1074             subpackets[i].rrpd.rsp_last_rtime = pkt_info->relative_time;
1075
1076             subpackets[i].frame_number = pkt_info->frame_number;  /* this acts as a switch later */
1077         }
1078     }
1079 }
1080
1081
1082 /*
1083  * This function is called for each packet
1084  * Wireshark scans all the packets once and then once again as they are displayed
1085  * The pinfo.visited boolean is set to FALSE; on the first scan
1086 */
1087 static int dissect_transum(tvbuff_t *buffer, packet_info *pinfo, proto_tree *tree, void *data _U_)
1088 {
1089     /* if (there is RTE info associated with this packet we need to output it */
1090     if (PINFO_FD_VISITED(pinfo))
1091     {
1092         RRPD *rrpd = (RRPD*)wmem_map_lookup(output_rrpd, GUINT_TO_POINTER(pinfo->num));
1093
1094         if (rrpd)
1095         {
1096             if (tree)
1097             {
1098                 /* Add the RTE data to the protocol decode tree if we output_flag is set */
1099                 write_rte(rrpd, buffer, tree, NULL);
1100             }
1101         }
1102     }
1103     else
1104     {
1105         PKT_INFO *sub_packet = wmem_alloc0_array(wmem_packet_scope(), PKT_INFO, MAX_SUBPKTS_PER_PACKET);
1106
1107         set_proto_values(pinfo, tree, &sub_packet[0], sub_packet);
1108
1109         if (sub_packet[0].pkt_of_interest)
1110         {
1111             /* Loop to process each sub_packet and update the related RTE data */
1112             for (int i = 0; i < MAX_SUBPKTS_PER_PACKET; i++)
1113             {
1114                 if (!sub_packet[i].frame_number)
1115                     break;
1116
1117                 update_rrpd_rte_data(&(sub_packet[i].rrpd));
1118             }
1119         }
1120     }
1121
1122     return 0;
1123 }
1124
1125 void
1126 proto_register_transum(void)
1127 {
1128     module_t *transum_module;
1129
1130     static hf_register_info hf[] = {
1131         { &hf_tsum_status,
1132         { "RTE Status", "transum.status",
1133         FT_STRING, BASE_NONE, NULL, 0x0,
1134         "Indication of completeness of the RTE information", HFILL } },
1135 #if 0
1136         { &hf_tsum_time_units,
1137         { "RTE Time Units", "transum.time_units",
1138         FT_STRING, BASE_NONE, NULL, 0x0,
1139         "Time units used (s, ms or us) for the RTE values", HFILL }
1140         },
1141 #endif
1142         { &hf_tsum_req_first_seg,
1143         { "Req First Seg", "transum.firstreq",
1144         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1145         "First Segment of an APDU Request", HFILL }
1146         },
1147
1148         { &hf_tsum_req_last_seg,
1149         { "Req Last Seg", "transum.lastreq",
1150         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1151         "Last Segment of an APDU Request", HFILL }
1152         },
1153
1154         { &hf_tsum_rsp_first_seg,
1155         { "Rsp First Seg", "transum.firstrsp",
1156         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1157         "First Segment of an APDU Response", HFILL }
1158         },
1159
1160         { &hf_tsum_rsp_last_seg,
1161         { "Rsp Last Seg", "transum.lastrsp",
1162         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1163         "Last Segment of an APDU Response", HFILL }
1164         },
1165
1166         { &hf_tsum_apdu_rsp_time,
1167         { "APDU Rsp Time", "transum.art",
1168         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1169         "RTE APDU Response Time", HFILL }
1170         },
1171
1172         { &hf_tsum_service_time,
1173         { "Service Time", "transum.st",
1174         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1175         "RTE Service Time", HFILL }
1176         },
1177
1178         { &hf_tsum_req_spread,
1179         { "Req Spread", "transum.reqspread",
1180         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1181         "RTE Request Spread", HFILL }
1182         },
1183
1184         { &hf_tsum_rsp_spread,
1185         { "Rsp Spread", "transum.rspspread",
1186         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1187         "RTE Response Spread", HFILL }
1188         },
1189
1190         { &hf_tsum_clip_filter,
1191         { "Trace clip filter", "transum.clip_filter",
1192         FT_STRING, BASE_NONE, NULL, 0x0,
1193         "Filter expression to select the APDU Reqest-Response pair", HFILL }
1194         },
1195
1196         { &hf_tsum_calculation,
1197         { "Calculation", "transum.calculation",
1198         FT_STRING, BASE_NONE, NULL, 0x0,
1199         "Basis of the RTE calculation", HFILL }
1200         },
1201
1202         { &hf_tsum_summary,
1203         { "Summary", "transum.summary",
1204         FT_STRING, BASE_NONE, NULL, 0x0,
1205         "Summarizer information", HFILL }
1206         },
1207
1208         { &hf_tsum_req_search,
1209         { "Req Search Count", "transum.req_search",
1210         FT_UINT32, BASE_DEC, NULL, 0x0,
1211         "rrpd_list search total for the request packets", HFILL }
1212         },
1213
1214         { &hf_tsum_rsp_search,
1215         { "Rsp Search Counts", "transum.rsp_search",
1216         FT_UINT32, BASE_DEC, NULL, 0x0,
1217         "rrpd_list search total for the response packets", HFILL }
1218         }
1219
1220     };
1221
1222     /* Setup protocol subtree array */
1223     static gint *ett[] = {
1224         &ett_transum,
1225         &ett_transum_header,
1226         &ett_transum_data
1227     };
1228
1229     proto_transum = proto_register_protocol("TRANSUM RTE Data", "TRANSUM", "transum");
1230
1231     /* Due to performance concerns of the dissector, it's disabled by default */
1232     proto_disable_by_default(proto_transum);
1233
1234
1235     /* Set User Preferences defaults */
1236     preferences.capture_position = TRACE_CAP_CLIENT;
1237     preferences.reassembly = TRUE;
1238
1239     range_convert_str(wmem_epan_scope(), &tcp_svc_port_range_values, "25, 80, 443, 1433", MAX_TCP_PORT);
1240     range_convert_str(wmem_epan_scope(), &udp_svc_port_range_values, "137-139", MAX_UDP_PORT);
1241
1242     preferences.orphan_ka_discard = FALSE;
1243     preferences.time_multiplier = RTE_TIME_SEC;
1244     preferences.rte_on_first_req = FALSE;
1245     preferences.rte_on_last_req = TRUE;
1246     preferences.rte_on_first_rsp = FALSE;
1247     preferences.rte_on_last_rsp = FALSE;
1248
1249     preferences.debug_enabled = FALSE;
1250
1251     /* no start registering stuff */
1252     proto_register_field_array(proto_transum, hf, array_length(hf));
1253     proto_register_subtree_array(ett, array_length(ett));
1254
1255     transum_module = prefs_register_protocol(proto_transum, NULL);  /* ToDo: We need to rethink the NULL pointer so that a preference change causes a rescan */
1256
1257     /* Register the preferences */
1258     prefs_register_obsolete_preference(transum_module, "tsumenabled");
1259
1260     prefs_register_enum_preference(transum_module,
1261         "capture_position",
1262         "Capture position",
1263         "Position of the capture unit that produced this trace.  This setting affects the way TRANSUM handles TCP Retransmissions.  See the manual for details.",
1264         &preferences.capture_position,
1265         capture_position_vals,
1266         FALSE);
1267
1268     prefs_register_bool_preference(transum_module,
1269         "reassembly",
1270         "Subdissector reassembly enabled",
1271         "Set this to match to the TCP subdissector reassembly setting",
1272         &preferences.reassembly);
1273
1274     prefs_register_range_preference(transum_module,
1275         "tcp_port_ranges",
1276         "Output RTE data for these TCP service ports",
1277         "Add and remove ports numbers separated by commas\nRanges are supported e.g. 25,80,2000-3000,5432",
1278         &tcp_svc_port_range_values,
1279         65536);
1280
1281     prefs_register_range_preference(transum_module,
1282         "udp_port_ranges",
1283         "Output RTE data for these UDP service ports",
1284         "Add and remove ports numbers separated by commas\nRanges are supported e.g. 123,137-139,520-521,2049",
1285         &udp_svc_port_range_values,
1286         65536);
1287
1288     prefs_register_bool_preference(transum_module,
1289         "orphan_ka_discard",
1290         "Discard orphaned TCP Keep-Alives",
1291         "Set this to discard any packet in the direction client to service,\nwith a 1-byte payload of 0x00 and the ACK flag set",
1292         &preferences.orphan_ka_discard);
1293
1294     /* removed from this release
1295     prefs_register_enum_preference(transum_module,
1296     "time_multiplier",
1297     "Time units for RTE values",
1298     "Unit of time used for APDU Response Time, Service Time and Spread Time values.",
1299     &preferences.time_multiplier,
1300     time_multiplier_vals,
1301     FALSE);
1302     */
1303
1304     prefs_register_bool_preference(transum_module,
1305         "rte_on_first_req",
1306         "Add RTE data to the first request segment",
1307         "RTE data will be added to the first request packet",
1308         &preferences.rte_on_first_req);
1309
1310     prefs_register_bool_preference(transum_module,
1311         "rte_on_last_req",
1312         "Add RTE data to the last request segment",
1313         "RTE data will be added to the last request packet",
1314         &preferences.rte_on_last_req);
1315
1316     prefs_register_bool_preference(transum_module,
1317         "rte_on_first_rsp",
1318         "Add RTE data to the first response segment",
1319         "RTE data will be added to the first response packet",
1320         &preferences.rte_on_first_rsp);
1321
1322     prefs_register_bool_preference(transum_module,
1323         "rte_on_last_rsp",
1324         "Add RTE data to the last response segment",
1325         "RTE data will be added to the last response packet",
1326         &preferences.rte_on_last_rsp);
1327
1328     prefs_register_bool_preference(transum_module,
1329         "debug_enabled",
1330         "Enable debug info",
1331         "Set this only to troubleshoot problems",
1332         &preferences.debug_enabled);
1333
1334     transum_handle = register_dissector("transum", dissect_transum, proto_transum);
1335
1336     register_init_routine(init_globals);
1337     register_cleanup_routine(cleanup_globals);
1338
1339     register_postdissector(transum_handle);
1340
1341     output_rrpd = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), g_direct_hash, g_direct_equal);
1342 }
1343
1344 void proto_reg_handoff_transum(void)
1345 {
1346     /* Get the field id for each field we will need */
1347     for (int i = 0; i < HF_INTEREST_END_OF_LIST; i++)
1348     {
1349         hf_of_interest[i].hf = proto_registrar_get_id_byname(hf_of_interest[i].proto_name);
1350     }
1351 }
1352
1353 /*
1354  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1355  *
1356  * Local variables:
1357  * c-basic-offset: 4
1358  * tab-width: 8
1359  * indent-tabs-mode: nil
1360  * End:
1361  *
1362  * vi: set shiftwidth=4 tabstop=8 expandtab:
1363  * :indentSize=4:tabSize=8:noTabs=true:
1364  */