Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-mgcp.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-mgcp.c
2
 * Routines for mgcp packet disassembly
3
 * RFC 2705
4
 * RFC 3435 (obsoletes 2705): Media Gateway Control Protocol (MGCP) Version 1.0
5
 * RFC 3660: Basic MGCP Packages
6
 * RFC 3661: MGCP Return Code Usage
7
 * NCS 1.0: PacketCable Network-Based Call Signaling Protocol Specification,
8
 *          PKT-SP-EC-MGCP-I09-040113, January 13, 2004, Cable Television
9
 *          Laboratories, Inc., http://www.PacketCable.com/
10
 * NCS 1.5: PKT-SP-NCS1.5-I04-120412, April 12, 2012 Cable Television
11
 *          Laboratories, Inc., http://www.PacketCable.com/
12
 * www.iana.org/assignments/mgcp-localconnectionoptions
13
 *
14
 * Copyright (c) 2000 by Ed Warnicke <hagbard@physics.rutgers.edu>
15
 * Copyright (c) 2004 by Thomas Anders <thomas.anders [AT] blue-cable.de>
16
 *
17
 * Wireshark - Network traffic analyzer
18
 * By Gerald Combs <gerald@wireshark.org>
19
 * Copyright 1999 Gerald Combs
20
 *
21
 * SPDX-License-Identifier: GPL-2.0-or-later
22
 */
23
24
0
#define WS_LOG_DOMAIN "packet-mgcp"
25
26
#include "config.h"
27
#include <wireshark.h>
28
29
#include <stdlib.h>
30
31
#include <epan/packet.h>
32
#include <epan/exceptions.h>
33
#include <epan/prefs.h>
34
#include <epan/conversation.h>
35
#include <epan/tap.h>
36
#include <epan/strutil.h>
37
#include <epan/rtd_table.h>
38
#include <epan/expert.h>
39
#include "packet-media-type.h"
40
#include "packet-mgcp.h"
41
#include "packet-sdp.h"
42
43
#include <wsutil/strtoi.h>
44
45
#define TCP_PORT_MGCP_GATEWAY 2427
46
#define UDP_PORT_MGCP_GATEWAY 2427
47
#define TCP_PORT_MGCP_CALLAGENT 2727
48
#define UDP_PORT_MGCP_CALLAGENT 2727
49
50
51
/* Define the mgcp proto */
52
static int proto_mgcp;
53
54
/* Define many many headers for mgcp */
55
static int hf_mgcp_req;
56
static int hf_mgcp_req_verb;
57
static int hf_mgcp_req_endpoint;
58
static int hf_mgcp_req_frame;
59
static int hf_mgcp_rsp;
60
static int hf_mgcp_rsp_frame;
61
static int hf_mgcp_time;
62
static int hf_mgcp_transid;
63
static int hf_mgcp_version;
64
static int hf_mgcp_rsp_rspcode;
65
static int hf_mgcp_rsp_rspstring;
66
static int hf_mgcp_params;
67
static int hf_mgcp_param_rspack;
68
static int hf_mgcp_param_bearerinfo;
69
static int hf_mgcp_param_callid;
70
static int hf_mgcp_param_connectionid;
71
static int hf_mgcp_param_secondconnectionid;
72
static int hf_mgcp_param_notifiedentity;
73
static int hf_mgcp_param_requestid;
74
static int hf_mgcp_param_localconnoptions;
75
static int hf_mgcp_param_localconnoptions_p;
76
static int hf_mgcp_param_localconnoptions_a;
77
static int hf_mgcp_param_localconnoptions_s;
78
static int hf_mgcp_param_localconnoptions_e;
79
static int hf_mgcp_param_localconnoptions_scrtp;
80
static int hf_mgcp_param_localconnoptions_scrtcp;
81
static int hf_mgcp_param_localconnoptions_b;
82
static int hf_mgcp_param_localconnoptions_esccd;
83
static int hf_mgcp_param_localconnoptions_escci;
84
static int hf_mgcp_param_localconnoptions_dqgi;
85
static int hf_mgcp_param_localconnoptions_dqrd;
86
static int hf_mgcp_param_localconnoptions_dqri;
87
static int hf_mgcp_param_localconnoptions_dqrr;
88
static int hf_mgcp_param_localconnoptions_k;
89
static int hf_mgcp_param_localconnoptions_gc;
90
static int hf_mgcp_param_localconnoptions_fmtp;
91
static int hf_mgcp_param_localconnoptions_nt;
92
static int hf_mgcp_param_localconnoptions_ofmtp;
93
static int hf_mgcp_param_localconnoptions_r;
94
static int hf_mgcp_param_localconnoptions_t;
95
static int hf_mgcp_param_localconnoptions_rcnf;
96
static int hf_mgcp_param_localconnoptions_rdir;
97
static int hf_mgcp_param_localconnoptions_rsh;
98
static int hf_mgcp_param_localconnoptions_mp;
99
static int hf_mgcp_param_localconnoptions_fxr;
100
static int hf_mgcp_param_localvoicemetrics;
101
static int hf_mgcp_param_remotevoicemetrics;
102
static int hf_mgcp_param_voicemetrics_nlr;
103
static int hf_mgcp_param_voicemetrics_jdr;
104
static int hf_mgcp_param_voicemetrics_bld;
105
static int hf_mgcp_param_voicemetrics_gld;
106
static int hf_mgcp_param_voicemetrics_bd;
107
static int hf_mgcp_param_voicemetrics_gd;
108
static int hf_mgcp_param_voicemetrics_rtd;
109
static int hf_mgcp_param_voicemetrics_esd;
110
static int hf_mgcp_param_voicemetrics_sl;
111
static int hf_mgcp_param_voicemetrics_nl;
112
static int hf_mgcp_param_voicemetrics_rerl;
113
static int hf_mgcp_param_voicemetrics_gmn;
114
static int hf_mgcp_param_voicemetrics_nsr;
115
static int hf_mgcp_param_voicemetrics_xsr;
116
static int hf_mgcp_param_voicemetrics_mlq;
117
static int hf_mgcp_param_voicemetrics_mcq;
118
static int hf_mgcp_param_voicemetrics_plc;
119
static int hf_mgcp_param_voicemetrics_jba;
120
static int hf_mgcp_param_voicemetrics_jbr;
121
static int hf_mgcp_param_voicemetrics_jbn;
122
static int hf_mgcp_param_voicemetrics_jbm;
123
static int hf_mgcp_param_voicemetrics_jbs;
124
static int hf_mgcp_param_voicemetrics_iaj;
125
static int hf_mgcp_param_connectionmode;
126
static int hf_mgcp_param_reqevents;
127
static int hf_mgcp_param_restartmethod;
128
static int hf_mgcp_param_restartdelay;
129
static int hf_mgcp_param_signalreq;
130
static int hf_mgcp_param_digitmap;
131
static int hf_mgcp_param_observedevent;
132
static int hf_mgcp_param_connectionparam;
133
static int hf_mgcp_param_connectionparam_ps;
134
static int hf_mgcp_param_connectionparam_os;
135
static int hf_mgcp_param_connectionparam_pr;
136
static int hf_mgcp_param_connectionparam_or;
137
static int hf_mgcp_param_connectionparam_pl;
138
static int hf_mgcp_param_connectionparam_ji;
139
static int hf_mgcp_param_connectionparam_la;
140
static int hf_mgcp_param_connectionparam_pcrps;
141
static int hf_mgcp_param_connectionparam_pcros;
142
static int hf_mgcp_param_connectionparam_pcrpl;
143
static int hf_mgcp_param_connectionparam_pcrji;
144
static int hf_mgcp_param_connectionparam_x;
145
static int hf_mgcp_param_reasoncode;
146
static int hf_mgcp_param_eventstates;
147
static int hf_mgcp_param_specificendpoint;
148
static int hf_mgcp_param_secondendpointid;
149
static int hf_mgcp_param_reqinfo;
150
static int hf_mgcp_param_quarantinehandling;
151
static int hf_mgcp_param_detectedevents;
152
static int hf_mgcp_param_capabilities;
153
static int hf_mgcp_param_maxmgcpdatagram;
154
static int hf_mgcp_param_packagelist;
155
static int hf_mgcp_param_extension;
156
static int hf_mgcp_param_extension_critical;
157
static int hf_mgcp_param_resourceid;
158
static int hf_mgcp_param_invalid;
159
static int hf_mgcp_messagecount;
160
static int hf_mgcp_dup;
161
static int hf_mgcp_req_dup;
162
static int hf_mgcp_req_dup_frame;
163
static int hf_mgcp_rsp_dup;
164
static int hf_mgcp_rsp_dup_frame;
165
static int hf_mgcp_param_x_osmux;
166
static int hf_mgcp_unknown_parameter;
167
static int hf_mgcp_malformed_parameter;
168
169
static expert_field ei_mgcp_rsp_rspcode_invalid;
170
171
static const value_string mgcp_return_code_vals[] = {
172
  {000, "Response Acknowledgement"},
173
  {100, "The transaction is currently being executed.  An actual completion message will follow on later."},
174
  {101, "The transaction has been queued for execution.  An actual completion message will follow later."},
175
  {200, "The requested transaction was executed normally."},
176
  {250, "The connection was deleted."},
177
  {400, "The transaction could not be executed, due to a transient error."},
178
  {401, "The phone is already off hook"},
179
  {402, "The phone is already on hook"},
180
  {403, "The transaction could not be executed, because the endpoint does not have sufficient resources at this time"},
181
  {404, "Insufficient bandwidth at this time"},
182
  {405, "The transaction could not be executed, because the endpoint is \"restarting\"."},
183
  {406, "Transaction time-out.  The transaction did not complete in a reasonable period of time and has been aborted."},
184
  {407, "Transaction aborted.  The transaction was aborted by some external action, e.g., a ModifyConnection command aborted by a DeleteConnection command."},
185
  {409, "The transaction could not be executed because of internal overload."},
186
  {410, "No endpoint available.  A valid \"any of\" wildcard was used, however there was no endpoint available to satisfy the request."},
187
  {500, "The transaction could not be executed, because the endpoint is unknown."},
188
  {501, "The transaction could not be executed, because the endpoint is not ready."},
189
  {502, "The transaction could not be executed, because the endpoint does not have sufficient resources"},
190
  {503, "\"All of\" wildcard too complicated."},
191
  {504, "Unknown or unsupported command."},
192
  {505, "Unsupported RemoteConnectionDescriptor."},
193
  {506, "Unable to satisfy both LocalConnectionOptions and RemoteConnectionDescriptor."},
194
  {507, "Unsupported functionality."},
195
  {508, "Unknown or unsupported quarantine handling."},
196
  {509, "Error in RemoteConnectionDescriptor."},
197
  {510, "The transaction could not be executed, because a protocol error was detected."},
198
  {511, "The transaction could not be executed, because the command contained an unrecognized extension."},
199
  {512, "The transaction could not be executed, because the gateway is not equipped to detect one of the requested events."},
200
  {513, "The transaction could not be executed, because the gateway is not equipped to generate one of the requested signals."},
201
  {514, "The transaction could not be executed, because the gateway cannot send the specified announcement."},
202
  {515, "The transaction refers to an incorrect connection-id (may have been already deleted)"},
203
  {516, "The transaction refers to an unknown call-id."},
204
  {517, "Unsupported or invalid mode."},
205
  {518, "Unsupported or unknown package."},
206
  {519, "Endpoint does not have a digit map."},
207
  {520, "The transaction could not be executed, because the endpoint is 'restarting'."},
208
  {521, "Endpoint redirected to another Call Agent."},
209
  {522, "No such event or signal."},
210
  {523, "Unknown action or illegal combination of actions"},
211
  {524, "Internal inconsistency in LocalConnectionOptions"},
212
  {525, "Unknown extension in LocalConnectionOptions"},
213
  {526, "Insufficient bandwidth"},
214
  {527, "Missing RemoteConnectionDescriptor"},
215
  {528, "Incompatible protocol version"},
216
  {529, "Internal hardware failure"},
217
  {530, "CAS signaling protocol error."},
218
  {531, "failure of a grouping of trunks (e.g. facility failure)."},
219
  {532, "Unsupported value(s) in LocalConnectionOptions."},
220
  {533, "Response too large."},
221
  {534, "Codec negotiation failure."},
222
  {535, "Packetization period not supported"},
223
  {536, "Unknown or unsupported RestartMethod"},
224
  {537, "Unknown or unsupported digit map extension"},
225
  {538, "Event/signal parameter error (e.g., missing, erroneous, unsupported, unknown, etc.)"},
226
  {539, "Invalid or unsupported command parameter."},
227
  {540, "Per endpoint connection limit exceeded."},
228
  {541, "Invalid or unsupported LocalConnectionOptions"},
229
  {0,   NULL }
230
};
231
static value_string_ext mgcp_return_code_vals_ext = VALUE_STRING_EXT_INIT(mgcp_return_code_vals);
232
233
/* TODO: add/use when tested/have capture to test with */
234
/*
235
static const value_string mgcp_reason_code_vals[] = {
236
  {0,   "Endpoint state is normal"},
237
  {900, "Endpoint malfunctioning."},
238
  {901, "Endpoint taken out-of-service."},
239
  {902, "Loss of lower layer connectivity (e.g., downstream sync)."},
240
  {903, "QoS resource reservation was lost."},
241
  {904, "Manual intervention."},
242
  {905, "Facility failure (e.g., DS-0 failure)."},
243
  {0,   NULL }
244
};
245
*/
246
247
248
/*
249
 * Define the trees for mgcp
250
 * We need one for MGCP itself, one for the MGCP paramters and one
251
 * for each of the dissected parameters
252
 */
253
static int ett_mgcp;
254
static int ett_mgcp_param;
255
static int ett_mgcp_param_connectionparam;
256
static int ett_mgcp_param_localconnectionoptions;
257
static int ett_mgcp_param_localvoicemetrics;
258
static int ett_mgcp_param_remotevoicemetrics;
259
260
/*
261
 * Define the tap for mgcp
262
 */
263
static int mgcp_tap;
264
265
/*
266
 * Here are the global variables associated with
267
 * the various user definable characteristics of the dissection
268
 *
269
 * MGCP has two kinds of "agents", gateways and callagents.  Callagents
270
 * control gateways in a master/slave sort of arrangement.  Since gateways
271
 * and callagents have different well known ports and could both
272
 * operate under either udp or tcp we have rather a lot of port info to
273
 * specify.
274
 *
275
 * global_mgcp_raw_text determines whether we are going to display
276
 * the raw text of the mgcp message, much like the HTTP dissector does.
277
 *
278
 */
279
static unsigned global_mgcp_gateway_tcp_port   = TCP_PORT_MGCP_GATEWAY;
280
static unsigned global_mgcp_gateway_udp_port   = UDP_PORT_MGCP_GATEWAY;
281
static unsigned global_mgcp_callagent_tcp_port = TCP_PORT_MGCP_CALLAGENT;
282
static unsigned global_mgcp_callagent_udp_port = UDP_PORT_MGCP_CALLAGENT;
283
static bool global_mgcp_raw_text;
284
static bool global_mgcp_message_count;
285
286
/* Some basic utility functions that are specific to this dissector */
287
static bool is_mgcp_verb(tvbuff_t *tvb, int offset, int maxlength, const char **verb_name);
288
static bool is_mgcp_rspcode(tvbuff_t *tvb, int offset, int maxlength);
289
static int tvb_parse_param(tvbuff_t *tvb, int offset, int maxlength, int** hf, mgcp_info_t* mi);
290
291
/*
292
 * The various functions that either dissect some
293
 * subpart of MGCP.  These aren't really proto dissectors but they
294
 * are written in the same style.
295
 */
296
static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
297
         proto_tree *mgcp_tree, proto_tree *ti);
298
static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, mgcp_info_t* mi);
299
static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree, mgcp_info_t* mi);
300
static void dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb,
301
            int offset, int param_type_len,
302
            int param_val_len);
303
static void dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb,
304
            int offset, int param_type_len,
305
            int param_val_len);
306
static void dissect_mgcp_localvoicemetrics(proto_tree *parent_tree, tvbuff_t *tvb,
307
            int offset, int param_type_len,
308
            int param_val_len);
309
static void dissect_mgcp_remotevoicemetrics(proto_tree *parent_tree, tvbuff_t *tvb,
310
            int offset, int param_type_len,
311
            int param_val_len);
