1 /* packet-h225.c
2  * Routines for h225 packet dissection
3  * Copyright 2005, Anders Broman <anders.broman@ericsson.com>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  *
11  * To quote the author of the previous H323/H225/H245 dissector:
12  *   "This is a complete replacement of the previous limitied dissector
13  * that Ronnie was crazy enough to write by hand. It was a lot of time
14  * to hack it by hand, but it is incomplete and buggy and it is good when
15  * it will go away."
16  * Ronnie did a great job and all the VoIP users had made good use of it!
17  * Credit to Tomas Kukosa for developing the asn2wrs compiler.
18  *
19  */
20 
21 #include "config.h"
22 
23 #include <epan/packet.h>
24 #include <epan/conversation.h>
25 #include <epan/proto_data.h>
26 
27 #include <epan/prefs.h>
28 #include <epan/oids.h>
29 #include <epan/next_tvb.h>
30 #include <epan/asn1.h>
31 #include <epan/t35.h>
32 #include <epan/tap.h>
33 #include <epan/stat_tap_ui.h>
34 #include <epan/rtd_table.h>
35 #include "packet-frame.h"
36 #include "packet-tpkt.h"
37 #include "packet-per.h"
38 #include "packet-h225.h"
39 #include "packet-h235.h"
40 #include "packet-h245.h"
41 #include "packet-h323.h"
42 #include "packet-q931.h"
43 #include "packet-tls.h"
44 
45 #define PNAME  "H323-MESSAGES"
46 #define PSNAME "H.225.0"
47 #define PFNAME "h225"
48 
49 #define UDP_PORT_RAS_RANGE "1718-1719"
50 #define TCP_PORT_CS   1720
51 #define TLS_PORT_CS   1300
52 
53 void proto_register_h225(void);
54 static h225_packet_info* create_h225_packet_info(packet_info *pinfo);
55 static void ras_call_matching(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, h225_packet_info *pi);
56 
57 /* Item of ras request list*/
58 typedef struct _h225ras_call_t {
59   guint32 requestSeqNum;
60   e_guid_t guid;
61   guint32 req_num;  /* frame number request seen */
62   guint32 rsp_num;  /* frame number response seen */
63   nstime_t req_time;  /* arrival time of request */
64   gboolean responded; /* true, if request has been responded */
65   struct _h225ras_call_t *next_call; /* pointer to next ras request with same SequenceNumber and conversation handle */
66 } h225ras_call_t;
67 
68 
69 /* Item of ras-request key list*/
70 typedef struct _h225ras_call_info_key {
71   guint reqSeqNum;
72   conversation_t *conversation;
73 } h225ras_call_info_key;
74 
75 /* Global Memory Chunks for lists and Global hash tables*/
76 
77 static wmem_map_t *ras_calls[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
78 
79 /* functions, needed using ras-request and halfcall matching*/
80 static h225ras_call_t * find_h225ras_call(h225ras_call_info_key *h225ras_call_key ,int category);
81 static h225ras_call_t * new_h225ras_call(h225ras_call_info_key *h225ras_call_key, packet_info *pinfo, e_guid_t *guid, int category);
82 static h225ras_call_t * append_h225ras_call(h225ras_call_t *prev_call, packet_info *pinfo, e_guid_t *guid, int category);
83 
84 
85 static dissector_handle_t h225ras_handle;
86 static dissector_handle_t data_handle;
87 /* Subdissector tables */
88 static dissector_table_t nsp_object_dissector_table;
89 static dissector_table_t nsp_h221_dissector_table;
90 static dissector_table_t tp_dissector_table;
91 static dissector_table_t gef_name_dissector_table;
92 static dissector_table_t gef_content_dissector_table;
93 
94 
95 static dissector_handle_t h245_handle=NULL;
96 static dissector_handle_t h245dg_handle=NULL;
97 static dissector_handle_t h4501_handle=NULL;
98 
99 static dissector_handle_t nsp_handle;
100 static dissector_handle_t tp_handle;
101 
102 static next_tvb_list_t *h245_list;
103 static next_tvb_list_t *tp_list;
104 
105 /* Initialize the protocol and registered fields */
106 static int h225_tap = -1;
107 static int proto_h225 = -1;
108 
109 static int hf_h221Manufacturer = -1;
110 static int hf_h225_ras_req_frame = -1;
111 static int hf_h225_ras_rsp_frame = -1;
112 static int hf_h225_ras_dup = -1;
113 static int hf_h225_ras_deltatime = -1;
114 static int hf_h225_debug_dissector_try_string = -1;
115 
116 #include "packet-h225-hf.c"
117 
118 /* Initialize the subtree pointers */
119 static gint ett_h225 = -1;
120 #include "packet-h225-ett.c"
121 
122 /* Preferences */
123 static guint h225_tls_port = TLS_PORT_CS;
124 static gboolean h225_reassembly = TRUE;
125 static gboolean h225_h245_in_tree = TRUE;
126 static gboolean h225_tp_in_tree = TRUE;
127 
128 /* Global variables */
129 static guint32 ipv4_address;
130 static ws_in6_addr ipv6_address;
131 static ws_in6_addr ipv6_address_zeros = {{0}};
132 static guint32 ip_port;
133 static gboolean contains_faststart = FALSE;
134 static e_guid_t *call_id_guid;
135 
136 /* NonStandardParameter */
137 static const char *nsiOID;
138 static guint32 h221NonStandard;
139 static guint32 t35CountryCode;
140 static guint32 t35Extension;
141 static guint32 manufacturerCode;
142 
143 /* TunnelledProtocol */
144 static const char *tpOID;
145 
146 static const value_string ras_message_category[] = {
147   {  0, "Gatekeeper    "},
148   {  1, "Registration  "},
149   {  2, "UnRegistration"},
150   {  3, "Admission     "},
151   {  4, "Bandwidth     "},
152   {  5, "Disengage     "},
153   {  6, "Location      "},
154   {  0, NULL }
155 };
156 
157 typedef enum _ras_type {
158   RAS_REQUEST,
159   RAS_CONFIRM,
160   RAS_REJECT,
161   RAS_OTHER
162 }ras_type;
163 
164 typedef enum _ras_category {
165   RAS_GATEKEEPER,
166   RAS_REGISTRATION,
167   RAS_UNREGISTRATION,
168   RAS_ADMISSION,
169   RAS_BANDWIDTH,
170   RAS_DISENGAGE,
171   RAS_LOCATION,
172   RAS_OTHERS
173 }ras_category;
174 
175 #define NUM_RAS_STATS 7
176 
177 static tap_packet_status
h225rassrt_packet(void * phs,packet_info * pinfo _U_,epan_dissect_t * edt _U_,const void * phi)178 h225rassrt_packet(void *phs, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *phi)
179 {
180   rtd_data_t* rtd_data = (rtd_data_t*)phs;
181   rtd_stat_table* rs = &rtd_data->stat_table;
182   const h225_packet_info *pi=(const h225_packet_info *)phi;
183 
184   ras_type rasmsg_type = RAS_OTHER;
185   ras_category rascategory = RAS_OTHERS;
186 
187   if (pi->msg_type != H225_RAS || pi->msg_tag == -1) {
188     /* No RAS Message or uninitialized msg_tag -> return */
189     return TAP_PACKET_DONT_REDRAW;
190   }
191 
192   if (pi->msg_tag < 21) {
193     /* */
194     rascategory = (ras_category)(pi->msg_tag / 3);
195     rasmsg_type = (ras_type)(pi->msg_tag % 3);
196   }
197   else {
198     /* No SRT yet (ToDo) */
199     return TAP_PACKET_DONT_REDRAW;
200   }
201 
202   switch(rasmsg_type) {
203 
204   case RAS_REQUEST:
205     if(pi->is_duplicate){
206       rs->time_stats[rascategory].req_dup_num++;
207     }
208     else {
209       rs->time_stats[rascategory].open_req_num++;
210     }
211     break;
212 
213   case RAS_CONFIRM:
214     /* no break - delay stats are identical for Confirm and Reject */
215   case RAS_REJECT:
216     if(pi->is_duplicate){
217       /* Duplicate is ignored */
218       rs->time_stats[rascategory].rsp_dup_num++;
219     }
220     else if (!pi->request_available) {
221       /* no request was seen, ignore response */
222       rs->time_stats[rascategory].disc_rsp_num++;
223     }
224     else {
225       rs->time_stats[rascategory].open_req_num--;
226       time_stat_update(&(rs->time_stats[rascategory].rtd[0]),&(pi->delta_time), pinfo);
227     }
228     break;
229 
230   default:
231     return TAP_PACKET_DONT_REDRAW;
232   }
233   return TAP_PACKET_REDRAW;
234 }
235 
236 #include "packet-h225-fn.c"
237 
238 /* Forward declaration we need below */
239 void proto_reg_handoff_h225(void);
240 
241 /*
242  * Functions needed for Ras-Hash-Table
243  */
244 
245 /* compare 2 keys */
h225ras_call_equal(gconstpointer k1,gconstpointer k2)246 static gint h225ras_call_equal(gconstpointer k1, gconstpointer k2)
247 {
248   const h225ras_call_info_key* key1 = (const h225ras_call_info_key*) k1;
249   const h225ras_call_info_key* key2 = (const h225ras_call_info_key*) k2;
250 
251   return (key1->reqSeqNum == key2->reqSeqNum &&
252           key1->conversation == key2->conversation);
253 }
254 
255 /* calculate a hash key */
h225ras_call_hash(gconstpointer k)256 static guint h225ras_call_hash(gconstpointer k)
257 {
258   const h225ras_call_info_key* key = (const h225ras_call_info_key*) k;
259 
260   return key->reqSeqNum + GPOINTER_TO_UINT(key->conversation);
261 }
262 
263 
find_h225ras_call(h225ras_call_info_key * h225ras_call_key,int category)264 h225ras_call_t * find_h225ras_call(h225ras_call_info_key *h225ras_call_key ,int category)
265 {
266   h225ras_call_t *h225ras_call = (h225ras_call_t *)wmem_map_lookup(ras_calls[category], h225ras_call_key);
267 
268   return h225ras_call;
269 }
270 
new_h225ras_call(h225ras_call_info_key * h225ras_call_key,packet_info * pinfo,e_guid_t * guid,int category)271 h225ras_call_t * new_h225ras_call(h225ras_call_info_key *h225ras_call_key, packet_info *pinfo, e_guid_t *guid, int category)
272 {
273   h225ras_call_info_key *new_h225ras_call_key;
274   h225ras_call_t *h225ras_call = NULL;
275 
276 
277   /* Prepare the value data.
278      "req_num" and "rsp_num" are frame numbers;
279      frame numbers are 1-origin, so we use 0
280      to mean "we don't yet know in which frame
281      the reply for this call appears". */
282   new_h225ras_call_key = wmem_new(wmem_file_scope(), h225ras_call_info_key);
283   new_h225ras_call_key->reqSeqNum = h225ras_call_key->reqSeqNum;
284   new_h225ras_call_key->conversation = h225ras_call_key->conversation;
285   h225ras_call = wmem_new(wmem_file_scope(), h225ras_call_t);
286   h225ras_call->req_num = pinfo->num;
287   h225ras_call->rsp_num = 0;
288   h225ras_call->requestSeqNum = h225ras_call_key->reqSeqNum;
289   h225ras_call->responded = FALSE;
290   h225ras_call->next_call = NULL;
291   h225ras_call->req_time=pinfo->abs_ts;
292   h225ras_call->guid=*guid;
293   /* store it */
294   wmem_map_insert(ras_calls[category], new_h225ras_call_key, h225ras_call);
295 
296   return h225ras_call;
297 }
298 
append_h225ras_call(h225ras_call_t * prev_call,packet_info * pinfo,e_guid_t * guid,int category _U_)299 h225ras_call_t * append_h225ras_call(h225ras_call_t *prev_call, packet_info *pinfo, e_guid_t *guid, int category _U_)
300 {
301   h225ras_call_t *h225ras_call = NULL;
302 
303   /* Prepare the value data.
304      "req_num" and "rsp_num" are frame numbers;
305      frame numbers are 1-origin, so we use 0
306      to mean "we don't yet know in which frame
307      the reply for this call appears". */
308   h225ras_call = wmem_new(wmem_file_scope(), h225ras_call_t);
309   h225ras_call->req_num = pinfo->num;
310   h225ras_call->rsp_num = 0;
311   h225ras_call->requestSeqNum = prev_call->requestSeqNum;
312   h225ras_call->responded = FALSE;
313   h225ras_call->next_call = NULL;
314   h225ras_call->req_time=pinfo->abs_ts;
315   h225ras_call->guid=*guid;
316 
317   prev_call->next_call = h225ras_call;
318   return h225ras_call;
319 }
320 
321 static void
h225_frame_end(void)322 h225_frame_end(void)
323 {
324   /* next_tvb pointers are allocated in packet scope, clear it. */
325   h245_list = NULL;
326   tp_list = NULL;
327 }
328 
329 static int
dissect_h225_H323UserInformation(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)330 dissect_h225_H323UserInformation(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
331 {
332   proto_item *it;
333   proto_tree *tr;
334   int offset = 0;
335   h225_packet_info* h225_pi;
336 
337   /* Init struct for collecting h225_packet_info */
338   h225_pi = create_h225_packet_info(pinfo);
339   h225_pi->msg_type = H225_CS;
340   p_add_proto_data(pinfo->pool, pinfo, proto_h225, 0, h225_pi);
341 
342   register_frame_end_routine(pinfo, h225_frame_end);
343   h245_list = next_tvb_list_new(pinfo->pool);
344   tp_list = next_tvb_list_new(pinfo->pool);
345 
346   col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
347   col_clear(pinfo->cinfo, COL_INFO);
348 
349   it=proto_tree_add_protocol_format(tree, proto_h225, tvb, 0, -1, PSNAME" CS");
350   tr=proto_item_add_subtree(it, ett_h225);
351 
352   offset = dissect_H323_UserInformation_PDU(tvb, pinfo, tr, NULL);
353 
354   if (h245_list->count){
355     col_append_str(pinfo->cinfo, COL_PROTOCOL, "/");
356     col_set_fence(pinfo->cinfo, COL_PROTOCOL);
357   }
358 
359   next_tvb_call(h245_list, pinfo, tree, h245dg_handle, data_handle);
360   next_tvb_call(tp_list, pinfo, tree, NULL, data_handle);
361 
362   tap_queue_packet(h225_tap, pinfo, h225_pi);
363 
364   return offset;
365 }
366 static int
dissect_h225_h225_RasMessage(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)367 dissect_h225_h225_RasMessage(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_){
368   proto_item *it;
369   proto_tree *tr;
370   guint32 offset=0;
371   h225_packet_info* h225_pi;
372 
373   /* Init struct for collecting h225_packet_info */
374   h225_pi = create_h225_packet_info(pinfo);
375   h225_pi->msg_type = H225_RAS;
376   p_add_proto_data(pinfo->pool, pinfo, proto_h225, 0, h225_pi);
377 
378   register_frame_end_routine(pinfo, h225_frame_end);
379   h245_list = next_tvb_list_new(pinfo->pool);
380   tp_list = next_tvb_list_new(pinfo->pool);
381 
382   col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
383 
384   it=proto_tree_add_protocol_format(tree, proto_h225, tvb, offset, -1, PSNAME" RAS");
385   tr=proto_item_add_subtree(it, ett_h225);
386 
387   offset = dissect_RasMessage_PDU(tvb, pinfo, tr, NULL);
388 
389   ras_call_matching(tvb, pinfo, tr, h225_pi);
390 
391   next_tvb_call(h245_list, pinfo, tree, h245dg_handle, data_handle);
392   next_tvb_call(tp_list, pinfo, tree, NULL, data_handle);
393 
394   tap_queue_packet(h225_tap, pinfo, h225_pi);
395 
396   return offset;
397 }
398 
399 
400 /* The following values represent the size of their valuestring arrays */
401 
402 #define RAS_MSG_TYPES (sizeof(h225_RasMessage_vals) / sizeof(value_string))
403 #define CS_MSG_TYPES (sizeof(T_h323_message_body_vals) / sizeof(value_string))
404 
405 #define GRJ_REASONS (sizeof(GatekeeperRejectReason_vals) / sizeof(value_string))
406 #define RRJ_REASONS (sizeof(RegistrationRejectReason_vals) / sizeof(value_string))
407 #define URQ_REASONS (sizeof(UnregRequestReason_vals) / sizeof(value_string))
408 #define URJ_REASONS (sizeof(UnregRejectReason_vals) / sizeof(value_string))
409 #define ARJ_REASONS (sizeof(AdmissionRejectReason_vals) / sizeof(value_string))
410 #define BRJ_REASONS (sizeof(BandRejectReason_vals) / sizeof(value_string))
411 #define DRQ_REASONS (sizeof(DisengageReason_vals) / sizeof(value_string))
412 #define DRJ_REASONS (sizeof(DisengageRejectReason_vals) / sizeof(value_string))
413 #define LRJ_REASONS (sizeof(LocationRejectReason_vals) / sizeof(value_string))
414 #define IRQNAK_REASONS (sizeof(InfoRequestNakReason_vals) / sizeof(value_string))
415 #define REL_CMP_REASONS (sizeof(h225_ReleaseCompleteReason_vals) / sizeof(value_string))
416 #define FACILITY_REASONS (sizeof(FacilityReason_vals) / sizeof(value_string))
417 
418 /* TAP STAT INFO */
419 typedef enum
420 {
421   MESSAGE_TYPE_COLUMN = 0,
422   COUNT_COLUMN
423 } h225_stat_columns;
424 
425 typedef struct _h225_table_item {
426   guint count;     /* Message count */
427   guint table_idx; /* stat_table index */
428 } h225_table_item_t;
429 
430 static stat_tap_table_item h225_stat_fields[] = {{TABLE_ITEM_STRING, TAP_ALIGN_LEFT, "Message Type or Reason", "%-25s"}, {TABLE_ITEM_UINT, TAP_ALIGN_RIGHT, "Count", "%d"}};
431 
432 static guint ras_msg_idx[RAS_MSG_TYPES];
433 static guint cs_msg_idx[CS_MSG_TYPES];
434 
435 static guint grj_reason_idx[GRJ_REASONS];
436 static guint rrj_reason_idx[RRJ_REASONS];
437 static guint urq_reason_idx[URQ_REASONS];
438 static guint urj_reason_idx[URJ_REASONS];
439 static guint arj_reason_idx[ARJ_REASONS];
440 static guint brj_reason_idx[BRJ_REASONS];
441 static guint drq_reason_idx[DRQ_REASONS];
442 static guint drj_reason_idx[DRJ_REASONS];
443 static guint lrj_reason_idx[LRJ_REASONS];
444 static guint irqnak_reason_idx[IRQNAK_REASONS];
445 static guint rel_cmp_reason_idx[REL_CMP_REASONS];
446 static guint facility_reason_idx[FACILITY_REASONS];
447 
448 static guint other_idx;
449 
h225_stat_init(stat_tap_table_ui * new_stat)450 static void h225_stat_init(stat_tap_table_ui* new_stat)
451 {
452   const char *table_name = "H.225 Messages and Message Reasons";
453   int num_fields = sizeof(h225_stat_fields)/sizeof(stat_tap_table_item);
454   stat_tap_table *table;
455   int row_idx = 0, msg_idx;
456   stat_tap_table_item_type items[sizeof(h225_stat_fields)/sizeof(stat_tap_table_item)];
457 
458   table = stat_tap_find_table(new_stat, table_name);
459   if (table) {
460     if (new_stat->stat_tap_reset_table_cb) {
461       new_stat->stat_tap_reset_table_cb(table);
462     }
463     return;
464   }
465 
466   table = stat_tap_init_table(table_name, num_fields, 0, NULL);
467   stat_tap_add_table(new_stat, table);
468 
469   items[MESSAGE_TYPE_COLUMN].type = TABLE_ITEM_STRING;
470   items[COUNT_COLUMN].type = TABLE_ITEM_UINT;
471   items[COUNT_COLUMN].value.uint_value = 0;
472 
473   /* Add a row for each value type */
474 
475   msg_idx = 0;
476   do
477   {
478     items[MESSAGE_TYPE_COLUMN].value.string_value =
479       h225_RasMessage_vals[msg_idx].strptr
480       ? h225_RasMessage_vals[msg_idx].strptr
481       : "Unknown RAS message";
482     ras_msg_idx[msg_idx] = row_idx;
483 
484     stat_tap_init_table_row(table, row_idx, num_fields, items);
485     row_idx++;
486     msg_idx++;
487   } while (h225_RasMessage_vals[msg_idx].strptr);
488 
489   msg_idx = 0;
490   do
491   {
492     items[MESSAGE_TYPE_COLUMN].value.string_value =
493       T_h323_message_body_vals[msg_idx].strptr
494       ? T_h323_message_body_vals[msg_idx].strptr
495       : "Unknown CS message";
496     cs_msg_idx[msg_idx] = row_idx;
497 
498     stat_tap_init_table_row(table, row_idx, num_fields, items);
499     row_idx++;
500     msg_idx++;
501   } while (T_h323_message_body_vals[msg_idx].strptr);
502 
503   msg_idx = 0;
504   do
505   {
506     items[MESSAGE_TYPE_COLUMN].value.string_value =
507       GatekeeperRejectReason_vals[msg_idx].strptr
508       ? GatekeeperRejectReason_vals[msg_idx].strptr
509       : "Unknown gatekeeper reject reason";
510     grj_reason_idx[msg_idx] = row_idx;
511 
512     stat_tap_init_table_row(table, row_idx, num_fields, items);
513     row_idx++;
514     msg_idx++;
515   } while (GatekeeperRejectReason_vals[msg_idx].strptr);
516 
517   msg_idx = 0;
518   do
519   {
520     items[MESSAGE_TYPE_COLUMN].value.string_value =
521       RegistrationRejectReason_vals[msg_idx].strptr
522       ? RegistrationRejectReason_vals[msg_idx].strptr
523       : "Unknown registration reject reason";
524     rrj_reason_idx[msg_idx] = row_idx;
525 
526     stat_tap_init_table_row(table, row_idx, num_fields, items);
527     row_idx++;
528     msg_idx++;
529   } while (RegistrationRejectReason_vals[msg_idx].strptr);
530 
531   msg_idx = 0;
532   do
533   {
534     items[MESSAGE_TYPE_COLUMN].value.string_value =
535       UnregRequestReason_vals[msg_idx].strptr
536       ? UnregRequestReason_vals[msg_idx].strptr
537       : "Unknown unregistration request reason";
538     urq_reason_idx[msg_idx] = row_idx;
539 
540     stat_tap_init_table_row(table, row_idx, num_fields, items);
541     row_idx++;
542     msg_idx++;
543   } while (UnregRequestReason_vals[msg_idx].strptr);
544 
545   msg_idx = 0;
546   do
547   {
548     items[MESSAGE_TYPE_COLUMN].value.string_value =
549       UnregRejectReason_vals[msg_idx].strptr
550       ? UnregRejectReason_vals[msg_idx].strptr
551       : "Unknown unregistration reject reason";
552     urj_reason_idx[msg_idx] = row_idx;
553 
554     stat_tap_init_table_row(table, row_idx, num_fields, items);
555     row_idx++;
556     msg_idx++;
557   } while (UnregRejectReason_vals[msg_idx].strptr);
558 
559   msg_idx = 0;
560   do
561   {
562     items[MESSAGE_TYPE_COLUMN].value.string_value =
563       AdmissionRejectReason_vals[msg_idx].strptr
564       ? AdmissionRejectReason_vals[msg_idx].strptr
565       : "Unknown admission reject reason";
566     arj_reason_idx[msg_idx] = row_idx;
567 
568     stat_tap_init_table_row(table, row_idx, num_fields, items);
569     row_idx++;
570     msg_idx++;
571   } while (AdmissionRejectReason_vals[msg_idx].strptr);
572 
573   msg_idx = 0;
574   do
575   {
576     items[MESSAGE_TYPE_COLUMN].value.string_value =
577       BandRejectReason_vals[msg_idx].strptr
578       ? BandRejectReason_vals[msg_idx].strptr
579       : "Unknown band reject reason";
580     brj_reason_idx[msg_idx] = row_idx;
581 
582     stat_tap_init_table_row(table, row_idx, num_fields, items);
583     row_idx++;
584     msg_idx++;
585   } while (BandRejectReason_vals[msg_idx].strptr);
586 
587   msg_idx = 0;
588   do
589   {
590     items[MESSAGE_TYPE_COLUMN].value.string_value =
591       DisengageReason_vals[msg_idx].strptr
592       ? DisengageReason_vals[msg_idx].strptr
593       : "Unknown disengage reason";
594     drq_reason_idx[msg_idx] = row_idx;
595 
596     stat_tap_init_table_row(table, row_idx, num_fields, items);
597     row_idx++;
598     msg_idx++;
599   } while (DisengageReason_vals[msg_idx].strptr);
600 
601   msg_idx = 0;
602   do
603   {
604     items[MESSAGE_TYPE_COLUMN].value.string_value =
605       DisengageRejectReason_vals[msg_idx].strptr
606       ? DisengageRejectReason_vals[msg_idx].strptr
607       : "Unknown disengage reject reason";
608     drj_reason_idx[msg_idx] = row_idx;
609 
610     stat_tap_init_table_row(table, row_idx, num_fields, items);
611     row_idx++;
612     msg_idx++;
613   } while (DisengageRejectReason_vals[msg_idx].strptr);
614 
615   msg_idx = 0;
616   do
617   {
618     items[MESSAGE_TYPE_COLUMN].value.string_value =
619       LocationRejectReason_vals[msg_idx].strptr
620       ? LocationRejectReason_vals[msg_idx].strptr
621       : "Unknown location reject reason";
622     lrj_reason_idx[msg_idx] = row_idx;
623 
624     stat_tap_init_table_row(table, row_idx, num_fields, items);
625     row_idx++;
626     msg_idx++;
627   } while (LocationRejectReason_vals[msg_idx].strptr);
628 
629   msg_idx = 0;
630   do
631   {
632     items[MESSAGE_TYPE_COLUMN].value.string_value =
633       InfoRequestNakReason_vals[msg_idx].strptr
634       ? InfoRequestNakReason_vals[msg_idx].strptr
635       : "Unknown info request nak reason";
636     irqnak_reason_idx[msg_idx] = row_idx;
637 
638     stat_tap_init_table_row(table, row_idx, num_fields, items);
639     row_idx++;
640     msg_idx++;
641   } while (InfoRequestNakReason_vals[msg_idx].strptr);
642 
643   msg_idx = 0;
644   do
645   {
646     items[MESSAGE_TYPE_COLUMN].value.string_value =
647       h225_ReleaseCompleteReason_vals[msg_idx].strptr
648       ? h225_ReleaseCompleteReason_vals[msg_idx].strptr
649       : "Unknown release complete reason";
650     rel_cmp_reason_idx[msg_idx] = row_idx;
651 
652     stat_tap_init_table_row(table, row_idx, num_fields, items);
653     row_idx++;
654     msg_idx++;
655   } while (h225_ReleaseCompleteReason_vals[msg_idx].strptr);
656 
657   msg_idx = 0;
658   do
659   {
660     items[MESSAGE_TYPE_COLUMN].value.string_value =
661       FacilityReason_vals[msg_idx].strptr
662       ? FacilityReason_vals[msg_idx].strptr
663       : "Unknown facility reason";
664     facility_reason_idx[msg_idx] = row_idx;
665 
666     stat_tap_init_table_row(table, row_idx, num_fields, items);
667     row_idx++;
668     msg_idx++;
669   } while (FacilityReason_vals[msg_idx].strptr);
670 
671 
672   items[MESSAGE_TYPE_COLUMN].value.string_value = "Unknown H.225 message";
673   stat_tap_init_table_row(table, row_idx, num_fields, items);
674   other_idx = row_idx;
675 }
676 
677 static tap_packet_status
h225_stat_packet(void * tapdata,packet_info * pinfo _U_,epan_dissect_t * edt _U_,const void * hpi_ptr)678 h225_stat_packet(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *hpi_ptr)
679 {
680   stat_data_t* stat_data = (stat_data_t*)tapdata;
681   const h225_packet_info *hpi = (const h225_packet_info *)hpi_ptr;
682   int tag_idx = -1;
683   int reason_idx = -1;
684 
685   if(hpi->msg_tag < 0) { /* uninitialized */
686     return TAP_PACKET_DONT_REDRAW;
687   }
688 
689   switch (hpi->msg_type) {
690 
691   case H225_RAS:
692     tag_idx = ras_msg_idx[MIN(hpi->msg_tag, (int)RAS_MSG_TYPES-1)];
693 
694     /* Look for reason tag */
695     if(hpi->reason < 0) { /* uninitialized */
696       break;
697     }
698 
699     switch(hpi->msg_tag) {
700 
701     case 2: /* GRJ */
702       reason_idx = grj_reason_idx[MIN(hpi->reason, (int)GRJ_REASONS-1)];
703       break;
704     case 5: /* RRJ */
705       reason_idx = rrj_reason_idx[MIN(hpi->reason, (int)RRJ_REASONS-1)];
706       break;
707     case 6: /* URQ */
708       reason_idx = urq_reason_idx[MIN(hpi->reason, (int)URQ_REASONS-1)];
709       break;
710     case 8: /* URJ */
711       reason_idx = urj_reason_idx[MIN(hpi->reason, (int)URJ_REASONS-1)];
712       break;
713     case 11: /* ARJ */
714       reason_idx = arj_reason_idx[MIN(hpi->reason, (int)ARJ_REASONS-1)];
715       break;
716     case 14: /* BRJ */
717       reason_idx = brj_reason_idx[MIN(hpi->reason, (int)BRJ_REASONS-1)];
718       break;
719     case 15: /* DRQ */
720       reason_idx = drq_reason_idx[MIN(hpi->reason, (int)DRQ_REASONS-1)];
721       break;
722     case 17: /* DRJ */
723       reason_idx = drj_reason_idx[MIN(hpi->reason, (int)DRJ_REASONS-1)];
724       break;
725     case 20: /* LRJ */
726       reason_idx = lrj_reason_idx[MIN(hpi->reason, (int)LRJ_REASONS-1)];
727       break;
728     case 29: /* IRQ Nak */
729       reason_idx = irqnak_reason_idx[MIN(hpi->reason, (int)IRQNAK_REASONS-1)];
730       break;
731     default:
732       /* do nothing */
733       break;
734     }
735 
736     break;
737 
738   case H225_CS:
739     tag_idx = cs_msg_idx[MIN(hpi->msg_tag, (int)CS_MSG_TYPES-1)];
740 
741     /* Look for reason tag */
742     if(hpi->reason < 0) { /* uninitialized */
743       break;
744     }
745 
746     switch(hpi->msg_tag) {
747 
748     case 5: /* ReleaseComplete */
749       reason_idx = rel_cmp_reason_idx[MIN(hpi->reason, (int)REL_CMP_REASONS-1)];
750       break;
751     case 6: /* Facility */
752       reason_idx = facility_reason_idx[MIN(hpi->reason, (int)FACILITY_REASONS-1)];
753       break;
754     default:
755       /* do nothing */
756       break;
757     }
758 
759     break;
760 
761   case H225_OTHERS:
762   default:
763     tag_idx = other_idx;
764   }
765 
766   if (tag_idx >= 0) {
767     stat_tap_table*table = g_array_index(stat_data->stat_tap_data->tables, stat_tap_table*, 0);
768     stat_tap_table_item_type* msg_data = stat_tap_get_field_data(table, tag_idx, COUNT_COLUMN);;
769     msg_data->value.uint_value++;
770     stat_tap_set_field_data(table, tag_idx, COUNT_COLUMN, msg_data);
771 
772     if (reason_idx >= 0) {
773       msg_data = stat_tap_get_field_data(table, reason_idx, COUNT_COLUMN);;
774       msg_data->value.uint_value++;
775       stat_tap_set_field_data(table, reason_idx, COUNT_COLUMN, msg_data);
776     }
777 
778     return TAP_PACKET_REDRAW;
779   }
780   return TAP_PACKET_DONT_REDRAW;
781 }
782 
783 static void
h225_stat_reset(stat_tap_table * table)784 h225_stat_reset(stat_tap_table* table)
785 {
786   guint element;
787   stat_tap_table_item_type* item_data;
788 
789   for (element = 0; element < table->num_elements; element++)
790   {
791     item_data = stat_tap_get_field_data(table, element, COUNT_COLUMN);
792     item_data->value.uint_value = 0;
793     stat_tap_set_field_data(table, element, COUNT_COLUMN, item_data);
794   }
795 }
796 
797 /*--- proto_register_h225 -------------------------------------------*/
proto_register_h225(void)798 void proto_register_h225(void) {
799 
800   /* List of fields */
801   static hf_register_info hf[] = {
802   { &hf_h221Manufacturer,
803     { "H.225 Manufacturer", "h225.Manufacturer", FT_UINT32, BASE_HEX,
804     VALS(H221ManufacturerCode_vals), 0, "h225.H.221 Manufacturer", HFILL }},
805 
806   { &hf_h225_ras_req_frame,
807     { "RAS Request Frame", "h225.ras.reqframe", FT_FRAMENUM, BASE_NONE,
808     NULL, 0, NULL, HFILL }},
809 
810   { &hf_h225_ras_rsp_frame,
811     { "RAS Response Frame", "h225.ras.rspframe", FT_FRAMENUM, BASE_NONE,
812     NULL, 0, NULL, HFILL }},
813 
814   { &hf_h225_ras_dup,
815     { "Duplicate RAS Message", "h225.ras.dup", FT_UINT32, BASE_DEC,
816     NULL, 0, NULL, HFILL }},
817 
818   { &hf_h225_ras_deltatime,
819     { "RAS Service Response Time", "h225.ras.timedelta", FT_RELATIVE_TIME, BASE_NONE,
820     NULL, 0, "Timedelta between RAS-Request and RAS-Response", HFILL }},
821 
822   { &hf_h225_debug_dissector_try_string,
823     { "*** DEBUG dissector_try_string", "h225.debug.dissector_try_string", FT_STRING, BASE_NONE,
824     NULL, 0, NULL, HFILL }},
825 
826 #include "packet-h225-hfarr.c"
827   };
828 
829   /* List of subtrees */
830   static gint *ett[] = {
831     &ett_h225,
832 #include "packet-h225-ettarr.c"
833   };
834 
835   static tap_param h225_stat_params[] = {
836     { PARAM_FILTER, "filter", "Filter", NULL, TRUE }
837   };
838 
839   static stat_tap_table_ui h225_stat_table = {
840     REGISTER_STAT_GROUP_TELEPHONY,
841     "H.225",
842     PFNAME,
843     "h225,counter",
844     h225_stat_init,
845     h225_stat_packet,
846     h225_stat_reset,
847     NULL,
848     NULL,
849     sizeof(h225_stat_fields)/sizeof(stat_tap_table_item), h225_stat_fields,
850     sizeof(h225_stat_params)/sizeof(tap_param), h225_stat_params,
851     NULL,
852     0
853   };
854 
855   module_t *h225_module;
856   int i, proto_h225_ras;
857 
858   /* Register protocol */
859   proto_h225 = proto_register_protocol(PNAME, PSNAME, PFNAME);
860 
861   /* Create a "fake" protocol to get proper display strings for SRT dialogs */
862   proto_h225_ras = proto_register_protocol("H.225 RAS", "H.225 RAS", "h225_ras");
863 
864   /* Register fields and subtrees */
865   proto_register_field_array(proto_h225, hf, array_length(hf));
866   proto_register_subtree_array(ett, array_length(ett));
867 
868   h225_module = prefs_register_protocol(proto_h225, proto_reg_handoff_h225);
869   prefs_register_uint_preference(h225_module, "tls.port",
870     "H.225 TLS Port",
871     "H.225 Server TLS Port",
872     10, &h225_tls_port);
873   prefs_register_bool_preference(h225_module, "reassembly",
874     "Reassemble H.225 messages spanning multiple TCP segments",
875     "Whether the H.225 dissector should reassemble messages spanning multiple TCP segments."
876     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
877     &h225_reassembly);
878   prefs_register_bool_preference(h225_module, "h245_in_tree",
879     "Display tunnelled H.245 inside H.225.0 tree",
880     "ON - display tunnelled H.245 inside H.225.0 tree, OFF - display tunnelled H.245 in root tree after H.225.0",
881     &h225_h245_in_tree);
882   prefs_register_bool_preference(h225_module, "tp_in_tree",
883     "Display tunnelled protocols inside H.225.0 tree",
884     "ON - display tunnelled protocols inside H.225.0 tree, OFF - display tunnelled protocols in root tree after H.225.0",
885     &h225_tp_in_tree);
886 
887   register_dissector(PFNAME, dissect_h225_H323UserInformation, proto_h225);
888   register_dissector("h323ui",dissect_h225_H323UserInformation, proto_h225);
889   h225ras_handle = register_dissector("h225.ras", dissect_h225_h225_RasMessage, proto_h225);
890 
891   nsp_object_dissector_table = register_dissector_table("h225.nsp.object", "H.225 NonStandardParameter Object", proto_h225, FT_STRING, BASE_NONE);
892   nsp_h221_dissector_table = register_dissector_table("h225.nsp.h221", "H.225 NonStandardParameter h221", proto_h225, FT_UINT32, BASE_HEX);
893   tp_dissector_table = register_dissector_table("h225.tp", "H.225 Tunnelled Protocol", proto_h225, FT_STRING, BASE_NONE);
894   gef_name_dissector_table = register_dissector_table("h225.gef.name", "H.225 Generic Extensible Framework Name", proto_h225, FT_STRING, BASE_NONE);
895   gef_content_dissector_table = register_dissector_table("h225.gef.content", "H.225 Generic Extensible Framework Content", proto_h225, FT_STRING, BASE_NONE);
896 
897   for(i=0;i<7;i++) {
898     ras_calls[i] = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), h225ras_call_hash, h225ras_call_equal);
899   }
900 
901   h225_tap = register_tap(PFNAME);
902 
903   register_rtd_table(proto_h225_ras, PFNAME, NUM_RAS_STATS, 1, ras_message_category, h225rassrt_packet, NULL);
904 
905   register_stat_tap_table_ui(&h225_stat_table);
906 
907   oid_add_from_string("Version 1","0.0.8.2250.0.1");
908   oid_add_from_string("Version 2","0.0.8.2250.0.2");
909   oid_add_from_string("Version 3","0.0.8.2250.0.3");
910   oid_add_from_string("Version 4","0.0.8.2250.0.4");
911   oid_add_from_string("Version 5","0.0.8.2250.0.5");
912   oid_add_from_string("Version 6","0.0.8.2250.0.6");
913 }
914 
915 
916 /*--- proto_reg_handoff_h225 ---------------------------------------*/
917 void
proto_reg_handoff_h225(void)918 proto_reg_handoff_h225(void)
919 {
920   static gboolean h225_prefs_initialized = FALSE;
921   static dissector_handle_t q931_tpkt_handle;
922   static guint saved_h225_tls_port;
923 
924   if (!h225_prefs_initialized) {
925     dissector_add_uint_range_with_preference("udp.port", UDP_PORT_RAS_RANGE, h225ras_handle);
926 
927     h245_handle = find_dissector("h245");
928     h245dg_handle = find_dissector("h245dg");
929     h4501_handle = find_dissector_add_dependency("h4501", proto_h225);
930     data_handle = find_dissector("data");
931     h225_prefs_initialized = TRUE;
932     q931_tpkt_handle = find_dissector("q931.tpkt");
933   } else {
934     ssl_dissector_delete(saved_h225_tls_port, q931_tpkt_handle);
935   }
936 
937   saved_h225_tls_port = h225_tls_port;
938   ssl_dissector_add(saved_h225_tls_port, q931_tpkt_handle);
939 }
940 
create_h225_packet_info(packet_info * pinfo)941 static h225_packet_info* create_h225_packet_info(packet_info *pinfo)
942 {
943   h225_packet_info* pi = wmem_new0(pinfo->pool, h225_packet_info);
944 
945   pi->msg_type = H225_OTHERS;
946   pi->cs_type = H225_OTHER;
947   pi->msg_tag = -1;
948   pi->reason = -1;
949 
950   return pi;
951 }
952 
953 /*
954   The following function contains the routines for RAS request/response matching.
955   A RAS response matches with a request, if both messages have the same
956   RequestSequenceNumber, belong to the same IP conversation and belong to the same
957   RAS "category" (e.g. Admission, Registration).
958 
959   We use hashtables to access the lists of RAS calls (request/response pairs).
960   We have one hashtable for each RAS category. The hashkeys consist of the
961   non-unique 16-bit RequestSequenceNumber and values representing the conversation.
962 
963   In big capture files, we might get different requests with identical keys.
964   These requests aren't necessarily duplicates. They might be valid new requests.
965   At the moment we just use the timedelta between the last valid and the new request
966   to decide if the new request is a duplicate or not. There might be better ways.
967   Two thresholds are defined below.
968 
969   However the decision is made, another problem arises. We can't just add those
970   requests to our hashtables. Instead we create lists of RAS calls with identical keys.
971   The hashtables for RAS calls contain now pointers to the first RAS call in a list of
972   RAS calls with identical keys.
973   These lists aren't expected to contain more than 3 items and are usually single item
974   lists. So we don't need an expensive but intelligent way to access these lists
975   (e.g. hashtables). Just walk through such a list.
976 */
977 
978 #define THRESHOLD_REPEATED_RESPONDED_CALL 300
979 #define THRESHOLD_REPEATED_NOT_RESPONDED_CALL 1800
980 
ras_call_matching(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,h225_packet_info * pi)981 static void ras_call_matching(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, h225_packet_info *pi)
982 {
983   proto_item *hidden_item;
984   conversation_t* conversation = NULL;
985   h225ras_call_info_key h225ras_call_key;
986   h225ras_call_t *h225ras_call = NULL;
987   nstime_t delta;
988   guint msg_category;
989 
990   if(pi->msg_type == H225_RAS && pi->msg_tag < 21) {
991     /* make RAS request/response matching only for tags from 0 to 20 for now */
992 
993     msg_category = pi->msg_tag / 3;
994     if(pi->msg_tag % 3 == 0) {    /* Request Message */
995       conversation = find_or_create_conversation(pinfo);
996 
997       /* prepare the key data */
998       h225ras_call_key.reqSeqNum = pi->requestSeqNum;
999       h225ras_call_key.conversation = conversation;
1000 
1001       /* look up the request */
1002       h225ras_call = find_h225ras_call(&h225ras_call_key ,msg_category);
1003 
1004       if (h225ras_call != NULL) {
1005         /* We've seen requests with this reqSeqNum, with the same
1006            source and destination, before - do we have
1007            *this* request already? */
1008         /* Walk through list of ras requests with identical keys */
1009         do {
1010           if (pinfo->num == h225ras_call->req_num) {
1011             /* We have seen this request before -> do nothing */
1012             break;
1013           }
1014 
1015           /* if end of list is reached, exit loop and decide if request is duplicate or not. */
1016           if (h225ras_call->next_call == NULL) {
1017             if ( (pinfo->num > h225ras_call->rsp_num && h225ras_call->rsp_num != 0
1018                && pinfo->abs_ts.secs > (h225ras_call->req_time.secs + THRESHOLD_REPEATED_RESPONDED_CALL) )
1019                ||(pinfo->num > h225ras_call->req_num && h225ras_call->rsp_num == 0
1020                && pinfo->abs_ts.secs > (h225ras_call->req_time.secs + THRESHOLD_REPEATED_NOT_RESPONDED_CALL) ) )
1021             {
1022               /* if last request has been responded
1023                  and this request appears after last response (has bigger frame number)
1024                  and last request occurred more than 300 seconds ago,
1025                  or if last request hasn't been responded
1026                  and this request appears after last request (has bigger frame number)
1027                  and last request occurred more than 1800 seconds ago,
1028                  we decide that we have a new request */
1029               /* Append new ras call to list */
1030               h225ras_call = append_h225ras_call(h225ras_call, pinfo, &pi->guid, msg_category);
1031             } else {
1032               /* No, so it's a duplicate request.
1033                  Mark it as such. */
1034               pi->is_duplicate = TRUE;
1035               hidden_item = proto_tree_add_uint(tree, hf_h225_ras_dup, tvb, 0,0, pi->requestSeqNum);
1036               proto_item_set_hidden(hidden_item);
1037             }
1038             break;
1039           }
1040           h225ras_call = h225ras_call->next_call;
1041         } while (h225ras_call != NULL );
1042       }
1043       else {
1044         h225ras_call = new_h225ras_call(&h225ras_call_key, pinfo, &pi->guid, msg_category);
1045       }
1046 
1047       /* add link to response frame, if available */
1048       if(h225ras_call && h225ras_call->rsp_num != 0){
1049         proto_item *ti =
1050         proto_tree_add_uint_format(tree, hf_h225_ras_rsp_frame, tvb, 0, 0, h225ras_call->rsp_num,
1051                                      "The response to this request is in frame %u",
1052                                      h225ras_call->rsp_num);
1053         proto_item_set_generated(ti);
1054       }
1055 
1056     /* end of request message handling*/
1057     }
1058     else {          /* Confirm or Reject Message */
1059       conversation = find_conversation_pinfo(pinfo, 0);
1060       if (conversation != NULL) {
1061         /* look only for matching request, if
1062            matching conversation is available. */
1063         h225ras_call_key.reqSeqNum = pi->requestSeqNum;
1064         h225ras_call_key.conversation = conversation;
1065         h225ras_call = find_h225ras_call(&h225ras_call_key ,msg_category);
1066         if(h225ras_call) {
1067           /* find matching ras_call in list of ras calls with identical keys */
1068           do {
1069             if (pinfo->num == h225ras_call->rsp_num) {
1070               /* We have seen this response before -> stop now with matching ras call */
1071               break;
1072             }
1073 
1074             /* Break when list end is reached */
1075             if(h225ras_call->next_call == NULL) {
1076               break;
1077             }
1078             h225ras_call = h225ras_call->next_call;
1079           } while (h225ras_call != NULL) ;
1080 
1081           if (!h225ras_call) {
1082             return;
1083           }
1084 
1085           /* if this is an ACF, ARJ or DCF, DRJ, give guid to tap and make it filterable */
1086           if (msg_category == 3 || msg_category == 5) {
1087             pi->guid = h225ras_call->guid;
1088             hidden_item = proto_tree_add_guid(tree, hf_h225_guid, tvb, 0, GUID_LEN, &pi->guid);
1089             proto_item_set_hidden(hidden_item);
1090           }
1091 
1092           if (h225ras_call->rsp_num == 0) {
1093             /* We have not yet seen a response to that call, so
1094                this must be the first response; remember its
1095                frame number. */
1096             h225ras_call->rsp_num = pinfo->num;
1097           }
1098           else {
1099             /* We have seen a response to this call - but was it
1100                *this* response? */
1101             if (h225ras_call->rsp_num != pinfo->num) {
1102               /* No, so it's a duplicate response.
1103                  Mark it as such. */
1104               pi->is_duplicate = TRUE;
1105               hidden_item = proto_tree_add_uint(tree, hf_h225_ras_dup, tvb, 0,0, pi->requestSeqNum);
1106               proto_item_set_hidden(hidden_item);
1107             }
1108           }
1109 
1110           if(h225ras_call->req_num != 0){
1111             proto_item *ti;
1112             h225ras_call->responded = TRUE;
1113             pi->request_available = TRUE;
1114 
1115             /* Indicate the frame to which this is a reply. */
1116             ti = proto_tree_add_uint_format(tree, hf_h225_ras_req_frame, tvb, 0, 0, h225ras_call->req_num,
1117               "This is a response to a request in frame %u", h225ras_call->req_num);
1118             proto_item_set_generated(ti);
1119 
1120             /* Calculate RAS Service Response Time */
1121             nstime_delta(&delta, &pinfo->abs_ts, &h225ras_call->req_time);
1122             pi->delta_time = delta; /* give it to tap */
1123 
1124             /* display Ras Service Response Time and make it filterable */
1125             ti = proto_tree_add_time(tree, hf_h225_ras_deltatime, tvb, 0, 0, &(pi->delta_time));
1126             proto_item_set_generated(ti);
1127           }
1128         }
1129       }
1130     }
1131   }
1132 }
1133 
1134 /*
1135  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1136  *
1137  * Local Variables:
1138  * c-basic-offset: 2
1139  * tab-width: 8
1140  * indent-tabs-mode: nil
1141  * End:
1142  *
1143  * vi: set shiftwidth=2 tabstop=8 expandtab:
1144  * :indentSize=2:tabSize=8:noTabs=true:
1145  */
1146