312
313
static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
314
315
14
#define NUM_TIMESTATS 11
316
317
static const value_string mgcp_message_type[] = {
318
  {  0, "Overall"},
319
  {  1, "EPCF   "},
320
  {  2, "CRCX   "},
321
  {  3, "MDCX   "},
322
  {  4, "DLCX   "},
323
  {  5, "RQNT   "},
324
  {  6, "NTFY   "},
325
  {  7, "AUEP   "},
326
  {  8, "AUCX   "},
327
  {  9, "RSIP   "},
328
  {  0, NULL}
329
};
330
331
static tap_packet_status
332
mgcpstat_packet(void *pms, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pmi, tap_flags_t flags _U_)
333
0
{
334
0
  rtd_data_t* rtd_data = (rtd_data_t*)pms;
335
0
  rtd_stat_table* ms = &rtd_data->stat_table;
336
0
  const mgcp_info_t *mi = (const mgcp_info_t *)pmi;
337
0
  nstime_t delta;
338
0
  tap_packet_status ret = TAP_PACKET_DONT_REDRAW;
339
340
0
  switch (mi->mgcp_type) {
341
342
0
  case MGCP_REQUEST:
343
0
    if (mi->is_duplicate) {
344
      /* Duplicate is ignored */
345
0
      ms->time_stats[0].req_dup_num++;
346
0
    }
347
0
    else {
348
0
      ms->time_stats[0].open_req_num++;
349
0
    }
350
0
    break;
351
352
0
  case MGCP_RESPONSE:
353
0
    if (mi->is_duplicate) {
354
      /* Duplicate is ignored */
355
0
      ms->time_stats[0].rsp_dup_num++;
356
0
    }
357
0
    else if (!mi->request_available) {
358
      /* no request was seen */
359
0
      ms->time_stats[0].disc_rsp_num++;
360
0
    }
361
0
    else {
362
0
      ms->time_stats[0].open_req_num--;
363
      /* calculate time delta between request and response */
364
0
      nstime_delta(&delta, &pinfo->abs_ts, &mi->req_time);
365
366
0
      time_stat_update(&(ms->time_stats[0].rtd[0]), &delta, pinfo);
367
368
0
      if (g_ascii_strncasecmp(mi->code, "EPCF", 4) == 0 ) {
369
0
        time_stat_update(&(ms->time_stats[0].rtd[1]), &delta, pinfo);
370
0
      }
371
0
      else if (g_ascii_strncasecmp(mi->code, "CRCX", 4) == 0 ) {
372
0
        time_stat_update(&(ms->time_stats[0].rtd[2]), &delta, pinfo);
373
0
      }
374
0
      else if (g_ascii_strncasecmp(mi->code, "MDCX", 4) == 0 ) {
375
0
        time_stat_update(&(ms->time_stats[0].rtd[3]), &delta, pinfo);
376
0
      }
377
0
      else if (g_ascii_strncasecmp(mi->code, "DLCX", 4) == 0 ) {
378
0
        time_stat_update(&(ms->time_stats[0].rtd[4]), &delta, pinfo);
379
0
      }
380
0
      else if (g_ascii_strncasecmp(mi->code, "RQNT", 4) == 0 ) {
381
0
        time_stat_update(&(ms->time_stats[0].rtd[5]), &delta, pinfo);
382
0
      }
383
0
      else if (g_ascii_strncasecmp(mi->code, "NTFY", 4) == 0 ) {
384
0
        time_stat_update(&(ms->time_stats[0].rtd[6]), &delta, pinfo);
385
0
      }
386
0
      else if (g_ascii_strncasecmp(mi->code, "AUEP", 4) == 0 ) {
387
0
        time_stat_update(&(ms->time_stats[0].rtd[7]), &delta, pinfo);
388
0
      }
389
0
      else if (g_ascii_strncasecmp(mi->code, "AUCX", 4) == 0 ) {
390
0
        time_stat_update(&(ms->time_stats[0].rtd[8]), &delta, pinfo);
391
0
      }
392
0
      else if (g_ascii_strncasecmp(mi->code, "RSIP", 4) == 0 ) {
393
0
        time_stat_update(&(ms->time_stats[0].rtd[9]), &delta, pinfo);
394
0
      }
395
0
      else {
396
0
        time_stat_update(&(ms->time_stats[0].rtd[10]), &delta, pinfo);
397
0
      }
398
399
0
      ret = TAP_PACKET_REDRAW;
400
0
    }
401
0
    break;
402
403
0
  default:
404
0
    break;
405
0
  }
406
407
0
  return ret;
408
0
}
409
410
411
/*
412
 * Some functions which should be moved to a library
413
 * as I think that people may find them of general usefulness.
414
 */
415
static int tvb_find_null_line(tvbuff_t* tvb, int offset, int len, int* next_offset);
416
static int tvb_find_dot_line(tvbuff_t* tvb, int offset, int len, int* next_offset);
417
418
static dissector_handle_t sdp_handle;
419
static dissector_handle_t mgcp_handle;
420
extern void
421
dissect_asciitpkt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
422
      dissector_handle_t subdissector_handle);
423
extern uint16_t is_asciitpkt(tvbuff_t *tvb);
424
425
/*
426
 * Init Hash table stuff
427
 */
428
429
typedef struct _mgcp_call_info_key
430
{
431
  uint32_t transid;
432
  conversation_t *conversation;
433
} mgcp_call_info_key;
434
435
static wmem_map_t *mgcp_calls;
436
437
/* Compare 2 keys */
438
static int mgcp_call_equal(const void *k1, const void *k2)
439
165
{
440
165
  const mgcp_call_info_key* key1 = (const mgcp_call_info_key*) k1;
441
165
  const mgcp_call_info_key* key2 = (const mgcp_call_info_key*) k2;
442
443
165
  return (key1->transid == key2->transid &&
444
165
          key1->conversation == key2->conversation);
445
165
}
446
447
/* Calculate a hash key */
448
static unsigned mgcp_call_hash(const void *k)
449
181
{
450
181
  const mgcp_call_info_key* key = (const mgcp_call_info_key*) k;
451
452
181
  return key->transid  + key->conversation->conv_index;
453
181
}
454
455
456
/************************************************************************
457
 * dissect_mgcp - The dissector for the Media Gateway Control Protocol
458
 ************************************************************************/
459
static int dissect_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
460
269
{
461
269
  int sectionlen;
462
269
  uint32_t num_messages;
463
269
  int tvb_sectionend, tvb_sectionbegin, tvb_len;
464
269
  proto_tree *mgcp_tree = NULL;
465
269
  proto_item *ti = NULL, *tii;
466
269
  const char *verb_name = "";
467
468
  /* Initialize variables */
469
269
  tvb_sectionend = 0;
470
269
  tvb_sectionbegin = tvb_sectionend;
471
269
  tvb_len = tvb_reported_length(tvb);
472
269
  num_messages = 0;
473
474
  /*
475
   * Check to see whether we're really dealing with MGCP by looking
476
   * for a valid MGCP verb or response code.  This isn't infallible,
477
   * but it's cheap and it's better than nothing.
478
   */
479
269
  if (!is_mgcp_verb(tvb, 0, tvb_len, &verb_name) && !is_mgcp_rspcode(tvb, 0, tvb_len))
480
159
    return 0;
481
482
  /*
483
   * Set the columns now, so that they'll be set correctly if we throw
484
   * an exception.  We can set them later as well....
485
   */
486
110
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "MGCP");
487
110
  col_clear(pinfo->cinfo, COL_INFO);
488
489
  /*
490
   * Loop through however many mgcp messages may be stuck in
491
   * this packet using piggybacking
492
   */
493
110
  do
494
612
  {
495
612
    num_messages++;
496
497
    /* Create our mgcp subtree */
498
612
    ti = proto_tree_add_item(tree, proto_mgcp, tvb, 0, -1, ENC_NA);
499
612
    mgcp_tree = proto_item_add_subtree(ti, ett_mgcp);
500
501
612
    sectionlen = tvb_find_dot_line(tvb, tvb_sectionbegin, -1, &tvb_sectionend);
502
612
    if (sectionlen != -1)
503
612
    {
504
612
      dissect_mgcp_message(tvb_new_subset_length_caplen(tvb, tvb_sectionbegin,
505
612
            sectionlen, sectionlen),
506
612
          pinfo, tree, mgcp_tree, ti);
507
612
      tvb_sectionbegin = tvb_sectionend;
508
612
    }
509
0
    else
510
0
    {
511
0
      break;
512
0
    }
513
612
  } while (tvb_sectionend < tvb_len);
514
515
0
  tii = proto_tree_add_uint(mgcp_tree, hf_mgcp_messagecount, tvb,
516
110
      0 , 0 , num_messages);
517
110
  proto_item_set_hidden(tii);
518
519
  /*
520
   * Add our column information after dissecting SDP
521
   * in order to prevent the column info changing to reflect the SDP
522
   * (when showing message count)
523
   */
524
110
  tvb_sectionbegin = 0;
525
110
  if (global_mgcp_message_count == true )
526
0
  {
527
0
    if (num_messages > 1)
528
0
    {
529
0
      col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i messages)", num_messages);
530
0
    }
531
0
    else
532
0
    {
533
0
      col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MGCP (%i message)", num_messages);
534
0
    }
535
0
  }
536
537
110
  sectionlen = tvb_find_line_end(tvb, tvb_sectionbegin, -1,
538
110
      &tvb_sectionend, false);
539
110
  col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s",
540
110
      tvb_format_text(pinfo->pool, tvb, tvb_sectionbegin, sectionlen));
541
542
110
  return tvb_len;
543
269
}
544
545
/************************************************************************
546
 * dissect_tpkt_mgcp - The dissector for the ASCII TPKT Media Gateway Control Protocol
547
 ************************************************************************/
548
static int dissect_tpkt_mgcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
549
84
{
550
84
  uint16_t ascii_tpkt;
551
84
  int     offset = 0;
552
553
  /* Check whether this looks like a ASCII TPKT-encapsulated
554
   *  MGCP packet.
555
   */
556
84
  ascii_tpkt = is_asciitpkt(tvb);
557
558
84
  if (ascii_tpkt != 1 )
559
67
  {
560
    /*
561
     * It's not a ASCII TPKT packet
562
     * in MGCP
563
     */
564
67
    offset = dissect_mgcp(tvb, pinfo, tree, NULL);
565
67
  }
566
17
  else
567
17
  {
568
    /*
569
     * Dissect ASCII TPKT header
570
     */
571
17
    dissect_asciitpkt(tvb, pinfo, tree, mgcp_handle);
572
17
    offset = tvb_reported_length(tvb);
573
17
  }
574
575
84
  return offset;
576
84
}
577
578
/* Dissect an individual MGCP message */
579
static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
580
         proto_tree *mgcp_tree, proto_tree *ti)
581
612
{
582
  /* Declare variables */
583
612
  int sectionlen;
584
612
  int tvb_sectionend, tvb_sectionbegin, tvb_len;
585
612
  tvbuff_t *next_tvb;
586
612
  const char *verb_name = "";
587
612
  mgcp_info_t* mi = wmem_new0(pinfo->pool, mgcp_info_t);
588
612
  sdp_setup_info_t setup_info = { .hf_id = 0, .hf_type = SDP_TRACE_ID_HF_TYPE_UINT32 };
589
612
  media_content_info_t content_info = { MEDIA_CONTAINER_SIP_DATA, NULL, NULL, &setup_info };
590
591
612
  mi->mgcp_type = MGCP_OTHERS;
592
593
  /* Initialize variables */
594
612
  tvb_len = tvb_reported_length(tvb);
595
596
  /*
597
   * Check to see whether we're really dealing with MGCP by looking
598
   * for a valid MGCP verb or response code.  This isn't infallible,
599
   * but it's cheap and it's better than nothing.
600
   */
601
612
  if (is_mgcp_verb(tvb, 0, tvb_len, &verb_name) || is_mgcp_rspcode(tvb, 0, tvb_len))
602
325
  {
603
    /* dissect first line */
604
325
    tvb_sectionbegin = 0;
605
325
    tvb_sectionend = tvb_sectionbegin;
606
325
    sectionlen = tvb_find_line_end(tvb, 0, -1, &tvb_sectionend, false);
607
325
    if (sectionlen > 0)
608
325
    {
609
325
      dissect_mgcp_firstline(tvb_new_subset_length_caplen(tvb, tvb_sectionbegin,
610
325
                             sectionlen, sectionlen), pinfo,
611
325
                             mgcp_tree, mi);
612
325
    }
613
325
    tvb_sectionbegin = tvb_sectionend;
614
615
    /* Dissect params */
616
325
    if (tvb_sectionbegin < tvb_len)
617
266
    {
618
266
      sectionlen = tvb_find_null_line(tvb, tvb_sectionbegin, -1,
619
266
                                      &tvb_sectionend);
620
266
      if (sectionlen > 0)
621
228
      {
622
228
        dissect_mgcp_params(tvb_new_subset_length_caplen(tvb, tvb_sectionbegin, sectionlen, sectionlen),
623
228
                                           mgcp_tree, mi);
624
228
      }
625
266
    }
626
627
    /* Set the mgcp payload length correctly so we don't include any
628
       encapsulated SDP */
629
325
    sectionlen = tvb_sectionend;
630
325
    proto_item_set_len(ti, sectionlen);
631
632
    /* Display the raw text of the mgcp message if desired */
633
634
    /* Do we want to display the raw text of our MGCP packet? */
635
325
    if (global_mgcp_raw_text)
636
0
    {
637
0
      mgcp_raw_text_add(tvb, mgcp_tree);
638
0
    }
639
640
    /* Dissect sdp payload */
641
325
    if (tvb_sectionend < tvb_len)
642
56
    {
643
56
      setup_info.is_osmux = mi->is_osmux;
644
56
      next_tvb = tvb_new_subset_remaining(tvb, tvb_sectionend);
645
56
      call_dissector_with_data(sdp_handle, next_tvb, pinfo, tree, &content_info);
646
56
    }
647
325
  }
648
612
}
649
650
651
/*
652
 * Add the raw text of the message to the dissect tree if appropriate
653
 * preferences are specified.
654
 */
655
static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
656
0
{
657
0
  int tvb_linebegin, tvb_lineend, linelen;
658
659
0
  tvb_linebegin = 0;
660
661
0
  do
662
0
  {
663
0
    tvb_find_line_end(tvb, tvb_linebegin, -1, &tvb_lineend, false);
664
0
    linelen = tvb_lineend - tvb_linebegin;
665
0
    proto_tree_add_format_text(tree, tvb, tvb_linebegin, linelen);
666
0
    tvb_linebegin = tvb_lineend;
667
0
  } while (tvb_offset_exists(tvb, tvb_lineend));
668
0
}
669
670
/*
671
 * is_mgcp_verb - A function for determining whether there is a
672
 *                MGCP verb at offset in tvb
673
 *
674
 * Parameter:
675
 * tvb - The tvbuff in which we are looking for an MGCP verb
676
 * offset - The offset in tvb at which we are looking for a MGCP verb
677
 * maxlength - The maximum distance from offset we may look for the
678
 *             characters that make up a MGCP verb.
679
 * verb_name - The name for the verb code found (output)
680
 *
681
 * Return: true if there is an MGCP verb at offset in tvb, otherwise false
682
 */
683
static bool is_mgcp_verb(tvbuff_t *tvb, int offset, int maxlength, const char **verb_name)
684
1.20k
{
685
1.20k
  bool returnvalue = false;
686
1.20k
  char word[5];
687
688
  /* This function is used for checking if a packet is actually an
689
     mgcp packet. Make sure that we do not throw an exception
690
     during such a check. If we did throw an exeption, we could
691
     not refuse the packet and give other dissectors the chance to
692
     look at it. */
693
1.20k
  if (tvb_captured_length_remaining(tvb, offset) < (int)sizeof(word))
694
154
    return false;
695
696
  /* Read the string into 'word' and see if it looks like the start of a verb */
697
1.05k
  if ((maxlength >= 4) && tvb_get_raw_bytes_as_string(tvb, offset, word, sizeof word))
698
1.05k
  {
699
1.05k
    if (((g_ascii_strncasecmp(word, "EPCF", 4) == 0) && (*verb_name = "EndpointConfiguration")) ||
700
1.05k
        ((g_ascii_strncasecmp(word, "CRCX", 4) == 0) && (*verb_name = "CreateConnection")) ||
701
1.05k
        ((g_ascii_strncasecmp(word, "MDCX", 4) == 0) && (*verb_name = "ModifyConnection")) ||
702
1.05k
        ((g_ascii_strncasecmp(word, "DLCX", 4) == 0) && (*verb_name = "DeleteConnection")) ||
703
1.05k
        ((g_ascii_strncasecmp(word, "RQNT", 4) == 0) && (*verb_name = "NotificationRequest")) ||
704
1.05k
        ((g_ascii_strncasecmp(word, "NTFY", 4) == 0) && (*verb_name = "Notify")) ||
705
1.05k
        ((g_ascii_strncasecmp(word, "AUEP", 4) == 0) && (*verb_name = "AuditEndpoint")) ||
706
1.05k
        ((g_ascii_strncasecmp(word, "AUCX", 4) == 0) && (*verb_name = "AuditConnection")) ||
707
1.05k
        ((g_ascii_strncasecmp(word, "RSIP", 4) == 0) && (*verb_name = "RestartInProgress")) ||
708
1.05k
        ((g_ascii_strncasecmp(word, "MESG", 4) == 0) && (*verb_name = "Message")) ||
709
1.05k
        (word[0] == 'X' && g_ascii_isalpha(word[1]) && g_ascii_isalpha(word[2]) &&
710
1.05k
                           g_ascii_isalpha(word[3]) && (*verb_name = "*Experimental*")))
711
197
    {
712
197
      returnvalue = true;
713
197
    }
714
1.05k
  }
715
716
  /* May be whitespace after verb code - anything else is an error.. */
717
1.05k
  if (returnvalue && maxlength >= 5)
718
197
  {
719
197
    char next = tvb_get_uint8(tvb, 4);
720
197
    if ((next != ' ') && (next != '\t'))
721
1
    {
722
1
      returnvalue = false;
723
1
    }
724
197
  }
725
726
1.05k
  return returnvalue;
727
1.20k
}
728
729
/*
730
 * is_mgcp_rspcode - A function for determining whether something which
731
 *                   looks roughly like a MGCP response code (3-digit number)
732
 *                   is at 'offset' in tvb
733
 *
734
 * Parameters:
735
 * tvb - The tvbuff in which we are looking for an MGCP response code
736
 * offset - The offset in tvb at which we are looking for a MGCP response code
737
 * maxlength - The maximum distance from offset we may look for the
738
 *             characters that make up a MGCP response code.
739
 *
740
 * Return: true if there is an MGCP response code at offset in tvb,
741
 *         otherwise false
742
 */
743
static bool is_mgcp_rspcode(tvbuff_t *tvb, int offset, int maxlength)
744
1.00k
{
745
1.00k
  bool returnvalue = false;
746
1.00k
  char word[4];
747
748
  /* see the comment in is_mgcp_verb() */
749
1.00k
  if (tvb_captured_length_remaining(tvb, offset) < (int)sizeof(word))
750
149
    return false;
751
752
  /* Do 1st 3 characters look like digits? */
753
859
  if (maxlength >= 3)
754
859
  {
755
859
    tvb_get_raw_bytes_as_string(tvb, offset, word, sizeof word);
756
859
    if (g_ascii_isdigit(word[0]) && g_ascii_isdigit(word[1]) && g_ascii_isdigit(word[2]))
757
727
    {
758
727
      returnvalue = true;
759
727
    }
760
859
  }
761
762
  /* Maybe some white space after the 3rd digit - anything else is an error */
763
859
  if (returnvalue && maxlength >= 4)
764
727
  {
765
727
    char next = tvb_get_uint8(tvb, 3);
766
727
    if ((next != ' ') && (next != '\t'))
767
165
    {
768
165
      returnvalue = false;
769
165
    }
770
727
  }
771
772
859
  return returnvalue;
773
1.00k
}
774
775
/*
776
 * tvb_parse_param - Parse the MGCP param into a type and a value.
777
 *
778
 * Parameters:
779
 * tvb - The tvbuff containing the MGCP param we are to parse.
780
 * offset - The offset in tvb at which we will begin looking for a
781
 *          MGCP parameter to parse.
782
 * len - The maximum distance from offset in tvb that we can look for
783
 *       an MGCP parameter to parse.
784
 * hf - The place to write a pointer to the integer representing the
785
 *      header field associated with the MGCP parameter parsed.
786
 *
787
 * Returns: The offset in tvb where the value of the MGCP parameter
788
 *          begins.
789
 */
790
static int tvb_parse_param(tvbuff_t* tvb, int offset, int len, int** hf, mgcp_info_t* mi)
791
786
{
792
786
  int returnvalue = -1, tvb_current_offset, ext_off;
793
786
  uint8_t tempchar, plus_minus;
794
786
  char **buf;
795
796
786
  tvb_current_offset = offset;
797
786
  *hf = NULL;
798
786
  buf = NULL;
799
800
786
  if (len > 0)
801
786
  {
802
786
    tempchar = (uint8_t)g_ascii_toupper(tvb_get_uint8(tvb, tvb_current_offset));
803
804
786
    switch (tempchar)
805
786
    {
806
3
      case 'K':
807
3
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
808
3
        {
809
3
          *hf = &hf_mgcp_param_invalid;
810
3
          break;
811
3
        }
812
0
        *hf = &hf_mgcp_param_rspack;
813
0
        break;
814
3
      case 'B':
815
3
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
816
3
        {
817
3
          *hf = &hf_mgcp_param_invalid;
818
3
          break;
819
3
        }
820
0
        *hf = &hf_mgcp_param_bearerinfo;
821
0
        break;
822
12
      case 'C':
823
12
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
824
12
        {
825
12
          *hf = &hf_mgcp_param_invalid;
826
12
          break;
827
12
        }
828
0
        *hf = &hf_mgcp_param_callid;
829
0
        break;
830
23
      case 'I':
831
23
        tvb_current_offset++;
832
23
        if (len > (tvb_current_offset - offset) &&
833
23
           (tempchar = tvb_get_uint8(tvb, tvb_current_offset)) == ':')
834
0
        {
835
0
          *hf = &hf_mgcp_param_connectionid;
836
0
          tvb_current_offset--;
837
0
        }
838
23
        else
839
23
          if (tempchar == '2')
840
0
        {
841
0
          *hf = &hf_mgcp_param_secondconnectionid;
842
0
        }
843
23
        break;
844
0
      case 'N':
845
0
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
846
0
        {
847
0
          *hf = &hf_mgcp_param_invalid;
848
0
          break;
849
0
        }
850
0
        *hf = &hf_mgcp_param_notifiedentity;
851
0
        break;
852
48
      case 'X':
853
        /* Move past 'X' */
854
48
        tvb_current_offset++;
855
856
        /* X: is RequestIdentifier */
857
48
        if (len > (tvb_current_offset - offset) &&
858
48
           (tempchar = tvb_get_uint8(tvb, tvb_current_offset)) == ':')
859
0
        {
860
0
          *hf = &hf_mgcp_param_requestid;
861
0
          tvb_current_offset--;
862
0
        }
863
        /* XRM/MCR */
864
48
        else
865
48
        if (len > (tvb_current_offset - offset) &&
866
48
           ((uint8_t)g_ascii_toupper(tvb_get_uint8(tvb,tvb_current_offset))) == 'R')
867
0
        {
868
          /* Move past 'R' */
869
0
          tvb_current_offset += 3;
870
0
          if (len > (tvb_current_offset - offset) &&
871
0
            ((uint8_t)g_ascii_toupper(tvb_get_uint8(tvb,tvb_current_offset))) == 'R')
872
0
          {
873
0
            *hf = &hf_mgcp_param_remotevoicemetrics;
874
0
          }
875
0
          else
876
0
          if (len > (tvb_current_offset - offset) &&
877
0
             ((uint8_t)g_ascii_toupper(tvb_get_uint8(tvb,tvb_current_offset))) == 'L')
878
0
          {
879
0
            *hf = &hf_mgcp_param_localvoicemetrics;
880
0
          }
881
0
          tvb_current_offset -= 4;
882
0
        }
883
884
        /* X+...: or X-....: are vendor extension parameters */
885
48
        else
886
48
        if (len > (tvb_current_offset - offset) &&
887
48
            ((plus_minus = tvb_get_uint8(tvb, tvb_current_offset)) == '-' ||
888
48
             (plus_minus == '+')))
889
0
        {
890
          /* Move past + or - */
891
0
          tvb_current_offset++;
892
893
          /* Keep going, through possible vendor param name */
894
          /* We have a mempbrk; perhaps an equivalent of strspn
895
           * for tvbs would be useful.
896
           */
897
0
          for (ext_off = 0; len > (ext_off + tvb_current_offset-offset); ext_off++) {
898
0
            tempchar = tvb_get_uint8(tvb, tvb_current_offset + ext_off);
899
0
            if (!g_ascii_isalpha(tempchar) && !g_ascii_isdigit(tempchar)) break;
900
0
          }
901
902
0
          if (tempchar == ':')
903
0
          {
904
            /* Looks like a valid vendor param name */
905
0
            ws_debug("MGCP Extension: %s", tvb_get_string_enc(wmem_packet_scope(), tvb, tvb_current_offset, ext_off, ENC_ASCII));
906
0
            switch (plus_minus)
907
0
            {
908
0
              case '+':
909
0
                *hf = &hf_mgcp_param_extension_critical;
910
0
                break;
911
0
              case '-':
912
0
                if (tvb_strncaseeql(tvb, tvb_current_offset, "OSMUX", ext_off) == 0) {
913
0
                  *hf = &hf_mgcp_param_x_osmux;
914
0
                } else {
915
0
                  *hf = &hf_mgcp_param_extension;
916
0
                }
917
0
                break;
918
0
            }
919
            /* -1: Final generic path below expects us to point to char before the ':'. */
920
0
            tvb_current_offset += ext_off - 1;
921
0
          }
922
0
        }
923
48
        break;
924
48
      case 'L':
925
0
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
926
0
        {
927
0
          *hf = &hf_mgcp_param_invalid;
928
0
          break;
929
0
        }
930
0
        *hf = &hf_mgcp_param_localconnoptions;
931
0
        break;
932
2
      case 'M':
933
2
        tvb_current_offset++;
934
2
        if (len > (tvb_current_offset - offset) &&
935
2
           (tempchar = (uint8_t)g_ascii_toupper(tvb_get_uint8(tvb, tvb_current_offset))) == ':')
936
0
        {
937
0
          *hf = &hf_mgcp_param_connectionmode;
938
0
          tvb_current_offset--;
939
0
        }
940
2
        else
941
2
        if (tempchar == 'D')
942
0
        {
943
0
          *hf = &hf_mgcp_param_maxmgcpdatagram;
944
0
        }
945
2
        break;
946
17
      case 'R':
947
17
        tvb_current_offset++;
948
17
        if (len > (tvb_current_offset - offset) &&
949
17
            (tempchar = (uint8_t)g_ascii_toupper(tvb_get_uint8(tvb, tvb_current_offset))) == ':')
950
0
        {
951
0
          *hf = &hf_mgcp_param_reqevents;
952
0
          tvb_current_offset--;
953
0
        }
954
17
        else
955
17
        if ( tempchar == 'M')
956
0
        {
957
0
          *hf = &hf_mgcp_param_restartmethod;
958
0
        }
959
17
        else
960
17
        if (tempchar == 'D')
961
0
        {
962
0
          *hf = &hf_mgcp_param_restartdelay;
963
0
        }
964
17
        break;
965
91
      case 'S':
966
91
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
967
90
        {
968
90
          *hf = &hf_mgcp_param_invalid;
969
90
          break;
970
90
        }
971
1
        *hf = &hf_mgcp_param_signalreq;
972
1
        buf = &(mi->signalReq);
973
1
        break;
974
14
      case 'D':
975
14
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
976
14
        {
977
14
          if (len > (tvb_current_offset + 5 - offset) &&
978
14
            (g_ascii_toupper(tvb_get_uint8(tvb, tvb_current_offset + 1) == 'Q')) &&
979
14
            (                tvb_get_uint8(tvb, tvb_current_offset + 2) == '-' ) &&
980
14
            (g_ascii_toupper(tvb_get_uint8(tvb, tvb_current_offset + 3) == 'R')) &&
981
14
            (g_ascii_toupper(tvb_get_uint8(tvb, tvb_current_offset + 4) == 'I')) &&
982
14
            (                tvb_get_uint8(tvb, tvb_current_offset + 5) == ':' )
983
14
          ) {
984
0
            tvb_current_offset+=4;
985
0
            *hf = &hf_mgcp_param_resourceid;
986
0
            break;
987
0
          }
988
989
14
          *hf = &hf_mgcp_param_invalid;
990
14
          break;
991
14
        }
992
0
        *hf = &hf_mgcp_param_digitmap;
993
0
        mi->hasDigitMap = true;
994
0
        break;
995
58
      case 'O':
996
58
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
997
58
        {
998
58
          *hf = &hf_mgcp_param_invalid;
999
58
          break;
1000
58
        }
1001
0
        *hf = &hf_mgcp_param_observedevent;
1002
0
        buf = &(mi->observedEvents);
1003
0
        break;
1004
2
      case 'P':
1005
2
        tvb_current_offset++;
1006
2
        if (len > (tvb_current_offset - offset) &&
1007
2
            (tempchar = (uint8_t)g_ascii_toupper(tvb_get_uint8(tvb, tvb_current_offset))) == ':')
1008
0
        {
1009
0
          *hf = &hf_mgcp_param_connectionparam;
1010
0
          tvb_current_offset--;
1011
0
        }
1012
2
        else
1013
2
        if ( tempchar == 'L')
1014
0
        {
1015
0
          *hf = &hf_mgcp_param_packagelist;
1016
0
        }
1017
2
        break;
1018
0
      case 'E':
1019
0
        tvb_current_offset++;
1020
0
        if (len > (tvb_current_offset - offset) &&
1021
0
            (tempchar = (uint8_t)g_ascii_toupper(tvb_get_uint8(tvb, tvb_current_offset))) == ':')
1022
0
        {
1023
0
          *hf = &hf_mgcp_param_reasoncode;
1024
0
          tvb_current_offset--;
1025
0
        }
1026
0
        else
1027
0
        if ( tempchar == 'S')
1028
0
        {
1029
0
          *hf = &hf_mgcp_param_eventstates;
1030
0
        }
1031
0
        break;
1032
6
      case 'Z':
1033
6
        tvb_current_offset++;
1034
6
        if (len > (tvb_current_offset - offset) &&
1035
6
            (tempchar = (uint8_t)g_ascii_toupper(tvb_get_uint8(tvb, tvb_current_offset))) == ':')
1036
0
        {
1037
0
          *hf = &hf_mgcp_param_specificendpoint;
1038
0
          tvb_current_offset--;
1039
0
        }
1040
6
        else
1041
6
        if (tempchar == '2')
1042
0
        {
1043
0
          *hf = &hf_mgcp_param_secondendpointid;
1044
0
        }
1045
6
        break;
1046
2
      case 'F':
1047
2
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
1048
0
        {
1049
0
          *hf = &hf_mgcp_param_invalid;
1050
0
          break;
1051
0
        }
1052
2
        *hf = &hf_mgcp_param_reqinfo;
1053
2
        break;
1054
9
      case 'Q':
1055
9
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
1056
9
        {
1057
9
          *hf = &hf_mgcp_param_invalid;
1058
9
          break;
1059
9
        }
1060
0
        *hf = &hf_mgcp_param_quarantinehandling;
1061
0
        break;
1062
36
      case 'T':
1063
36
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
1064
36
        {
1065
36
          *hf = &hf_mgcp_param_invalid;
1066
36
          break;
1067
36
        }
1068
0
        *hf = &hf_mgcp_param_detectedevents;
1069
0
        break;
1070
12
      case 'A':
1071
12
        if (tvb_get_uint8(tvb, tvb_current_offset+1) != ':')
1072
12
        {
1073
12
          *hf = &hf_mgcp_param_invalid;
1074
12
          break;
1075
12
        }
1076
0
        *hf = &hf_mgcp_param_capabilities;
1077
0
        break;
1078
1079
448
      default:
1080
448
        *hf = &hf_mgcp_param_invalid;
1081
448
        break;
1082
786
    }
1083
1084
    /* Move to (hopefully) the colon */
1085
786
    tvb_current_offset++;
1086
1087
    /* Add a recognised parameter type if we have one */
1088
786
    if (*hf != NULL && len > (tvb_current_offset - offset) &&
1089
786
        tvb_get_uint8(tvb, tvb_current_offset) == ':')
1090
8
    {
1091
8
      tvb_current_offset++;
1092
8
      tvb_current_offset = tvb_skip_wsp(tvb, tvb_current_offset, (len - tvb_current_offset + offset));
1093
8
      returnvalue = tvb_current_offset;
1094
1095
      /* set the observedEvents or signalReq used in Voip Calls analysis */
1096
8
      if (buf != NULL) {
1097
1
        *buf = tvb_get_string_enc(wmem_packet_scope(), tvb, tvb_current_offset, (len - tvb_current_offset + offset), ENC_ASCII);
1098
1
      }
1099
8
    }
1100
786
  }
1101
0
  else
1102
0
  {
1103
    /* Was an empty line */
1104
0
    *hf = &hf_mgcp_param_invalid;
1105
0
  }
1106
1107
  /* For these types, show the whole line */
1108
786
  if ((*hf == &hf_mgcp_param_invalid) ||
1109
786
      (*hf == &hf_mgcp_param_extension) || (*hf == &hf_mgcp_param_extension_critical) ||
1110
786
      (*hf == &hf_mgcp_param_localvoicemetrics) || (*hf == &hf_mgcp_param_remotevoicemetrics))
1111
685
  {
1112
685
    returnvalue = offset;
1113
685
  }
1114
1115
786
  return returnvalue;
1116
786
}
1117
1118
1119
/*
1120
 * dissect_mgcp_firstline - Dissects the firstline of an MGCP message.
1121
 *                          Adds the appropriate headers fields to
1122
 *                          tree for the dissection of the first line
1123
 *                          of an MGCP message.
1124
 *
1125
 * Parameters:
1126
 * tvb - The tvb containing the first line of an MGCP message.  This
1127
 *       tvb is presumed to ONLY contain the first line of the MGCP
1128
 *       message.
1129
 * pinfo - The packet info for the packet.  This is not really used
1130
 *         by this function but is passed through so as to retain the
1131
 *         style of a dissector.
1132
 * tree - The tree from which to hang the structured information parsed
1133
 *        from the first line of the MGCP message.
1134
 */
1135
static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, mgcp_info_t* mi)
1136
325
{
1137
325
  int tvb_current_offset, tvb_previous_offset, tvb_len, tvb_current_len;
1138
325
  int tokennum, tokenlen;
1139
325
  proto_item* hidden_item;
1140
325
  char *transid = NULL;
1141
325
  char *code = NULL;
1142
325
  char *endpointId = NULL;
1143
325
  mgcp_type_t mgcp_type = MGCP_OTHERS;
1144
325
  conversation_t* conversation;
1145
325
  mgcp_call_info_key mgcp_call_key;
1146
325
  mgcp_call_info_key *new_mgcp_call_key = NULL;
1147
325
  mgcp_call_t *mgcp_call = NULL;
1148
325
  nstime_t delta;
1149
325
  const char *verb_description = "";
1150
325
  char code_with_verb[64] = "";  /* To fit "<4-letter-code> (<longest-verb>)" */
1151
325
  proto_item* pi;
1152
1153
325
  static address null_address = ADDRESS_INIT_NONE;
1154
325
  tvb_previous_offset = 0;
1155
325
  tvb_len = tvb_reported_length(tvb);
1156
325
  tvb_current_offset = tvb_previous_offset;
1157
325
  mi->is_duplicate = false;
1158
325
  mi->request_available = false;
1159
1160
  /* if (tree) */
1161
325
  {
1162
325
    tokennum = 0;
1163
1164
325
    do
1165
828
    {
1166
828
      tvb_current_len = tvb_reported_length_remaining(tvb, tvb_previous_offset);
1167
828
      tvb_current_offset = tvb_find_uint8(tvb, tvb_previous_offset, tvb_current_len, ' ');
1168
828
      if (tvb_current_offset == -1)
1169
283
      {
1170
283
        tvb_current_offset = tvb_len;
1171
283
        tokenlen = tvb_current_len;
1172
283
      }
1173
545
      else
1174
545
      {
1175
545
        tokenlen = tvb_current_offset - tvb_previous_offset;
1176
545
      }
1177
828
      if (tokennum == 0)
1178
325
      {
1179
325
        if (tokenlen > 4)
1180
2
        {
1181
          /* XXX - exception */
1182
2
          return;
1183
2
        }
1184
1185
323
        code = tvb_format_text(pinfo->pool, tvb, tvb_previous_offset, tokenlen);
1186
323
        (void) g_strlcpy(mi->code, code, 5);
1187
323
        if (is_mgcp_verb(tvb, tvb_previous_offset, tvb_current_len, &verb_description))
1188
64
        {
1189
64
          mgcp_type = MGCP_REQUEST;
1190
64
          if (verb_description != NULL)
1191
64
          {
1192
            /* Can show verb along with code if known */
1193
64
            snprintf(code_with_verb, 64, "%s (%s)", code, verb_description);
1194
64
          }
1195
1196
64
          proto_tree_add_string_format(tree, hf_mgcp_req_verb, tvb,
1197
64
                                       tvb_previous_offset, tokenlen,
1198
64
                                       code, "%s",
1199
64
                                       strlen(code_with_verb) ? code_with_verb : code);
1200
64
        }
1201
259
        else
1202
259
        if (is_mgcp_rspcode(tvb, tvb_previous_offset, tvb_current_len))
1203
259
        {
1204
259
          bool rspcode_valid;
1205
259
          mgcp_type = MGCP_RESPONSE;
1206
259
          rspcode_valid = ws_strtou32(code, NULL, &mi->rspcode);
1207
259
          pi = proto_tree_add_uint(tree, hf_mgcp_rsp_rspcode, tvb,
1208
259
                              tvb_previous_offset, tokenlen, mi->rspcode);
1209
259
          if (!rspcode_valid)
1210
0
            expert_add_info(pinfo, pi, &ei_mgcp_rsp_rspcode_invalid);
1211
259
        }
1212
0
        else
1213
0
        {
1214
0
          break;
1215
0
        }
1216
323
      }
1217
826
      if (tokennum == 1)
1218
319
      {
1219
319
        transid = tvb_format_text(pinfo->pool, tvb, tvb_previous_offset, tokenlen);
1220
        /* XXX - what if this isn't a valid text string? */
1221
319
        mi->transid = (uint32_t)strtoul(transid, NULL, 10);
1222
319
        proto_tree_add_string(tree, hf_mgcp_transid, tvb,
1223
319
                              tvb_previous_offset, tokenlen, transid);
1224
319
      }
1225
826
      if (tokennum == 2)
1226
177
      {
1227
177
        if (mgcp_type == MGCP_REQUEST)
1228
58
        {
1229
58
          endpointId = tvb_format_text(pinfo->pool, tvb, tvb_previous_offset, tokenlen);
1230
58
          mi->endpointId = wmem_strdup(pinfo->pool, endpointId);
1231
58
          proto_tree_add_string(tree, hf_mgcp_req_endpoint, tvb,
1232
58
                                tvb_previous_offset, tokenlen, endpointId);
1233
58
        }
1234
119
        else
1235
119
        if (mgcp_type == MGCP_RESPONSE)
1236
119
        {
1237
119
          if (tvb_current_offset < tvb_len)
1238
34
          {
1239
34
            tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1240
34
                                         -1, &tvb_current_offset, false);
1241
34
          }
1242
85
          else
1243
85
          {
1244
85
            tokenlen = tvb_current_len;
1245
85
          }
1246
119
          proto_tree_add_string(tree, hf_mgcp_rsp_rspstring, tvb,
1247
119
                                tvb_previous_offset, tokenlen,
1248
119
                                tvb_format_text(pinfo->pool, tvb, tvb_previous_offset,
1249
119
                                tokenlen));
1250
119
          break;
1251
119
        }
1252
177
      }
1253
1254
707
      if ((tokennum == 3 && mgcp_type == MGCP_REQUEST))
1255
7
      {
1256
7
        if (tvb_current_offset < tvb_len )
1257
3
        {
1258
3
          tokenlen = tvb_find_line_end(tvb, tvb_previous_offset,
1259
3
                                       -1, &tvb_current_offset, false);
1260
3
        }
1261
4
        else
1262
4
        {
1263
4
          tokenlen = tvb_current_len;
1264
4
        }
1265
7
        proto_tree_add_string(tree, hf_mgcp_version, tvb,
1266
7
                              tvb_previous_offset, tokenlen,
1267
7
                              tvb_format_text(pinfo->pool, tvb, tvb_previous_offset,
1268
7
                              tokenlen));
1269
7
        break;
1270
7
      }
1271
700
      if (tvb_current_offset < tvb_len)
1272
508
      {
1273
508
        tvb_previous_offset = tvb_skip_wsp(tvb, tvb_current_offset,
1274
508
                                           tvb_current_len);
1275
508
      }
1276
700
      tokennum++;
1277
700
    } while (tvb_current_offset < tvb_len && tvb_offset_exists(tvb, tvb_current_offset) && tvb_previous_offset < tvb_len && tokennum <= 3);
1278
1279
323
    switch (mgcp_type)
1280
323
    {
1281
259
      case MGCP_RESPONSE:
1282
259
        hidden_item = proto_tree_add_boolean(tree, hf_mgcp_rsp, tvb, 0, 0, true);
1283
259
        proto_item_set_hidden(hidden_item);
1284
        /* Check for MGCP response.  A response must match a call that
1285
           we've seen, and the response must be sent to the same
1286
           port and address that the call came from, and must
1287
           come from the port to which the call was sent.
1288
1289
           If the transport is connection-oriented (we check, for
1290
           now, only for "pinfo->ptype" of PT_TCP), we take
1291
           into account the address from which the call was sent
1292
           and the address to which the call was sent, because
1293
           the addresses of the two endpoints should be the same
1294
           for all calls and replies.
1295
1296
           If the transport is connectionless, we don't worry
1297
           about the address to which the call was sent and from
1298
           which the reply was sent, because there's no
1299
           guarantee that the reply will come from the address
1300
           to which the call was sent. */
1301
259
        if (pinfo->ptype == PT_TCP)
1302
146
        {
1303
146
          conversation = find_conversation_pinfo(pinfo, 0);
1304
146
        }
1305
113
        else
1306
113
        {
1307
          /* XXX - can we just use NO_ADDR_B?  Unfortunately,
1308
           * you currently still have to pass a non-null
1309
           * pointer for the second address argument even
1310
           * if you do that.
1311
           */
1312
113
          conversation = find_conversation(pinfo->num, &null_address,
1313
113
                                           &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport,
1314
113
                                           pinfo->destport, 0);
1315
113
        }
1316
259
        if (conversation != NULL)
1317
259
        {
1318
          /* Look only for matching request, if
1319
             matching conversation is available. */
1320
259
          mgcp_call_key.transid = mi->transid;
1321
259
          mgcp_call_key.conversation = conversation;
1322
259
          mgcp_call = (mgcp_call_t *)wmem_map_lookup(mgcp_calls, &mgcp_call_key);
1323
259
          if (mgcp_call)
1324
104
          {
1325
            /* Indicate the frame to which this is a reply. */
1326
104
            if (mgcp_call->req_num)
1327
104
            {
1328
104
              proto_item* item;
1329
104
              mi->request_available = true;
1330
104
              mgcp_call->responded = true;
1331
104
              mi->req_num = mgcp_call->req_num;
1332
104
              (void) g_strlcpy(mi->code, mgcp_call->code, 5);
1333
104
              item = proto_tree_add_uint_format(tree, hf_mgcp_req_frame,
1334
104
                                                tvb, 0, 0, mgcp_call->req_num,
1335
104
                                                "This is a response to a request in frame %u",
1336
104
                                                mgcp_call->req_num);
1337
104
              proto_item_set_generated(item);
1338
104
              nstime_delta(&delta, &pinfo->abs_ts, &mgcp_call->req_time);
1339
104
              item = proto_tree_add_time(tree, hf_mgcp_time, tvb, 0, 0, &delta);
1340
104
              proto_item_set_generated(item);
1341
104
            }
1342
1343
104
            if (mgcp_call->rsp_num == 0)
1344
2
            {
1345
              /* We have not yet seen a response to that call, so
1346
                 this must be the first response; remember its
1347
                 frame number. */
1348
2
              mgcp_call->rsp_num = pinfo->num;
1349
2
            }
1350
102
            else
1351
102
            {
1352
              /* We have seen a response to this call - but was it
1353
                 *this* response? (disregard provisional responses) */
1354
102
              if ((mgcp_call->rsp_num != pinfo->num) &&
1355
102
                  (mi->rspcode >= 200) &&
1356
102
                  (mi->rspcode == mgcp_call->rspcode))
1357
67
              {
1358
67
                proto_item* item;
1359
1360
                /* No, so it's a duplicate response. Mark it as such. */
1361
67
                mi->is_duplicate = true;
1362
67
                col_append_fstr(pinfo->cinfo, COL_INFO,
1363
67
                    ", Duplicate Response %u",
1364
67
                    mi->transid);
1365
1366
67
                item = proto_tree_add_uint(tree, hf_mgcp_dup, tvb, 0, 0, mi->transid);
1367
67
                proto_item_set_hidden(item);
1368
67
                item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup,
1369
67
                    tvb, 0, 0, mi->transid);
1370
67
                proto_item_set_generated(item);
1371
67
                item = proto_tree_add_uint(tree, hf_mgcp_rsp_dup_frame,
1372
67
                    tvb, 0, 0, mgcp_call->rsp_num);
1373
67
                proto_item_set_generated(item);
1374
67
              }
1375
102
            }
1376
            /* Now store the response code (after comparison above) */
1377
104
            mgcp_call->rspcode = mi->rspcode;
1378
104
          }
1379
259
        }
1380
259
        break;
1381
64
      case MGCP_REQUEST:
1382
64
        hidden_item = proto_tree_add_boolean(tree, hf_mgcp_req, tvb, 0, 0, true);
1383
64
        proto_item_set_hidden(hidden_item);
1384
        /* Keep track of the address and port whence the call came,
1385
         * and the port to which the call is being sent, so that
1386
         * we can match up calls with replies.
1387
         *
1388
         * If the transport is connection-oriented (we check, for
1389
         * now, only for "pinfo->ptype" of PT_TCP), we take
1390
         * into account the address from which the call was sent
1391
         * and the address to which the call was sent, because
1392
         * the addresses of the two endpoints should be the same
1393
         * for all calls and replies.
1394
         *
1395
         * If the transport is connectionless, we don't worry
1396
         * about the address to which the call was sent and from
1397
         * which the reply was sent, because there's no
1398
         * guarantee that the reply will come from the address
1399
         * to which the call was sent.
1400
         */
1401
64
        if (pinfo->ptype == PT_TCP)
1402
0
        {
1403
0
          conversation = find_conversation_pinfo(pinfo, 0);
1404
0
        }
1405
64
        else
1406
64
        {
1407
          /*
1408
           * XXX - can we just use NO_ADDR_B?  Unfortunately,
1409
           * you currently still have to pass a non-null
1410
           * pointer for the second address argument even
1411
           * if you do that.
1412
           */
1413
64
          conversation = find_conversation(pinfo->num, &pinfo->src,
1414
64
                                           &null_address, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport,
1415
64
                                           pinfo->destport, 0);
1416
64
        }
1417
64
        if (conversation == NULL)
1418
0
        {
1419
          /* It's not part of any conversation - create a new one. */
1420
0
          if (pinfo->ptype == PT_TCP)
1421
0
          {
1422
0
            conversation = conversation_new(pinfo->num, &pinfo->src,
1423
0
                                            &pinfo->dst, CONVERSATION_TCP, pinfo->srcport,
1424
0
                                            pinfo->destport, 0);
1425
0
          }
1426
0
          else
1427
0
          {
1428
0
            conversation = conversation_new(pinfo->num, &pinfo->src,
1429
0
                                            &null_address, conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport,
1430
0
                                            pinfo->destport, 0);
1431
0
          }
1432
0
        }
1433
1434
        /* Prepare the key data */
1435
64
        mgcp_call_key.transid = mi->transid;
1436
64
        mgcp_call_key.conversation = conversation;
1437
1438
        /* Look up the request */
1439
64
        mgcp_call = (mgcp_call_t *)wmem_map_lookup(mgcp_calls, &mgcp_call_key);
1440
64
        if (mgcp_call != NULL)
1441
59
        {
1442
          /* We've seen a request with this TRANSID, with the same
1443
             source and destination, before - but was it
1444
             *this* request? */
1445
59
          if (pinfo->num != mgcp_call->req_num)
1446
59
          {
1447
            /* No, so it's a duplicate request. Mark it as such. */
1448
59
            mi->is_duplicate = true;
1449
59
            mi->req_num = mgcp_call->req_num;
1450
59
            col_append_fstr(pinfo->cinfo, COL_INFO,
1451
59
                            ", Duplicate Request %u",
1452
59
                            mi->transid);
1453
59
            if (tree)
1454
59
            {
1455
59
              proto_item* item;
1456
59
              item = proto_tree_add_uint(tree, hf_mgcp_dup, tvb, 0, 0, mi->transid);
1457
59
              proto_item_set_hidden(item);
1458
59
              item = proto_tree_add_uint(tree, hf_mgcp_req_dup, tvb, 0, 0, mi->transid);
1459
59
              proto_item_set_generated(item);
1460
59
              item = proto_tree_add_uint(tree, hf_mgcp_req_dup_frame, tvb, 0, 0, mi->req_num);
1461
59
              proto_item_set_generated(item);
1462
59
            }
1463
59
          }
1464
59
        }
1465
5
        else
1466
5
        {
1467
          /* Prepare the value data.
1468
             "req_num" and "rsp_num" are frame numbers;
1469
             frame numbers are 1-origin, so we use 0
1470
             to mean "we don't yet know in which frame
1471
             the reply for this call appears". */
1472
5
          new_mgcp_call_key    = (mgcp_call_info_key *)wmem_alloc(wmem_file_scope(), sizeof(*new_mgcp_call_key));
1473
5
          *new_mgcp_call_key   = mgcp_call_key;
1474
5
          mgcp_call            = (mgcp_call_t *)wmem_alloc(wmem_file_scope(), sizeof(*mgcp_call));
1475
5
          mgcp_call->req_num   = pinfo->num;
1476
5
          mgcp_call->rsp_num   = 0;
1477
5
          mgcp_call->transid   = mi->transid;
1478
5
          mgcp_call->responded = false;
1479
5
          mgcp_call->req_time=pinfo->abs_ts;
1480
5
          (void) g_strlcpy(mgcp_call->code, mi->code, 5);
1481
1482
          /* Store it */
1483
5
          wmem_map_insert(mgcp_calls, new_mgcp_call_key, mgcp_call);
1484
5
        }
1485
64
        if (mgcp_call->rsp_num)
1486
50
        {
1487
50
          proto_item* item = proto_tree_add_uint_format(tree, hf_mgcp_rsp_frame,
1488
50
                                                        tvb, 0, 0, mgcp_call->rsp_num,
1489
50
                                                        "The response to this request is in frame %u",
1490
50
                                                        mgcp_call->rsp_num);
1491
50
          proto_item_set_generated(item);
1492
50
        }
1493
64
        break;
1494
0
      default:
1495
0
        break;
1496
323
    }
1497
1498
323
    mi->mgcp_type = mgcp_type;
1499
323
    if (mgcp_call)
1500
168
    {
1501
168
      mi->req_time.secs=mgcp_call->req_time.secs;
1502
168
      mi->req_time.nsecs=mgcp_call->req_time.nsecs;
1503
168
    }
1504
323
  }
1505
1506
0
  tap_queue_packet(mgcp_tap, pinfo, mi);
1507
323
}
1508
1509
/*
1510
 * dissect_mgcp_params - Dissects the parameters of an MGCP message.
1511
 *                       Adds the appropriate headers fields to
1512
 *                       tree for the dissection of the parameters
1513
 *                       of an MGCP message.
1514
 *
1515
 * Parameters:
1516
 * tvb - The tvb containing the parameters of an MGCP message.  This
1517
 *       tvb is presumed to ONLY contain the part of the MGCP
1518
 *       message which contains the MGCP parameters.
1519
 * tree - The tree from which to hang the structured information parsed
1520
 *        from the parameters of the MGCP message.
1521
 */
1522
static void dissect_mgcp_params(tvbuff_t *tvb, proto_tree *tree, mgcp_info_t* mi)
1523
228
{
1524
228
  int linelen, tokenlen, *my_param;
1525
228
  int tvb_lineend, tvb_linebegin, tvb_len, old_lineend;
1526
228
  int tvb_tokenbegin;
1527
228
  proto_tree *mgcp_param_ti, *mgcp_param_tree;
1528
1529
228
  tvb_len = tvb_reported_length(tvb);
1530
228
  tvb_linebegin = 0;
1531
228
  tvb_lineend = tvb_linebegin;
1532
1533
228
  mgcp_param_ti = proto_tree_add_item(tree, hf_mgcp_params, tvb,
1534
228
      tvb_linebegin, tvb_len, ENC_NA);
1535
228
  proto_item_set_text(mgcp_param_ti, "Parameters");
1536
228
  mgcp_param_tree = proto_item_add_subtree(mgcp_param_ti, ett_mgcp_param);
1537
1538
  /* Parse the parameters */
1539
1.01k
  while (tvb_offset_exists(tvb, tvb_lineend))
1540
786
  {
1541
786
    old_lineend = tvb_lineend;
1542
786
    linelen = tvb_find_line_end(tvb, tvb_linebegin, -1, &tvb_lineend, false);
1543
786
    tvb_tokenbegin = tvb_parse_param(tvb, tvb_linebegin, linelen, &my_param, mi);
1544
1545
786
    if (my_param)
1546
688
    {
1547
688
      tokenlen = tvb_find_line_end(tvb, tvb_tokenbegin, -1, &tvb_lineend, false);
1548
688
      if (*my_param == hf_mgcp_param_connectionparam) {
1549
0
        dissect_mgcp_connectionparams(mgcp_param_tree, tvb, tvb_linebegin,
1550
0
                    tvb_tokenbegin - tvb_linebegin, tokenlen);
1551
688
      } else if (*my_param == hf_mgcp_param_localconnoptions) {
1552
0
        dissect_mgcp_localconnectionoptions(mgcp_param_tree, tvb, tvb_linebegin,
1553
0
                    tvb_tokenbegin - tvb_linebegin, tokenlen);
1554
688
      } else if (*my_param == hf_mgcp_param_localvoicemetrics) {
1555
0
        dissect_mgcp_localvoicemetrics(mgcp_param_tree, tvb, tvb_linebegin,
1556
0
                     tvb_tokenbegin - tvb_linebegin, tokenlen);
1557
688
      } else if (*my_param == hf_mgcp_param_remotevoicemetrics) {
1558
0
        dissect_mgcp_remotevoicemetrics(mgcp_param_tree, tvb, tvb_linebegin,
1559
0
                tvb_tokenbegin - tvb_linebegin, tokenlen);
1560
688
      } else if (*my_param == hf_mgcp_param_x_osmux) {
1561
0
          proto_tree_add_string(mgcp_param_tree, *my_param, tvb,
1562
0
                    tvb_linebegin, linelen,
1563
0
                    tvb_format_text(wmem_packet_scope(),
1564
0
                        tvb, tvb_tokenbegin, tokenlen));
1565
          /* Mark that Osmux is used, so that packet-sdp.c doesn't call
1566
           * srtp_add_address() and decodes it as RTP. */
1567
0
          mi->is_osmux = true;
1568
688
      } else {
1569
688
        proto_tree_add_string(mgcp_param_tree, *my_param, tvb,
1570
688
                  tvb_linebegin, linelen,
1571
688
                  tvb_format_text(wmem_packet_scope(),
1572
688
                      tvb, tvb_tokenbegin, tokenlen));
1573
688
      }
1574
688
    }
1575
1576
786
    tvb_linebegin = tvb_lineend;
1577
    /* Its a infinite loop if we didn't advance (or went backwards) */
1578
786
    if (old_lineend >= tvb_lineend)
1579
0
    {
1580
      /* XXX - exception */
1581
0
      break;
1582
0
    }
1583
786
  }
1584
228
}
1585
1586
/* Dissect the connection params */
1587
static void
1588
dissect_mgcp_connectionparams(proto_tree *parent_tree, tvbuff_t *tvb, int offset, int param_type_len, int param_val_len)
1589
0
{
1590
0
  proto_tree *tree;
1591
0
  proto_item *item;
1592
1593
0
  char *tokenline;
1594
0
  char **tokens;
1595
0
  unsigned i;
1596
1597
0
  item = proto_tree_add_item(parent_tree, hf_mgcp_param_connectionparam, tvb, offset, param_type_len+param_val_len, ENC_ASCII);
1598
0
  tree = proto_item_add_subtree(item, ett_mgcp_param_connectionparam);
1599
1600
  /* The P: line */
1601
0
  offset += param_type_len; /* skip the P: */
1602
0
  tokenline = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, param_val_len, ENC_ASCII);
1603
1604
  /* Split into type=value pairs separated by comma */
1605
0
  tokens = wmem_strsplit(wmem_packet_scope(), tokenline, ",", -1);
1606
1607
0
  for (i = 0; tokens[i] != NULL; i++)
1608
0
  {
1609
0
    char **typval;
1610
0
    unsigned tokenlen;
1611
0
    int hf_uint = 0;
1612
0
    int hf_string = 0;
1613
1614
0
    tokenlen = (int)strlen(tokens[i]);
1615
0
    typval = wmem_strsplit(wmem_packet_scope(), tokens[i], "=", 2);
1616
0
    if ((typval[0] != NULL) && (typval[1] != NULL))
1617
0
    {
1618
0
      if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PS"))
1619
0
      {
1620
0
        hf_uint = hf_mgcp_param_connectionparam_ps;
1621
0
      }
1622
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "OS"))
1623
0
      {
1624
0
        hf_uint = hf_mgcp_param_connectionparam_os;
1625
0
      }
1626
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PR"))
1627
0
      {
1628
0
        hf_uint = hf_mgcp_param_connectionparam_pr;
1629
0
      }
1630
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "OR"))
1631
0
      {
1632
0
        hf_uint = hf_mgcp_param_connectionparam_or;
1633
0
      }
1634
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PL"))
1635
0
      {
1636
0
        hf_uint = hf_mgcp_param_connectionparam_pl;
1637
0
      }
1638
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JI"))
1639
0
      {
1640
0
        hf_uint = hf_mgcp_param_connectionparam_ji;
1641
0
      }
1642
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "LA"))
1643
0
      {
1644
0
        hf_uint = hf_mgcp_param_connectionparam_la;
1645
0
      }
1646
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RPS"))
1647
0
      {
1648
0
        hf_uint = hf_mgcp_param_connectionparam_pcrps;
1649
0
      } else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/ROS"))
1650
0
      {
1651
0
        hf_uint = hf_mgcp_param_connectionparam_pcros;
1652
0
      }
1653
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RPL"))
1654
0
      {
1655
0
        hf_uint = hf_mgcp_param_connectionparam_pcrpl;
1656
0
      }
1657
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PC/RJI"))
1658
0
      {
1659
0
        hf_uint = hf_mgcp_param_connectionparam_pcrji;
1660
0
      }
1661
0
      else if (!g_ascii_strncasecmp(g_strstrip(typval[0]), "X-", 2))
1662
0
      {
1663
0
        hf_string = hf_mgcp_param_connectionparam_x;
1664
0
      }
1665
1666
0
      if (hf_uint > 0)
1667
0
      {
1668
0
        proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, (uint32_t)strtoul(typval[1], NULL, 10));
1669
0
      }
1670
0
      else if (hf_string > 0)
1671
0
      {
1672
0
        proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
1673
0
      }
1674
0
      else
1675
0
      {
1676
0
        proto_tree_add_string(tree, hf_mgcp_unknown_parameter, tvb, offset, tokenlen, tokens[i]);
1677
0
      }
1678
0
    }
1679
0
    else
1680
0
    {
1681
0
      proto_tree_add_string(tree, hf_mgcp_malformed_parameter, tvb, offset, tokenlen, tokens[i]);
1682
0
    }
1683
0
    offset += tokenlen + 1; /* 1 extra for the delimiter */
1684
0
  }
1685
1686
0
}
1687
1688
/* Dissect the local connection option */
1689
static void
1690
dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_t *tvb, int offset, int param_type_len, int param_val_len)
1691
0
{
1692
0
  proto_tree *tree;
1693
0
  proto_item *item;
1694
1695
0
  char *tokenline;
1696
0
  char **tokens;
1697
0
  unsigned i;
1698
1699
0
  item = proto_tree_add_item(parent_tree, hf_mgcp_param_localconnoptions, tvb, offset, param_type_len+param_val_len, ENC_ASCII);
1700
0
  tree = proto_item_add_subtree(item, ett_mgcp_param_localconnectionoptions);
1701
1702
  /* The L: line */
1703
0
  offset += param_type_len; /* skip the L: */
1704
0
  tokenline = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, param_val_len, ENC_ASCII);
1705
1706
  /* Split into type=value pairs separated by comma */
1707
0
  tokens = wmem_strsplit(wmem_packet_scope(), tokenline, ",", -1);
1708
0
  for (i = 0; tokens[i] != NULL; i++)
1709
0
  {
1710
0
    char **typval;
1711
0
    unsigned tokenlen;
1712
0
    int hf_uint;
1713
0
    int hf_string;
1714
1715
0
    hf_uint = -1;
1716
0
    hf_string = -1;
1717
1718
0
    tokenlen = (int)strlen(tokens[i]);
1719
0
    typval = wmem_strsplit(wmem_packet_scope(), tokens[i], ":", 2);
1720
0
    if ((typval[0] != NULL) && (typval[1] != NULL))
1721
0
    {
1722
0
      if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "p"))
1723
0
      {
1724
0
        hf_uint = hf_mgcp_param_localconnoptions_p;
1725
0
      }
1726
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "a"))
1727
0
      {
1728
0
        hf_string = hf_mgcp_param_localconnoptions_a;
1729
0
      }
1730
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "s"))
1731
0
      {
1732
0
        hf_string = hf_mgcp_param_localconnoptions_s;
1733
0
      }
1734
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "e"))
1735
0
      {
1736
0
        hf_string = hf_mgcp_param_localconnoptions_e;
1737
0
      }
1738
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "sc-rtp"))
1739
0
      {
1740
0
        hf_string = hf_mgcp_param_localconnoptions_scrtp;
1741
0
      }
1742
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "sc-rtcp"))
1743
0
      {
1744
0
        hf_string = hf_mgcp_param_localconnoptions_scrtcp;
1745
0
      }
1746
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "b"))
1747
0
      {
1748
0
        hf_string = hf_mgcp_param_localconnoptions_b;
1749
0
      }
1750
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "es-ccd"))
1751
0
      {
1752
0
        hf_string = hf_mgcp_param_localconnoptions_esccd;
1753
0
      }
1754
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "es-cci"))
1755
0
      {
1756
0
        hf_string = hf_mgcp_param_localconnoptions_escci;
1757
0
      }
1758
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-gi"))
1759
0
      {
1760
0
        hf_string = hf_mgcp_param_localconnoptions_dqgi;
1761
0
      }
1762
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-rd"))
1763
0
      {
1764
0
        hf_string = hf_mgcp_param_localconnoptions_dqrd;
1765
0
      }
1766
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-ri"))
1767
0
      {
1768
0
        hf_string = hf_mgcp_param_localconnoptions_dqri;
1769
0
      }
1770
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "dq-rr"))
1771
0
      {
1772
0
        hf_string = hf_mgcp_param_localconnoptions_dqrr;
1773
0
      }
1774
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "k"))
1775
0
      {
1776
0
        hf_string = hf_mgcp_param_localconnoptions_k;
1777
0
      }
1778
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "gc"))
1779
0
      {
1780
0
        hf_uint = hf_mgcp_param_localconnoptions_gc;
1781
0
      }
1782
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "fmtp"))
1783
0
      {
1784
0
        hf_string = hf_mgcp_param_localconnoptions_fmtp;
1785
0
      }
1786
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "nt"))
1787
0
      {
1788
0
        hf_string = hf_mgcp_param_localconnoptions_nt;
1789
0
      }
1790
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "o-fmtp"))
1791
0
      {
1792
0
        hf_string = hf_mgcp_param_localconnoptions_ofmtp;
1793
0
      }
1794
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r"))
1795
0
      {
1796
0
        hf_string = hf_mgcp_param_localconnoptions_r;
1797
0
      }
1798
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "t"))
1799
0
      {
1800
0
        hf_string = hf_mgcp_param_localconnoptions_t;
1801
0
      }
1802
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-cnf"))
1803
0
      {
1804
0
        hf_string = hf_mgcp_param_localconnoptions_rcnf;
1805
0
      }
1806
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-dir"))
1807
0
      {
1808
0
        hf_string = hf_mgcp_param_localconnoptions_rdir;
1809
0
      }
1810
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "r-sh"))
1811
0
      {
1812
0
        hf_string = hf_mgcp_param_localconnoptions_rsh;
1813
0
      }
1814
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "mp"))
1815
0
      {
1816
0
        hf_string = hf_mgcp_param_localconnoptions_mp;
1817
0
      }
1818
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "fxr/fx"))
1819
0
      {
1820
0
        hf_string = hf_mgcp_param_localconnoptions_fxr;
1821
0
      }
1822
0
      else
1823
0
      {
1824
0
        hf_uint = -1;
1825
0
        hf_string = -1;
1826
0
      }
1827
1828
      /* Add item */
1829
0
      if (hf_uint > 0)
1830
0
      {
1831
0
        proto_tree_add_uint(tree, hf_uint, tvb, offset, tokenlen, (uint32_t)strtoul(typval[1], NULL, 10));
1832
0
      }
1833
0
      else if (hf_string > 0)
1834
0
      {
1835
0
        proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
1836
0
      }
1837
0
      else
1838
0
      {
1839
0
        proto_tree_add_string(tree, hf_mgcp_unknown_parameter, tvb, offset, tokenlen, tokens[i]);
1840
0
      }
1841
0
    }
1842
0
  }
1843
0
}
1844
1845
/* Dissect the Local Voice Metrics option */
1846
static void
1847
dissect_mgcp_localvoicemetrics(proto_tree *parent_tree, tvbuff_t *tvb, int offset, int param_type_len, int param_val_len)
1848
0
{
1849
0
  proto_tree *tree = parent_tree;
1850
0
  proto_item *item = NULL;
1851
1852
0
  char *tokenline = NULL;
1853
0
  char **tokens = NULL;
1854
0
  char **typval = NULL;
1855
0
  unsigned i = 0;
1856
0
  unsigned tokenlen = 0;
1857
0
  int hf_string = -1;
1858
1859
0
  if (parent_tree)
1860
0
  {
1861
0
  item = proto_tree_add_item(parent_tree, hf_mgcp_param_localvoicemetrics, tvb, offset, param_type_len+param_val_len, ENC_ASCII);
1862
0
    tree = proto_item_add_subtree(item, ett_mgcp_param_localvoicemetrics);
1863
0
  }
1864
1865
  /* The XRM/LVM: line */
1866
0
  offset += 9; /* skip the XRM/LVM: */
1867
0
  tokenline = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, param_val_len - 9, ENC_ASCII);
1868
1869
  /* Split into type=value pairs separated by comma and WSP */
1870
0
  tokens = wmem_strsplit(wmem_packet_scope(), tokenline, ",", -1);
1871
0
  for (i = 0; tokens[i] != NULL; i++)
1872
0
  {
1873
1874
0
    tokenlen = (int)strlen(tokens[i]);
1875
0
    typval = wmem_strsplit(wmem_packet_scope(), tokens[i], "=", 2);
1876
0
    if ((typval[0] != NULL) && (typval[1] != NULL))
1877
0
    {
1878
0
      if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "NLR"))
1879
0
      {
1880
0
        hf_string = hf_mgcp_param_voicemetrics_nlr;
1881
0
      }
1882
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JDR"))
1883
0
      {
1884
0
        hf_string = hf_mgcp_param_voicemetrics_jdr;
1885
0
      }
1886
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "BLD"))
1887
0
      {
1888
0
        hf_string = hf_mgcp_param_voicemetrics_bld;
1889
0
      }
1890
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "GLD"))
1891
0
      {
1892
0
        hf_string = hf_mgcp_param_voicemetrics_gld;
1893
0
      }
1894
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "BD"))
1895
0
      {
1896
0
        hf_string = hf_mgcp_param_voicemetrics_bd;
1897
0
      }
1898
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "GD"))
1899
0
      {
1900
0
        hf_string = hf_mgcp_param_voicemetrics_gd;
1901
0
      }
1902
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "RTD"))
1903
0
      {
1904
0
        hf_string = hf_mgcp_param_voicemetrics_rtd;
1905
0
      }
1906
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "ESD"))
1907
0
      {
1908
0
        hf_string = hf_mgcp_param_voicemetrics_esd;
1909
0
      }
1910
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "SL"))
1911
0
      {
1912
0
        hf_string = hf_mgcp_param_voicemetrics_sl;
1913
0
      }
1914
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "NL"))
1915
0
      {
1916
0
        hf_string = hf_mgcp_param_voicemetrics_nl;
1917
0
      }
1918
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "RERL"))
1919
0
      {
1920
0
        hf_string = hf_mgcp_param_voicemetrics_rerl;
1921
0
      }
1922
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "GMN"))
1923
0
      {
1924
0
        hf_string = hf_mgcp_param_voicemetrics_gmn;
1925
0
      }
1926
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "NSR"))
1927
0
      {
1928
0
        hf_string = hf_mgcp_param_voicemetrics_nsr;
1929
0
      }
1930
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "XSR"))
1931
0
      {
1932
0
        hf_string = hf_mgcp_param_voicemetrics_xsr;
1933
0
      }
1934
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "MLQ"))
1935
0
      {
1936
0
        hf_string = hf_mgcp_param_voicemetrics_mlq;
1937
0
      }
1938
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "MCQ"))
1939
0
      {
1940
0
        hf_string = hf_mgcp_param_voicemetrics_mcq;
1941
0
      }
1942
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PLC"))
1943
0
      {
1944
0
        hf_string = hf_mgcp_param_voicemetrics_plc;
1945
0
      }
1946
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JBA"))
1947
0
      {
1948
0
        hf_string = hf_mgcp_param_voicemetrics_jba;
1949
0
      }
1950
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JBR"))
1951
0
      {
1952
0
        hf_string = hf_mgcp_param_voicemetrics_jbr;
1953
0
      }
1954
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JBN"))
1955
0
      {
1956
0
        hf_string = hf_mgcp_param_voicemetrics_jbn;
1957
0
      }
1958
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JBM"))
1959
0
      {
1960
0
        hf_string = hf_mgcp_param_voicemetrics_jbm;
1961
0
      }
1962
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JBS"))
1963
0
      {
1964
0
        hf_string = hf_mgcp_param_voicemetrics_jbs;
1965
0
      }
1966
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "IAJ"))
1967
0
      {
1968
0
        hf_string = hf_mgcp_param_voicemetrics_iaj;
1969
0
      }
1970
0
      else
1971
0
      {
1972
0
        hf_string = -1;
1973
0
      }
1974
1975
      /* Add item */
1976
0
      if (tree)
1977
0
      {
1978
0
        if (hf_string > 0)
1979
0
        {
1980
0
          proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
1981
0
        }
1982
0
        else
1983
0
        {
1984
0
          proto_tree_add_string(tree, hf_mgcp_unknown_parameter, tvb, offset, tokenlen, tokens[i]);
1985
0
        }
1986
0
      }
1987
0
    }
1988
0
    else if (tree)
1989
0
    {
1990
0
      proto_tree_add_string(tree, hf_mgcp_malformed_parameter, tvb, offset, tokenlen, tokens[i]);
1991
0
    }
1992
0
    offset += tokenlen + 1; /* 1 extra for the delimiter */
1993
0
  }
1994
0
}
1995
1996
/* Dissect the Remote Voice Metrics option */
1997
static void
1998
dissect_mgcp_remotevoicemetrics(proto_tree *parent_tree, tvbuff_t *tvb, int offset, int param_type_len, int param_val_len)
1999
0
{
2000
0
  proto_tree *tree = parent_tree;
2001
0
  proto_item *item = NULL;
2002
2003
0
  char *tokenline = NULL;
2004
0
  char **tokens = NULL;
2005
0
  char **typval = NULL;
2006
0
  unsigned i = 0;
2007
0
  unsigned tokenlen = 0;
2008
0
  int hf_string = -1;
2009
2010
0
  if (parent_tree)
2011
0
  {
2012
0
  item = proto_tree_add_item(parent_tree, hf_mgcp_param_remotevoicemetrics, tvb, offset, param_type_len+param_val_len, ENC_ASCII);
2013
0
    tree = proto_item_add_subtree(item, ett_mgcp_param_remotevoicemetrics);
2014
0
  }
2015
2016
  /* The XRM/RVM: line */
2017
0
  offset += 9; /* skip the XRM/RVM: */
2018
0
  tokenline = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, param_val_len - 9, ENC_ASCII);
2019
2020
  /* Split into type=value pairs separated by comma and WSP */
2021
0
  tokens = wmem_strsplit(wmem_packet_scope(), tokenline, ",", -1);
2022
0
  for (i = 0; tokens[i] != NULL; i++)
2023
0
  {
2024
0
    tokenlen = (int)strlen(tokens[i]);
2025
0
    typval = wmem_strsplit(wmem_packet_scope(), tokens[i], "=", 2);
2026
0
    if ((typval[0] != NULL) && (typval[1] != NULL))
2027
0
    {
2028
0
      if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "NLR"))
2029
0
      {
2030
0
        hf_string = hf_mgcp_param_voicemetrics_nlr;
2031
0
      }
2032
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JDR"))
2033
0
      {
2034
0
        hf_string = hf_mgcp_param_voicemetrics_jdr;
2035
0
      }
2036
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "BLD"))
2037
0
      {
2038
0
        hf_string = hf_mgcp_param_voicemetrics_bld;
2039
0
      }
2040
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "GLD"))
2041
0
      {
2042
0
        hf_string = hf_mgcp_param_voicemetrics_gld;
2043
0
      }
2044
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "BD"))
2045
0
      {
2046
0
        hf_string = hf_mgcp_param_voicemetrics_bd;
2047
0
      }
2048
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "GD"))
2049
0
      {
2050
0
        hf_string = hf_mgcp_param_voicemetrics_gd;
2051
0
      }
2052
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "RTD"))
2053
0
      {
2054
0
        hf_string = hf_mgcp_param_voicemetrics_rtd;
2055
0
      }
2056
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "ESD"))
2057
0
      {
2058
0
        hf_string = hf_mgcp_param_voicemetrics_esd;
2059
0
      }
2060
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "SL"))
2061
0
      {
2062
0
        hf_string = hf_mgcp_param_voicemetrics_sl;
2063
0
      }
2064
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "NL"))
2065
0
      {
2066
0
        hf_string = hf_mgcp_param_voicemetrics_nl;
2067
0
      }
2068
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "RERL"))
2069
0
      {
2070
0
        hf_string = hf_mgcp_param_voicemetrics_rerl;
2071
0
      }
2072
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "GMN"))
2073
0
      {
2074
0
        hf_string = hf_mgcp_param_voicemetrics_gmn;
2075
0
      }
2076
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "NSR"))
2077
0
      {
2078
0
        hf_string = hf_mgcp_param_voicemetrics_nsr;
2079
0
      }
2080
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "XSR"))
2081
0
      {
2082
0
        hf_string = hf_mgcp_param_voicemetrics_xsr;
2083
0
      }
2084
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "MLQ"))
2085
0
      {
2086
0
        hf_string = hf_mgcp_param_voicemetrics_mlq;
2087
0
      }
2088
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "MCQ"))
2089
0
      {
2090
0
        hf_string = hf_mgcp_param_voicemetrics_mcq;
2091
0
      }
2092
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "PLC"))
2093
0
      {
2094
0
        hf_string = hf_mgcp_param_voicemetrics_plc;
2095
0
      }
2096
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JBA"))
2097
0
      {
2098
0
        hf_string = hf_mgcp_param_voicemetrics_jba;
2099
0
      }
2100
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JBR"))
2101
0
      {
2102
0
        hf_string = hf_mgcp_param_voicemetrics_jbr;
2103
0
      }
2104
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JBN"))
2105
0
      {
2106
0
        hf_string = hf_mgcp_param_voicemetrics_jbn;
2107
0
      }
2108
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JBM"))
2109
0
      {
2110
0
        hf_string = hf_mgcp_param_voicemetrics_jbm;
2111
0
      }
2112
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "JBS"))
2113
0
      {
2114
0
        hf_string = hf_mgcp_param_voicemetrics_jbs;
2115
0
      }
2116
0
      else if (!g_ascii_strcasecmp(g_strstrip(typval[0]), "IAJ"))
2117
0
      {
2118
0
        hf_string = hf_mgcp_param_voicemetrics_iaj;
2119
0
      }
2120
0
      else
2121
0
      {
2122
0
        hf_string = -1;
2123
0
      }
2124
2125
      /* Add item */
2126
0
      if (tree)
2127
0
      {
2128
0
        if (hf_string > 0)
2129
0
        {
2130
0
          proto_tree_add_string(tree, hf_string, tvb, offset, tokenlen, g_strstrip(typval[1]));
2131
0
        }
2132
0
        else
2133
0
        {
2134
0
          proto_tree_add_string(tree, hf_mgcp_unknown_parameter, tvb, offset, tokenlen, tokens[i]);
2135
0
        }
2136
0
      }
2137
0
    }
2138
0
    else if (tree)
2139
0
    {
2140
0
      proto_tree_add_string(tree, hf_mgcp_malformed_parameter, tvb, offset, tokenlen, tokens[i]);
2141
0
    }
2142
0
    offset += tokenlen + 1; /* 1 extra for the delimiter */
2143
0
  }
2144
0
}
2145
2146
/*
2147
 * tvb_find_null_line - Returns the length from offset to the first null
2148
 *                      line found (a null line is a line that begins
2149
 *                      with a CR or LF.  The offset to the first character
2150
 *                      after the null line is written into the int pointed
2151
 *                      to by next_offset.
2152
 *
2153
 * Parameters:
2154
 * tvb - The tvbuff in which we are looking for a null line.
2155
 * offset - The offset in tvb at which we will begin looking for
2156
 *          a null line.
2157
 * len - The maximum distance from offset in tvb that we will look for
2158
 *       a null line.  If it is -1 we will look to the end of the buffer.
2159
 *
2160
 * next_offset - The location to write the offset of first character
2161
 *               FOLLOWING the null line.
2162
 *
2163
 * Returns: The length from offset to the first character BEFORE
2164
 *          the null line..
2165
 */
2166
static int tvb_find_null_line(tvbuff_t* tvb, int offset, int len, int* next_offset)
2167
266
{
2168
266
  int tvb_lineend, tvb_current_len, tvb_linebegin, maxoffset;
2169
266
  unsigned tempchar;
2170
2171
266
  tvb_linebegin = offset;
2172
266
  tvb_lineend = tvb_linebegin;
2173
2174
  /* Simple setup to allow for the traditional -1 search to the end of the tvbuff */
2175
266
  if (len != -1)
2176
0
  {
2177
0
    tvb_current_len = len;
2178
0
  }
2179
266
  else
2180
266
  {
2181
266
    tvb_current_len = tvb_reported_length_remaining(tvb, offset);
2182
266
  }
2183
2184
266
  maxoffset = (tvb_current_len - 1) + offset;
2185
2186
  /* Loop around until we either find a line beginning with a carriage return
2187
     or newline character or until we hit the end of the tvbuff. */
2188
266
  do
2189
842
  {
2190
842
    tvb_linebegin = tvb_lineend;
2191
842
    tvb_current_len = tvb_reported_length_remaining(tvb, tvb_linebegin);
2192
842
    tvb_find_line_end(tvb, tvb_linebegin, tvb_current_len, &tvb_lineend, false);
2193
842
    tempchar = tvb_get_uint8(tvb, tvb_linebegin);
2194
842
  } while (tempchar != '\r' && tempchar != '\n' && tvb_lineend <= maxoffset && tvb_offset_exists(tvb, tvb_lineend));
2195
2196
2197
266
  *next_offset = tvb_lineend;
2198
2199
266
  if (tvb_lineend <= maxoffset)
2200
56
  {
2201
56
    tvb_current_len = tvb_linebegin - offset;
2202
56
  }
2203
210
  else
2204
210
  {
2205
210
    tvb_current_len = tvb_reported_length_remaining(tvb, offset);
2206
210
  }
2207
2208
266
  return tvb_current_len;
2209
266
}
2210
2211
/*
2212
 * tvb_find_dot_line -  Returns the length from offset to the first line
2213
 *                      containing only a dot (.) character.  A line
2214
 *                      containing only a dot is used to indicate a
2215
 *                      separation between multiple MGCP messages
2216
 *                      piggybacked in the same UDP packet.
2217
 *
2218
 * Parameters:
2219
 * tvb - The tvbuff in which we are looking for a dot line.
2220
 * offset - The offset in tvb at which we will begin looking for
2221
 *          a dot line.
2222
 * len - The maximum distance from offset in tvb that we will look for
2223
 *       a dot line.  If it is -1 we will look to the end of the buffer.
2224
 *
2225
 * next_offset - The location to write the offset of first character
2226
 *               FOLLOWING the dot line.
2227
 *
2228
 * Returns: The length from offset to the first character BEFORE
2229
 *          the dot line or -1 if the character at offset is a .
2230
 *          followed by a newline or a carriage return.
2231
 */
2232
static int tvb_find_dot_line(tvbuff_t* tvb, int offset, int len, int* next_offset)
2233
612
{
2234
612
  int tvb_current_offset, tvb_current_len, maxoffset, tvb_len;
2235
612
  uint8_t tempchar;
2236
612
  tvb_current_len = len;
2237
612
  tvb_len = tvb_reported_length(tvb);
2238
2239
612
  if (len == -1)
2240
612
  {
2241
612
    maxoffset = tvb_len - 1;
2242
612
  }
2243
0
  else
2244
0
  {
2245
0
    maxoffset = (len - 1) + offset;
2246
0
  }
2247
612
  tvb_current_offset = offset -1;
2248
2249
612
  do
2250
997
  {
2251
997
    tvb_current_offset = tvb_find_uint8(tvb, tvb_current_offset+1,
2252
997
                                         tvb_current_len, '.');
2253
997
    tvb_current_len = maxoffset - tvb_current_offset + 1;
2254
2255
    /* If we didn't find a . then break out of the loop */
2256
997
    if (tvb_current_offset == -1)
2257
102
    {
2258
102
      break;
2259
102
    }
2260
2261
    /* Do we have and characters following the . ? */
2262
895
    if (tvb_current_offset < maxoffset)
2263
887
    {
2264
887
      tempchar = tvb_get_uint8(tvb, tvb_current_offset+1);
2265
      /* Are the characters that follow the dot a newline or carriage return ? */
2266
887
      if (tempchar == '\r' || tempchar == '\n')
2267
620
      {
2268
        /* Do we have any characters that proceed the . ? */
2269
620
        if (tvb_current_offset == 0)
2270
0
        {
2271
0
          break;
2272
0
        }
2273
620
        else
2274
620
        {
2275
620
          tempchar = tvb_get_uint8(tvb, tvb_current_offset-1);
2276
2277
          /* Are the characters that follow the dot a newline or a
2278
             carriage return ? */
2279
620
          if (tempchar == '\r' || tempchar == '\n')
2280
502
          {
2281
502
            break;
2282
502
          }
2283
620
        }
2284
620
      }
2285
887
    }
2286
8
    else
2287
8
    if (tvb_current_offset == maxoffset)
2288
8
    {
2289
8
      if (tvb_current_offset == 0)
2290
0
      {
2291
0
        break;
2292
0
      }
2293
8
      else
2294
8
      {
2295
8
        tempchar = tvb_get_uint8(tvb, tvb_current_offset-1);
2296
8
        if (tempchar == '\r' || tempchar == '\n')
2297
0
        {
2298
0
          break;
2299
0
        }
2300
8
      }
2301
8
    }
2302
895
  } while (tvb_current_offset < maxoffset);
2303
2304
2305
  /*
2306
   * So now we either have the tvb_current_offset of a . in a dot line
2307
   * or a tvb_current_offset of -1
2308
   */
2309
612
  if (tvb_current_offset == -1)
2310
102
  {
2311
102
    tvb_current_offset = maxoffset +1;
2312
102
    *next_offset = maxoffset + 1;
2313
102
  }
2314
510
  else
2315
510
  {
2316
510
    tvb_find_line_end(tvb, tvb_current_offset, tvb_current_len, next_offset, false);
2317
510
  }
2318
2319
612
  if (tvb_current_offset == offset)
2320
0
  {
2321
0
    tvb_current_len = -1;
2322
0
  }
2323
612
  else
2324
612
  {
2325
612
    tvb_current_len = tvb_current_offset - offset;
2326
612
  }
2327
2328
612
  return tvb_current_len;
2329
612
}
2330
2331
/* Register all the bits needed with the filtering engine */
2332
2333
void proto_register_mgcp(void);
2334
void proto_reg_handoff_mgcp(void);
2335
2336
void proto_register_mgcp(void)
2337
14
{
2338
14
  expert_module_t* expert_mgcp;
2339
2340
14
  static hf_register_info hf[] =
2341
14
    {
2342
14
      { &hf_mgcp_req,
2343
14
        { "Request", "mgcp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2344
14
          "True if MGCP request", HFILL }},
2345
14
      { &hf_mgcp_rsp,
2346
14
        { "Response", "mgcp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2347
14
          "true if MGCP response", HFILL }},
2348
14
      { &hf_mgcp_req_frame,
2349
14
        { "Request Frame", "mgcp.reqframe", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0,
2350
14
          NULL, HFILL }},
2351
14
      { &hf_mgcp_rsp_frame,
2352
14
        { "Response Frame", "mgcp.rspframe", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0,
2353
14
          NULL, HFILL }},
2354
14
      { &hf_mgcp_time,
2355
14
        { "Time from request", "mgcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
2356
14
          "Timedelta between Request and Response", HFILL }},
2357
14
      { &hf_mgcp_req_verb,
2358
14
        { "Verb", "mgcp.req.verb", FT_STRING, BASE_NONE, NULL, 0x0,
2359
14
          "Name of the verb", HFILL }},
2360
14
      { &hf_mgcp_req_endpoint,
2361
14
        { "Endpoint", "mgcp.req.endpoint", FT_STRING, BASE_NONE, NULL, 0x0,
2362
14
          "Endpoint referenced by the message", HFILL }},
2363
14
      { &hf_mgcp_transid,
2364
14
        { "Transaction ID", "mgcp.transid", FT_STRING, BASE_NONE, NULL, 0x0,
2365
14
          "Transaction ID of this message", HFILL }},
2366
14
      { &hf_mgcp_version,
2367
14
        { "Version", "mgcp.version", FT_STRING, BASE_NONE, NULL, 0x0,
2368
14
          "MGCP Version", HFILL }},
2369
14
      { &hf_mgcp_rsp_rspcode,
2370
14
        { "Response Code", "mgcp.rsp.rspcode", FT_UINT32, BASE_DEC|BASE_EXT_STRING, &mgcp_return_code_vals_ext, 0x0,
2371
14
          NULL, HFILL }},
2372
14
      { &hf_mgcp_rsp_rspstring,
2373
14
        { "Response String", "mgcp.rsp.rspstring", FT_STRING, BASE_NONE, NULL, 0x0,
2374
14
          NULL, HFILL }},
2375
14
      { &hf_mgcp_params,
2376
14
        { "Parameters", "mgcp.params", FT_NONE, BASE_NONE, NULL, 0x0,
2377
14
          "MGCP parameters", HFILL }},
2378
14
      { &hf_mgcp_param_rspack,
2379
14
        { "ResponseAck (K)", "mgcp.param.rspack", FT_STRING, BASE_NONE, NULL, 0x0,
2380
14
          "Response Ack", HFILL }},
2381
14
      { &hf_mgcp_param_bearerinfo,
2382
14
        { "BearerInformation (B)", "mgcp.param.bearerinfo", FT_STRING, BASE_NONE, NULL, 0x0,
2383
14
          "Bearer Information", HFILL }},
2384
14
      { &hf_mgcp_param_callid,
2385
14
        { "CallId (C)", "mgcp.param.callid", FT_STRING, BASE_NONE, NULL, 0x0,
2386
14
          "Call Id", HFILL }},
2387
14
      { &hf_mgcp_param_connectionid,
2388
14
        {"ConnectionIdentifier (I)", "mgcp.param.connectionid", FT_STRING, BASE_NONE, NULL, 0x0,
2389
14
         "Connection Identifier", HFILL }},
2390
14
      { &hf_mgcp_param_secondconnectionid,
2391
14
        { "SecondConnectionID (I2)", "mgcp.param.secondconnectionid", FT_STRING, BASE_NONE, NULL, 0x0,
2392
14
          "Second Connection Identifier", HFILL }},
2393
14
      { &hf_mgcp_param_notifiedentity,
2394
14
        { "NotifiedEntity (N)", "mgcp.param.notifiedentity", FT_STRING, BASE_NONE, NULL, 0x0,
2395
14
          "Notified Entity", HFILL }},
2396
14
      { &hf_mgcp_param_requestid,
2397
14
        { "RequestIdentifier (X)", "mgcp.param.requestid", FT_STRING, BASE_NONE, NULL, 0x0,
2398
14
          "Request Identifier", HFILL }},
2399
14
      { &hf_mgcp_param_localconnoptions,
2400
14
        { "LocalConnectionOptions (L)", "mgcp.param.localconnectionoptions", FT_STRING, BASE_NONE, NULL, 0x0,
2401
14
          "Local Connection Options", HFILL }},
2402
14
      { &hf_mgcp_param_localconnoptions_p,
2403
14
        { "Packetization period (p)", "mgcp.param.localconnectionoptions.p", FT_UINT32, BASE_DEC, NULL, 0x0,
2404
14
          NULL, HFILL }},
2405
14
      { &hf_mgcp_param_localconnoptions_a,
2406
14
        { "Codecs (a)", "mgcp.param.localconnectionoptions.a", FT_STRING, BASE_NONE, NULL, 0x0,
2407
14
          NULL, HFILL }},
2408
14
      { &hf_mgcp_param_localconnoptions_s,
2409
14
        { "Silence Suppression (s)", "mgcp.param.localconnectionoptions.s", FT_STRING, BASE_NONE, NULL, 0x0,
2410
14
          NULL, HFILL }},
2411
14
      { &hf_mgcp_param_localconnoptions_e,
2412
14
        { "Echo Cancellation (e)", "mgcp.param.localconnectionoptions.e", FT_STRING, BASE_NONE, NULL, 0x0,
2413
14
          NULL, HFILL }},
2414
14
      { &hf_mgcp_param_localconnoptions_scrtp,
2415
14
        { "RTP ciphersuite (sc-rtp)", "mgcp.param.localconnectionoptions.scrtp", FT_STRING, BASE_NONE, NULL, 0x0,
2416
14
          NULL, HFILL }},
2417
14
      { &hf_mgcp_param_localconnoptions_scrtcp,
2418
14
        { "RTCP ciphersuite (sc-rtcp)", "mgcp.param.localconnectionoptions.scrtcp", FT_STRING, BASE_NONE, NULL, 0x0,
2419
14
          NULL, HFILL }},
2420
14
      { &hf_mgcp_param_localconnoptions_b,
2421
14
        { "Bandwidth (b)", "mgcp.param.localconnectionoptions.b", FT_STRING, BASE_NONE, NULL, 0x0,
2422
14
          NULL, HFILL }},
2423
14
      { &hf_mgcp_param_localconnoptions_esccd,
2424
14
        { "Content Destination (es-ccd)", "mgcp.param.localconnectionoptions.esccd", FT_STRING, BASE_NONE, NULL, 0x0,
2425
14
          NULL, HFILL }},
2426
14
      { &hf_mgcp_param_localconnoptions_escci,
2427
14
        { "Content Identifier (es-cci)", "mgcp.param.localconnectionoptions.escci", FT_STRING, BASE_NONE, NULL, 0x0,
2428
14
          NULL, HFILL }},
2429
14
      { &hf_mgcp_param_localconnoptions_dqgi,
2430
14
        { "D-QoS GateID (dq-gi)", "mgcp.param.localconnectionoptions.dqgi", FT_STRING, BASE_NONE, NULL, 0x0,
2431
14
          NULL, HFILL }},
2432
14
      { &hf_mgcp_param_localconnoptions_dqrd,
2433
14
        { "D-QoS Reserve Destination (dq-rd)", "mgcp.param.localconnectionoptions.dqrd", FT_STRING, BASE_NONE, NULL, 0x0,
2434
14
          NULL, HFILL }},
2435
14
      { &hf_mgcp_param_localconnoptions_dqri,
2436
14
        { "D-QoS Resource ID (dq-ri)", "mgcp.param.localconnectionoptions.dqri", FT_STRING, BASE_NONE, NULL, 0x0,
2437
14
          NULL, HFILL }},
2438
14
      { &hf_mgcp_param_localconnoptions_dqrr,
2439
14
        { "D-QoS Resource Reservation (dq-rr)", "mgcp.param.localconnectionoptions.dqrr", FT_STRING, BASE_NONE, NULL, 0x0,
2440
14
          NULL, HFILL }},
2441
14
      { &hf_mgcp_param_localconnoptions_k,
2442
14
        { "Encryption Key (k)", "mgcp.param.localconnectionoptions.k", FT_STRING, BASE_NONE, NULL, 0x0,
2443
14
          NULL, HFILL }},
2444
14
      { &hf_mgcp_param_localconnoptions_gc,
2445
14
        { "Gain Control (gc)", "mgcp.param.localconnectionoptions.gc", FT_UINT32, BASE_DEC, NULL, 0x0,
2446
14
          NULL, HFILL }},
2447
14
      { &hf_mgcp_param_localconnoptions_fmtp,
2448
14
        { "Media Format (fmtp)", "mgcp.param.localconnectionoptions.fmtp", FT_STRING, BASE_NONE, NULL, 0x0,
2449
14
          NULL, HFILL }},
2450
14
      { &hf_mgcp_param_localconnoptions_nt,
2451
14
        { "Network Type (nt)", "mgcp.param.localconnectionoptions.nt", FT_STRING, BASE_NONE, NULL, 0x0,
2452
14
          NULL, HFILL }},
2453
14
      { &hf_mgcp_param_localconnoptions_ofmtp,
2454
14
        { "Optional Media Format (o-fmtp)", "mgcp.param.localconnectionoptions.ofmtp", FT_STRING, BASE_NONE, NULL, 0x0,
2455
14
          NULL, HFILL }},
2456
14
      { &hf_mgcp_param_localconnoptions_r,
2457
14
        { "Resource Reservation (r)", "mgcp.param.localconnectionoptions.r", FT_STRING, BASE_NONE, NULL, 0x0,
2458
14
          NULL, HFILL }},
2459
14
      { &hf_mgcp_param_localconnoptions_t,
2460
14
        { "Type of Service (r)", "mgcp.param.localconnectionoptions.t", FT_STRING, BASE_NONE, NULL, 0x0,
2461
14
          NULL, HFILL }},
2462
14
      { &hf_mgcp_param_localconnoptions_rcnf,
2463
14
        { "Reservation Confirmation (r-cnf)", "mgcp.param.localconnectionoptions.rcnf", FT_STRING, BASE_NONE, NULL, 0x0,
2464
14
          NULL, HFILL }},
2465
14
      { &hf_mgcp_param_localconnoptions_rdir,
2466
14
        { "Reservation Direction (r-dir)", "mgcp.param.localconnectionoptions.rdir", FT_STRING, BASE_NONE, NULL, 0x0,
2467
14
          NULL, HFILL }},
2468
14
      { &hf_mgcp_param_localconnoptions_rsh,
2469
14
        { "Resource Sharing (r-sh)", "mgcp.param.localconnectionoptions.rsh", FT_STRING, BASE_NONE, NULL, 0x0,
2470
14
          NULL, HFILL }},
2471
14
      { &hf_mgcp_param_localconnoptions_mp,
2472
14
        { "Multiple Packetization period (mp)", "mgcp.param.localconnectionoptions.mp", FT_STRING, BASE_NONE, NULL, 0x0,
2473
14
          NULL, HFILL }},
2474
14
      { &hf_mgcp_param_localconnoptions_fxr,
2475
14
        { "FXR (fxr/fx)", "mgcp.param.localconnectionoptions.fxr", FT_STRING, BASE_NONE, NULL, 0x0,
2476
14
          NULL, HFILL }},
2477
14
      { &hf_mgcp_param_localvoicemetrics,
2478
14
        { "LocalVoiceMetrics (XRM/LVM)", "mgcp.param.localvoicemetrics", FT_STRING, BASE_NONE, NULL, 0x0,
2479
14
          NULL, HFILL }},
2480
14
      { &hf_mgcp_param_remotevoicemetrics,
2481
14
        { "RemoteVoiceMetrics (XRM/RVM)", "mgcp.param.remotevoicemetrics", FT_STRING, BASE_NONE, NULL, 0x0,
2482
14
          NULL, HFILL }},
2483
14
      { &hf_mgcp_param_voicemetrics_nlr,
2484
14
        { "Network packet loss rate(NLR)", "mgcp.param.voicemetrics.nlr", FT_STRING, BASE_NONE, NULL, 0x0,
2485
14
          "Voice Metrics NLR", HFILL }},
2486
14
      { &hf_mgcp_param_voicemetrics_jdr,
2487
14
        { "Jitter buffer discard rate(JDR)", "mgcp.param.voicemetrics.jdr", FT_STRING, BASE_NONE, NULL, 0x0,
2488
14
          "Voice Metrics JDR", HFILL }},
2489
14
      { &hf_mgcp_param_voicemetrics_bld,
2490
14
        { "Burst loss density(BLD)", "mgcp.param.voicemetrics.bld", FT_STRING, BASE_NONE, NULL, 0x0,
2491
14
          "Voice Metrics BLD", HFILL }},
2492
14
      { &hf_mgcp_param_voicemetrics_gld,
2493
14
        { "Gap loss density(GLD)", "mgcp.param.voicemetrics.gld", FT_STRING, BASE_NONE, NULL, 0x0,
2494
14
          "Voice Metrics GLD", HFILL }},
2495
14
      { &hf_mgcp_param_voicemetrics_bd,
2496
14
        { "Burst duration(BD)", "mgcp.param.voicemetrics.bd", FT_STRING, BASE_NONE, NULL, 0x0,
2497
14
          "Voice Metrics BD", HFILL }},
2498
14
      { &hf_mgcp_param_voicemetrics_gd,
2499
14
        { "Gap duration(GD)", "mgcp.param.voicemetrics.gd", FT_STRING, BASE_NONE, NULL, 0x0,
2500
14
          "Voice Metrics GD", HFILL }},
2501
14
      { &hf_mgcp_param_voicemetrics_rtd,
2502
14
        { "Round trip network delay(RTD)", "mgcp.param.voicemetrics.rtd", FT_STRING, BASE_NONE, NULL, 0x0,
2503
14
          "Voice Metrics RTD", HFILL }},
2504
14
      { &hf_mgcp_param_voicemetrics_esd,
2505
14
        { "End system delay(ESD)", "mgcp.param.voicemetrics.esd", FT_STRING, BASE_NONE, NULL, 0x0,
2506
14
          "Voice Metrics ESD", HFILL }},
2507
14
      { &hf_mgcp_param_voicemetrics_sl,
2508
14
        { "Signal level(SL)", "mgcp.param.voicemetrics.sl", FT_STRING, BASE_NONE, NULL, 0x0,
2509
14
          "Voice Metrics SL", HFILL }},
2510
14
      { &hf_mgcp_param_voicemetrics_nl,
2511
14
        { "Noise level(NL)", "mgcp.param.voicemetrics.nl", FT_STRING, BASE_NONE, NULL, 0x0,
2512
14
          "Voice Metricsx NL", HFILL }},
2513
14
      { &hf_mgcp_param_voicemetrics_rerl,
2514
14
        { "Residual echo return loss(RERL)", "mgcp.param.voicemetrics.rerl", FT_STRING, BASE_NONE, NULL, 0x0,
2515
14
          "Voice Metrics ERL", HFILL }},
2516
14
      { &hf_mgcp_param_voicemetrics_gmn,
2517
14
        { "Minimum gap threshold(GMN)", "mgcp.param.voicemetrics.gmn", FT_STRING, BASE_NONE, NULL, 0x0,
2518
14
          "Voice Metrics GMN", HFILL }},
2519
14
      { &hf_mgcp_param_voicemetrics_nsr,
2520
14
        { "R factor(NSR)", "mgcp.param.voicemetrics.nsr", FT_STRING, BASE_NONE, NULL, 0x0,
2521
14
          "Voice Metrics NSR", HFILL }},
2522
14
      { &hf_mgcp_param_voicemetrics_xsr,
2523
14
        { "External R factor(XSR)", "mgcp.param.voicemetrics.xsr", FT_STRING, BASE_NONE, NULL, 0x0,
2524
14
          "Voice Metrics XSR", HFILL }},
2525
14
      { &hf_mgcp_param_voicemetrics_mlq,
2526
14
        { "Estimated MOS-LQ(MLQ)", "mgcp.param.voicemetrics.mlq", FT_STRING, BASE_NONE, NULL, 0x0,
2527
14
          "Voice Metrics MLQ", HFILL }},
2528
14
      { &hf_mgcp_param_voicemetrics_mcq,
2529
14
        { "Estimated MOS-CQ(MCQ)", "mgcp.param.voicemetrics.mcq", FT_STRING, BASE_NONE, NULL, 0x0,
2530
14
          "Voice Metrics MCQ", HFILL }},
2531
14
      { &hf_mgcp_param_voicemetrics_plc,
2532
14
        { "Packet loss concealment type(PLC)", "mgcp.param.voicemetrics.plc", FT_STRING, BASE_NONE, NULL, 0x0,
2533
14
          "Voice Metrics PLC", HFILL }},
2534
14
      { &hf_mgcp_param_voicemetrics_jba,
2535
14
        { "Jitter Buffer Adaptive(JBA)", "mgcp.param.voicemetrics.jba", FT_STRING, BASE_NONE, NULL, 0x0,
2536
14
          "Voice Metrics JBA", HFILL }},
2537
14
      { &hf_mgcp_param_voicemetrics_jbr,
2538
14
        { "Jitter Buffer Rate(JBR)", "mgcp.param.voicemetrics.jbr", FT_STRING, BASE_NONE, NULL, 0x0,
2539
14
          "Voice Metrics JBR", HFILL }},
2540
14
      { &hf_mgcp_param_voicemetrics_jbn,
2541
14
        { "Nominal jitter buffer delay(JBN)", "mgcp.param.voicemetrics.jbn", FT_STRING, BASE_NONE, NULL, 0x0,
2542
14
          "Voice Metrics JBN", HFILL }},
2543
14
      { &hf_mgcp_param_voicemetrics_jbm,
2544
14
        { "Maximum jitter buffer delay(JBM)", "mgcp.param.voicemetrics.jbm", FT_STRING, BASE_NONE, NULL, 0x0,
2545
14
          "Voice Metrics JBM", HFILL }},
2546
14
      { &hf_mgcp_param_voicemetrics_jbs,
2547
14
        { "Absolute maximum jitter buffer delay(JBS)", "mgcp.param.voicemetrics.jbs", FT_STRING, BASE_NONE, NULL, 0x0,
2548
14
          "Voice Metrics JBS", HFILL }},
2549
14
      { &hf_mgcp_param_voicemetrics_iaj,
2550
14
        { "Inter-arrival Jitter(IAJ)", "mgcp.param.voicemetrics.iaj", FT_STRING, BASE_NONE, NULL, 0x0,
2551
14
          "Voice Metrics IAJ", HFILL }},
2552
14
      { &hf_mgcp_param_connectionmode,
2553
14
        { "ConnectionMode (M)", "mgcp.param.connectionmode", FT_STRING, BASE_NONE, NULL, 0x0,
2554
14
          "Connection Mode", HFILL }},
2555
14
      { &hf_mgcp_param_reqevents,
2556
14
        { "RequestedEvents (R)", "mgcp.param.reqevents", FT_STRING, BASE_NONE, NULL, 0x0,
2557
14
          "Requested Events", HFILL }},
2558
14
      { &hf_mgcp_param_signalreq,
2559
14
        { "SignalRequests (S)", "mgcp.param.signalreq", FT_STRING, BASE_NONE, NULL, 0x0,
2560
14
          "Signal Request", HFILL }},
2561
14
      { &hf_mgcp_param_restartmethod,
2562
14
        { "RestartMethod (RM)", "mgcp.param.restartmethod", FT_STRING, BASE_NONE, NULL, 0x0,
2563
14
          "Restart Method", HFILL }},
2564
14
      { &hf_mgcp_param_restartdelay,
2565
14
        { "RestartDelay (RD)", "mgcp.param.restartdelay", FT_STRING, BASE_NONE, NULL, 0x0,
2566
14
          "Restart Delay", HFILL }},
2567
14
      { &hf_mgcp_param_digitmap,
2568
14
        { "DigitMap (D)", "mgcp.param.digitmap", FT_STRING, BASE_NONE, NULL, 0x0,
2569
14
          "Digit Map", HFILL }},
2570
14
      { &hf_mgcp_param_observedevent,
2571
14
        { "ObservedEvents (O)", "mgcp.param.observedevents", FT_STRING, BASE_NONE, NULL, 0x0,
2572
14
          "Observed Events", HFILL }},
2573
14
      { &hf_mgcp_param_connectionparam,
2574
14
        { "ConnectionParameters (P)", "mgcp.param.connectionparam", FT_STRING, BASE_NONE, NULL, 0x0,
2575
14
          "Connection Parameters", HFILL }},
2576
14
      { &hf_mgcp_param_connectionparam_ps,
2577
14
        { "Packets sent (PS)", "mgcp.param.connectionparam.ps", FT_UINT32, BASE_DEC, NULL, 0x0,
2578
14
          "Packets sent (P:PS)", HFILL }},
2579
14
      { &hf_mgcp_param_connectionparam_os,
2580
14
        { "Octets sent (OS)", "mgcp.param.connectionparam.os", FT_UINT32, BASE_DEC, NULL, 0x0,
2581
14
          "Octets sent (P:OS)", HFILL }},
2582
14
      { &hf_mgcp_param_connectionparam_pr,
2583
14
        { "Packets received (PR)", "mgcp.param.connectionparam.pr", FT_UINT32, BASE_DEC, NULL, 0x0,
2584
14
          "Packets received (P:PR)", HFILL }},
2585
14
      { &hf_mgcp_param_connectionparam_or,
2586
14
        { "Octets received (OR)", "mgcp.param.connectionparam.or", FT_UINT32, BASE_DEC, NULL, 0x0,
2587
14
          "Octets received (P:OR)", HFILL }},
2588
14
      { &hf_mgcp_param_connectionparam_pl,
2589
14
        { "Packets lost (PL)", "mgcp.param.connectionparam.pl", FT_UINT32, BASE_DEC, NULL, 0x0,
2590
14
          "Packets lost (P:PL)", HFILL }},
2591
14
      { &hf_mgcp_param_connectionparam_ji,
2592
14
        { "Jitter (JI)", "mgcp.param.connectionparam.ji", FT_UINT32, BASE_DEC, NULL, 0x0,
2593
14
          "Average inter-packet arrival jitter in milliseconds (P:JI)", HFILL }},
2594
14
      { &hf_mgcp_param_connectionparam_la,
2595
14
        { "Latency (LA)", "mgcp.param.connectionparam.la", FT_UINT32, BASE_DEC, NULL, 0x0,
2596
14
          "Average latency in milliseconds (P:LA)", HFILL }},
2597
14
      { &hf_mgcp_param_connectionparam_pcrps,
2598
14
        { "Remote Packets sent (PC/RPS)", "mgcp.param.connectionparam.pcrps", FT_UINT32, BASE_DEC, NULL, 0x0,
2599
14
          "Remote Packets sent (P:PC/RPS)", HFILL }},
2600
14
      { &hf_mgcp_param_connectionparam_pcros,
2601
14
        { "Remote Octets sent (PC/ROS)", "mgcp.param.connectionparam.pcros", FT_UINT32, BASE_DEC, NULL, 0x0,
2602
14
          "Remote Octets sent (P:PC/ROS)", HFILL }},
2603
14
      { &hf_mgcp_param_connectionparam_pcrpl,
2604
14
        { "Remote Packets lost (PC/RPL)", "mgcp.param.connectionparam.pcrpl", FT_UINT32, BASE_DEC, NULL, 0x0,
2605
14
          "Remote Packets lost (P:PC/RPL)", HFILL }},
2606
14
      { &hf_mgcp_param_connectionparam_pcrji,
2607
14
        { "Remote Jitter (PC/RJI)", "mgcp.param.connectionparam.pcrji", FT_UINT32, BASE_DEC, NULL, 0x0,
2608
14
          "Remote Jitter (P:PC/RJI)", HFILL }},
2609
14
      { &hf_mgcp_param_connectionparam_x,
2610
14
        { "Vendor Extension", "mgcp.param.connectionparam.x", FT_STRING, BASE_NONE, NULL, 0x0,
2611
14
          "Vendor Extension (P:X-*)", HFILL }},
2612
14
      { &hf_mgcp_param_reasoncode,
2613
14
        { "ReasonCode (E)", "mgcp.param.reasoncode", FT_STRING, BASE_NONE, NULL, 0x0,
2614
14
          "Reason Code", HFILL }},
2615
14
      { &hf_mgcp_param_eventstates,
2616
14
        { "EventStates (ES)", "mgcp.param.eventstates", FT_STRING, BASE_NONE, NULL, 0x0,
2617
14
          "Event States", HFILL }},
2618
14
      { &hf_mgcp_param_specificendpoint,
2619
14
        { "SpecificEndpointID (Z)", "mgcp.param.specificendpointid", FT_STRING, BASE_NONE, NULL, 0x0,
2620
14
          "Specific Endpoint ID", HFILL }},
2621
14
      { &hf_mgcp_param_secondendpointid,
2622
14
        { "SecondEndpointID (Z2)", "mgcp.param.secondendpointid", FT_STRING, BASE_NONE, NULL, 0x0,
2623
14
          "Second Endpoint ID", HFILL }},
2624
14
      { &hf_mgcp_param_reqinfo,
2625
14
        { "RequestedInfo (F)", "mgcp.param.reqinfo", FT_STRING, BASE_NONE, NULL, 0x0,
2626
14
          "Requested Info", HFILL }},
2627
14
      { &hf_mgcp_param_quarantinehandling,
2628
14
        { "QuarantineHandling (Q)", "mgcp.param.quarantinehandling", FT_STRING, BASE_NONE, NULL, 0x0,
2629
14
          "Quarantine Handling", HFILL }},
2630
14
      { &hf_mgcp_param_detectedevents,
2631
14
        { "DetectedEvents (T)", "mgcp.param.detectedevents", FT_STRING, BASE_NONE, NULL, 0x0,
2632
14
          "Detected Events", HFILL }},
2633
14
      { &hf_mgcp_param_capabilities,
2634
14
        { "Capabilities (A)", "mgcp.param.capabilities", FT_STRING, BASE_NONE, NULL, 0x0,
2635
14
          NULL, HFILL }},
2636
14
      { &hf_mgcp_param_maxmgcpdatagram,
2637
14
        {"MaxMGCPDatagram (MD)", "mgcp.param.maxmgcpdatagram", FT_STRING, BASE_NONE, NULL, 0x0,
2638
14
         "Maximum MGCP Datagram size", HFILL }},
2639
14
      { &hf_mgcp_param_packagelist,
2640
14
        {"PackageList (PL)", "mgcp.param.packagelist", FT_STRING, BASE_NONE, NULL, 0x0,
2641
14
         "Package List", HFILL }},
2642
14
      { &hf_mgcp_param_extension,
2643
14
        { "Extension Parameter (non-critical)", "mgcp.param.extension", FT_STRING, BASE_NONE, NULL, 0x0,
2644
14
          NULL, HFILL }},
2645
14
      { &hf_mgcp_param_extension_critical,
2646
14
        { "Extension Parameter (critical)", "mgcp.param.extensioncritical", FT_STRING, BASE_NONE, NULL, 0x0,
2647
14
          "Critical Extension Parameter", HFILL }},
2648
14
      { &hf_mgcp_param_resourceid,
2649
14
        { "ResourceIdentifier (DQ-RI)", "mgcp.param.resourceid", FT_STRING, BASE_NONE, NULL, 0x0,
2650
14
          "Resource Identifier", HFILL }},
2651
14
      { &hf_mgcp_param_invalid,
2652
14
        { "Invalid Parameter", "mgcp.param.invalid", FT_STRING, BASE_NONE, NULL, 0x0,
2653
14
          NULL, HFILL }},
2654
14
      { &hf_mgcp_messagecount,
2655
14
        { "MGCP Message Count", "mgcp.messagecount", FT_UINT32, BASE_DEC, NULL, 0x0,
2656
14
          "Number of MGCP message in a packet", HFILL }},
2657
14
      { &hf_mgcp_dup,
2658
14
        { "Duplicate Message", "mgcp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
2659
14
          NULL, HFILL }},
2660
14
      { &hf_mgcp_req_dup,
2661
14
        { "Duplicate Request", "mgcp.req.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
2662
14
          NULL, HFILL }},
2663
14
      { &hf_mgcp_req_dup_frame,
2664
14
        { "Original Request Frame", "mgcp.req.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2665
14
          "Frame containing original request", HFILL }},
2666
14
      { &hf_mgcp_rsp_dup,
2667
14
        { "Duplicate Response", "mgcp.rsp.dup", FT_UINT32, BASE_DEC, NULL, 0x0,
2668
14
          NULL, HFILL }},
2669
14
      { &hf_mgcp_rsp_dup_frame,
2670
14
        { "Original Response Frame", "mgcp.rsp.dup.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2671
14
          "Frame containing original response", HFILL }},
2672
14
      { &hf_mgcp_param_x_osmux,
2673
14
        { "X-Osmux", "mgcp.param.x_osmux", FT_STRING, BASE_NONE, NULL, 0x0,
2674
14
          "Osmux CID", HFILL }},
2675
14
      { &hf_mgcp_unknown_parameter,
2676
14
        { "Unknown parameter", "mgcp.unknown_parameter", FT_STRING, BASE_NONE, NULL, 0x0,
2677
14
          NULL, HFILL }},
2678
14
      { &hf_mgcp_malformed_parameter,
2679
14
        { "Malformed parameter", "mgcp.rsp.malformed_parameter", FT_STRING, BASE_NONE, NULL, 0x0,
2680
14
          NULL, HFILL }},
2681
14
    };
2682
2683
14
  static int *ett[] =
2684
14
    {
2685
14
      &ett_mgcp,
2686
14
      &ett_mgcp_param,
2687
14
      &ett_mgcp_param_connectionparam,
2688
14
      &ett_mgcp_param_localconnectionoptions,
2689
14
      &ett_mgcp_param_localvoicemetrics,
2690
14
      &ett_mgcp_param_remotevoicemetrics
2691
14
    };
2692
2693
14
  static ei_register_info ei[] = {
2694
14
    { &ei_mgcp_rsp_rspcode_invalid, { "mgcp.rsp.rspcode.invalid", PI_MALFORMED, PI_ERROR,
2695
14
    "RSP code must be a string containing an integer", EXPFILL }}
2696
14
  };
2697
2698
14
  module_t *mgcp_module;
2699
2700
  /* Register protocol */
2701
14
  proto_mgcp = proto_register_protocol("Media Gateway Control Protocol", "MGCP", "mgcp");
2702
14
  proto_register_field_array(proto_mgcp, hf, array_length(hf));
2703
14
  proto_register_subtree_array(ett, array_length(ett));
2704
2705
14
  mgcp_calls = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), mgcp_call_hash, mgcp_call_equal);
2706
2707
14
  mgcp_handle = register_dissector("mgcp", dissect_mgcp, proto_mgcp);
2708
2709
  /* Register our configuration options */
2710
14
  mgcp_module = prefs_register_protocol(proto_mgcp, proto_reg_handoff_mgcp);
2711
2712
14
  prefs_register_uint_preference(mgcp_module, "tcp.gateway_port",
2713
14
               "MGCP Gateway TCP Port",
2714
14
               "Set the UDP port for gateway messages "
2715
14
               "(if other than the default of 2427)",
2716
14
               10, &global_mgcp_gateway_tcp_port);
2717
2718
14
  prefs_register_uint_preference(mgcp_module, "udp.gateway_port",
2719
14
               "MGCP Gateway UDP Port",
2720
14
               "Set the TCP port for gateway messages "
2721
14
               "(if other than the default of 2427)",
2722
14
               10, &global_mgcp_gateway_udp_port);
2723
2724
14
  prefs_register_uint_preference(mgcp_module, "tcp.callagent_port",
2725
14
               "MGCP Callagent TCP Port",
2726
14
               "Set the TCP port for callagent messages "
2727
14
               "(if other than the default of 2727)",
2728
14
               10, &global_mgcp_callagent_tcp_port);
2729
2730
14
  prefs_register_uint_preference(mgcp_module, "udp.callagent_port",
2731
14
               "MGCP Callagent UDP Port",
2732
14
               "Set the UDP port for callagent messages "
2733
14
               "(if other than the default of 2727)",
2734
14
               10, &global_mgcp_callagent_udp_port);
2735
2736
2737
14
  prefs_register_bool_preference(mgcp_module, "display_raw_text",
2738
14
               "Display raw text for MGCP message",
2739
14
               "Specifies that the raw text of the "
2740
14
               "MGCP message should be displayed "
2741
14
               "instead of (or in addition to) the "
2742
14
               "dissection tree",
2743
14
               &global_mgcp_raw_text);
2744
2745
14
  prefs_register_obsolete_preference(mgcp_module, "display_dissect_tree");
2746
2747
14
  prefs_register_bool_preference(mgcp_module, "display_mgcp_message_count",
2748
14
               "Display the number of MGCP messages",
2749
14
               "Display the number of MGCP messages "
2750
14
               "found in a packet in the protocol column.",
2751
14
               &global_mgcp_message_count);
2752
2753
14
  mgcp_tap = register_tap("mgcp");
2754
2755
14
  register_rtd_table(proto_mgcp, NULL, 1, NUM_TIMESTATS, mgcp_message_type, mgcpstat_packet, NULL);
2756
2757
14
  expert_mgcp = expert_register_protocol(proto_mgcp);
2758
14
  expert_register_field_array(expert_mgcp, ei, array_length(ei));
2759
2760
14
}
2761
2762
/* The registration hand-off routine */
2763
void proto_reg_handoff_mgcp(void)
2764
14
{
2765
14
  static bool mgcp_prefs_initialized = false;
2766
14
  static dissector_handle_t mgcp_tpkt_handle;
2767
  /*
2768
   * Variables to allow for proper deletion of dissector registration when
2769
   * the user changes port from the gui.
2770
   */
2771
14
  static unsigned gateway_tcp_port;
2772
14
  static unsigned gateway_udp_port;
2773
14
  static unsigned callagent_tcp_port;
2774
14
  static unsigned callagent_udp_port;
2775
2776
14
  if (!mgcp_prefs_initialized)
2777
14
  {
2778
    /* Get a handle for the SDP dissector. */
2779
14
    sdp_handle = find_dissector_add_dependency("sdp", proto_mgcp);
2780
14
    mgcp_tpkt_handle = create_dissector_handle(dissect_tpkt_mgcp, proto_mgcp);
2781
14
    mgcp_prefs_initialized = true;
2782
14
  }
2783
0
  else
2784
0
  {
2785
0
    dissector_delete_uint("tcp.port", gateway_tcp_port,   mgcp_tpkt_handle);
2786
0
    dissector_delete_uint("udp.port", gateway_udp_port,   mgcp_handle);
2787
0
    dissector_delete_uint("tcp.port", callagent_tcp_port, mgcp_tpkt_handle);
2788
0
    dissector_delete_uint("udp.port", callagent_udp_port, mgcp_handle);
2789
0
  }
2790
2791
  /* Set our port number for future use */
2792
14
  gateway_tcp_port = global_mgcp_gateway_tcp_port;
2793
14
  gateway_udp_port = global_mgcp_gateway_udp_port;
2794
2795
14
  callagent_tcp_port = global_mgcp_callagent_tcp_port;
2796
14
  callagent_udp_port = global_mgcp_callagent_udp_port;
2797
2798
  /* Names of port preferences too specific to add "auto" preference here */
2799
14
  dissector_add_uint("tcp.port", global_mgcp_gateway_tcp_port,   mgcp_tpkt_handle);
2800
14
  dissector_add_uint("udp.port", global_mgcp_gateway_udp_port,   mgcp_handle);
2801
14
  dissector_add_uint("tcp.port", global_mgcp_callagent_tcp_port, mgcp_tpkt_handle);
2802
14
  dissector_add_uint("udp.port", global_mgcp_callagent_udp_port, mgcp_handle);
2803
14
}
2804
2805
/*
2806
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2807
 *
2808
 * Local variables:
2809
 * c-basic-offset: 8
2810
 * tab-width: 8
2811
 * indent-tabs-mode: t
2812
 * End:
2813
 *
2814
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2815
 * :indentSize=8:tabSize=8:noTabs=false:
2816
 */