Document the new Copy Profile button.
[obnox/wireshark/wip.git] / epan / dissectors / packet-catapult-dct2000.c
1 /* packet-catapult-dct2000.c
2  * Routines for Catapult DCT2000 packet stub header disassembly
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <glib.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35
36 #include <epan/packet.h>
37 #include <epan/expert.h>
38 #include <epan/emem.h>
39 #include <epan/proto.h>
40 #include <epan/ipproto.h>
41 #include <epan/prefs.h>
42 #include <epan/strutil.h>
43 #include <epan/addr_resolv.h>
44
45 #include <wiretap/catapult_dct2000.h>
46 #include "packet-umts_fp.h"
47 #include "packet-mac-lte.h"
48 #include "packet-rlc-lte.h"
49 #include "packet-pdcp-lte.h"
50
51 /* Protocol and registered fields. */
52 static int proto_catapult_dct2000 = -1;
53
54 static int hf_catapult_dct2000_context = -1;
55 static int hf_catapult_dct2000_port_number = -1;
56 static int hf_catapult_dct2000_timestamp = -1;
57 static int hf_catapult_dct2000_protocol = -1;
58 static int hf_catapult_dct2000_variant = -1;
59 static int hf_catapult_dct2000_outhdr = -1;
60 static int hf_catapult_dct2000_direction = -1;
61 static int hf_catapult_dct2000_encap = -1;
62 static int hf_catapult_dct2000_unparsed_data = -1;
63 static int hf_catapult_dct2000_comment = -1;
64 static int hf_catapult_dct2000_tty = -1;
65 static int hf_catapult_dct2000_tty_line = -1;
66 static int hf_catapult_dct2000_dissected_length = -1;
67
68 static int hf_catapult_dct2000_ipprim_addresses = -1;
69 static int hf_catapult_dct2000_ipprim_src_addr_v4 = -1;
70 static int hf_catapult_dct2000_ipprim_src_addr_v6 = -1;
71 static int hf_catapult_dct2000_ipprim_dst_addr_v4 = -1;
72 static int hf_catapult_dct2000_ipprim_dst_addr_v6 = -1;
73 static int hf_catapult_dct2000_ipprim_addr_v4 = -1;
74 static int hf_catapult_dct2000_ipprim_addr_v6 = -1;
75 static int hf_catapult_dct2000_ipprim_udp_src_port = -1;
76 static int hf_catapult_dct2000_ipprim_udp_dst_port = -1;
77 static int hf_catapult_dct2000_ipprim_udp_port = -1;
78 static int hf_catapult_dct2000_ipprim_tcp_src_port = -1;
79 static int hf_catapult_dct2000_ipprim_tcp_dst_port = -1;
80 static int hf_catapult_dct2000_ipprim_tcp_port = -1;
81 static int hf_catapult_dct2000_ipprim_conn_id = -1;
82
83 static int hf_catapult_dct2000_sctpprim_addresses = -1;
84 static int hf_catapult_dct2000_sctpprim_dst_addr_v4 = -1;
85 static int hf_catapult_dct2000_sctpprim_dst_addr_v6 = -1;
86 static int hf_catapult_dct2000_sctpprim_addr_v4 = -1;
87 static int hf_catapult_dct2000_sctpprim_addr_v6 = -1;
88 static int hf_catapult_dct2000_sctpprim_dst_port = -1;
89
90 static int hf_catapult_dct2000_lte_ueid = -1;
91 static int hf_catapult_dct2000_lte_srbid = -1;
92 static int hf_catapult_dct2000_lte_drbid = -1;
93 static int hf_catapult_dct2000_lte_cellid = -1;
94 static int hf_catapult_dct2000_lte_bcch_transport = -1;
95 static int hf_catapult_dct2000_lte_rlc_op = -1;
96 static int hf_catapult_dct2000_lte_rlc_channel_type = -1;
97 static int hf_catapult_dct2000_lte_rlc_mui = -1;
98 static int hf_catapult_dct2000_lte_rlc_cnf = -1;
99 static int hf_catapult_dct2000_lte_rlc_discard_req = -1;
100
101
102 /* Variables used for preferences */
103 static gboolean catapult_dct2000_try_ipprim_heuristic = TRUE;
104 static gboolean catapult_dct2000_try_sctpprim_heuristic = TRUE;
105 static gboolean catapult_dct2000_dissect_lte_rrc = TRUE;
106 static gboolean catapult_dct2000_dissect_lte_s1ap = TRUE;
107 static gboolean catapult_dct2000_dissect_mac_lte_oob_messages = TRUE;
108
109 /* Protocol subtree. */
110 static int ett_catapult_dct2000 = -1;
111 static int ett_catapult_dct2000_ipprim = -1;
112 static int ett_catapult_dct2000_sctpprim = -1;
113 static int ett_catapult_dct2000_tty = -1;
114
115 static const value_string direction_vals[] = {
116     { 0,   "Sent" },
117     { 1,   "Received" },
118     { 0,   NULL },
119 };
120
121 static const value_string encap_vals[] = {
122     { WTAP_ENCAP_RAW_IP,                 "Raw IP" },
123     { WTAP_ENCAP_ETHERNET,               "Ethernet" },
124     { WTAP_ENCAP_ISDN,                   "LAPD" },
125     { WTAP_ENCAP_ATM_PDUS_UNTRUNCATED,   "ATM (PDUs untruncated)" },
126     { WTAP_ENCAP_PPP,                    "PPP" },
127     { DCT2000_ENCAP_SSCOP,               "SSCOP" },
128     { WTAP_ENCAP_FRELAY,                 "Frame Relay" },
129     { WTAP_ENCAP_MTP2,                   "MTP2" },
130     { DCT2000_ENCAP_NBAP,                "NBAP" },
131     { DCT2000_ENCAP_UNHANDLED,           "No Direct Encapsulation" },
132     { 0,                                 NULL },
133 };
134
135 static const value_string bcch_transport_vals[] = {
136     { BCH_TRANSPORT,    "BCH" },
137     { DLSCH_TRANSPORT,  "DLSCH" },
138     { 0,   NULL },
139 };
140
141
142 #define RLC_MGMT_ASSIGN                 0x41
143 #define RLC_AM_DATA_REQ                 0x60
144 #define RLC_AM_DATA_IND                 0x61
145 #define RLC_AM_DATA_CONF                0x62
146 #define RLC_UM_DATA_REQ                 0x70
147 #define RLC_UM_DATA_IND                 0x71
148 #define RLC_UM_DATA_CONF                0x74
149 #define RLC_TR_DATA_REQ                 0x80
150 #define RLC_TR_DATA_IND                 0x81
151 #define RLC_TR_DATA_CONF                0x83
152
153 static const value_string rlc_op_vals[] = {
154     { RLC_AM_DATA_REQ,   "[UL] [AM]" },
155     { RLC_AM_DATA_IND,   "[DL] [AM]" },
156     { RLC_UM_DATA_REQ,   "[UL] [UM]"},
157     { RLC_UM_DATA_IND,   "[DL] [UM]"},
158     { RLC_TR_DATA_REQ,   "[UL] [TM]"},
159     { RLC_TR_DATA_IND,   "[DL] [TM]"},
160     { 0,   NULL }
161 };
162
163
164 static const value_string rlc_logical_channel_vals[] = {
165     { Channel_DCCH,  "DCCH"},
166     { Channel_BCCH,  "BCCH"},
167     { Channel_CCCH,  "CCCH"},
168     { Channel_PCCH,  "PCCH"},
169     { 0,             NULL}
170 };
171
172
173
174 #define MAX_OUTHDR_VALUES 32
175
176 static guint outhdr_values[MAX_OUTHDR_VALUES];
177 static gint outhdr_values_found = 0;
178
179 extern int proto_fp;
180 extern int proto_mac_lte;
181 extern int proto_rlc_lte;
182 extern int proto_pdcp_lte;
183
184 static dissector_handle_t mac_lte_handle;
185 static dissector_handle_t rlc_lte_handle;
186 static dissector_handle_t pdcp_lte_handle;
187
188 void proto_register_catapult_dct2000(void);
189
190 static dissector_handle_t look_for_dissector(char *protocol_name);
191 static void parse_outhdr_string(const guchar *outhdr_string);
192 static void attach_fp_info(packet_info *pinfo, gboolean received,
193                            const char *protocol_name, int variant);
194 static void attach_mac_lte_info(packet_info *pinfo);
195 static void attach_rlc_lte_info(packet_info *pinfo);
196 static void attach_pdcp_lte_info(packet_info *pinfo);
197
198
199
200 /* Return the number of bytes used to encode the length field
201    (we're not interested in the length value itself) */
202 static int skipASNLength(guint8 value)
203 {
204     if ((value & 0x80) == 0)
205     {
206         return 1;
207     }
208     else
209     {
210         return ((value & 0x03) == 1) ? 2 : 3;
211     }
212 }
213
214
215 /* Look for the protocol data within an ipprim packet.
216    Only set *data_offset if data field found. */
217 static gboolean find_ipprim_data_offset(tvbuff_t *tvb, int *data_offset, guint8 direction,
218                                         guint32 *source_addr_offset, guint8 *source_addr_length,
219                                         guint32 *dest_addr_offset,   guint8 *dest_addr_length,
220                                         guint32 *source_port_offset, guint32 *dest_port_offset,
221                                         port_type *type_of_port,
222                                         guint16 *conn_id_offset)
223 {
224     guint8 length;
225     int offset = *data_offset;
226
227     /* Get the ipprim command code. */
228     guint8 tag = tvb_get_guint8(tvb, offset++);
229
230     /* Only accept UDP or TCP data request or indication */
231     switch (tag) {
232         case 0x23:  /* UDP data request */
233         case 0x24:  /* UDP data indication */
234             *type_of_port = PT_UDP;
235             break;
236         case 0x45:  /* TCP data request */
237         case 0x46:  /* TCP data indication */
238             *type_of_port = PT_TCP;
239             break;
240         default:
241             return FALSE;
242     }
243
244     /* Skip any other TLC fields before reach payload */
245     while (tvb_length_remaining(tvb, offset) > 2) {
246         /* Look at next tag */
247         tag = tvb_get_guint8(tvb, offset++);
248
249         /* Is this the data payload we're expecting? */
250         if (((tag == 0x34) && (*type_of_port == PT_UDP)) ||
251             ((tag == 0x48) && (*type_of_port == PT_TCP))) {
252
253             *data_offset = offset;
254             return TRUE;
255         }
256         else {
257             /* Read length in next byte */
258             length = tvb_get_guint8(tvb, offset++);
259
260             if (tag == 0x31 && length >=4) {
261                 /* Remote IP address */
262                 if (direction == 0) {
263                     /* Sent *to* remote, so dest */
264                     *dest_addr_offset = offset;
265                     *dest_addr_length = (length/4) * 4;
266                 }
267                 else {
268                     *source_addr_offset = offset;
269                     *source_addr_length = (length/4) * 4;
270                 }
271
272                 /* Remote port follows (if present) */
273                 if ((length % 4) == 2) {
274                     if (direction == 0) {
275                         *dest_port_offset = offset + 4;
276                     }
277                     else {
278                         *source_port_offset = offset + 4;
279                     }
280                 }
281             }
282             else
283             if (tag == 0x32) {
284                 if (length == 4 || length == 16) {
285                     /* Local IP address */
286                     if (direction == 0) {
287                         /* Sent *from* local, so source */
288                         *source_addr_offset = offset;
289                         *source_addr_length = length;
290                     }
291                     else {
292                         *dest_addr_offset = offset;
293                         *dest_addr_length = length;
294                     }
295                 }
296             }
297             else
298             if (tag == 0x33 && length == 2) {
299                 /* Get local port */
300                 if (direction == 0) {
301                     /* Sent from local, so source */
302                     *source_port_offset = offset;
303                 }
304                 else {
305                     *dest_port_offset = offset;
306                 }
307             }
308             else
309             if (tag == 0x36 && length == 2) {
310                 /* Get conn_id */
311                 *conn_id_offset = offset;
312             }
313
314             /* Skip the length of the indicated value */
315             offset += length;
316         }
317     }
318
319     /* No data found... */
320     return FALSE;
321 }
322
323
324
325 /* Look for the protocol data within an sctpprim (variant 1 or 2...) packet.
326    Only set *data_offset if data field found. */
327 static gboolean find_sctpprim_variant1_data_offset(tvbuff_t *tvb, int *data_offset,
328                                                    guint32 *dest_addr_offset,
329                                                    guint16 *dest_addr_length,
330                                                    guint32 *dest_port_offset)
331 {
332     int offset = *data_offset;
333
334     /* Get the sctpprim command code. */
335     guint8 first_tag = tvb_get_guint8(tvb, offset++);
336     guint8 tag;
337     guint8 first_length_byte;
338
339     /* Only accept interested in data requests or indications */
340     switch (first_tag) {
341         case 0x04:  /* data request */
342         case 0x62:  /* data indication */
343             break;
344         default:
345             return FALSE;
346     }
347
348     first_length_byte = tvb_get_guint8(tvb, offset);
349     offset += skipASNLength(first_length_byte);
350
351     /* Skip any other fields before reach payload */
352     while (tvb_length_remaining(tvb, offset) > 2) {
353         /* Look at next tag */
354         tag = tvb_get_guint8(tvb, offset++);
355
356         /* Is this the data payload we're expecting? */
357         if (tag == 0x19) {
358             *data_offset = offset;
359             return TRUE;
360         }
361         else {
362             /* Skip length field */
363             offset++;
364             switch (tag) {
365                 case 0x0a: /* destPort */
366                     *dest_port_offset = offset;
367                     offset += 2;
368                     break;
369
370                 case 0x01: /* sctpInstanceNum */
371                 case 0x1e: /* strseqnum */
372                 case 0x0d: /* streamnum */
373                     offset += 2;
374                     continue;
375
376                 case 0x09: /* ipv4Address */
377                     *dest_addr_offset = offset;
378                     *dest_addr_length = 4;
379                     offset += 4;
380                     break;
381
382                 case 0x1d:
383                 case 0x0c: /* payloadType */
384                     offset += 4;
385                     continue;
386
387                 default:
388                     /* Fail if not a known header field */
389                     return FALSE;
390             }
391         }
392     }
393
394     /* No data found... */
395     return FALSE;
396 }
397
398 /* Look for the protocol data within an sctpprim (variant 3) packet.
399    Only set *data_offset if data field found. */
400 static gboolean find_sctpprim_variant3_data_offset(tvbuff_t *tvb, int *data_offset,
401                                                    guint32 *dest_addr_offset,
402                                                    guint16 *dest_addr_length,
403                                                    guint32 *dest_port_offset)
404 {
405     guint16 tag = 0;
406     guint16 length = 0;
407     int offset = *data_offset;
408
409     /* Get the sctpprim (2 byte) command code. */
410     guint16 top_tag = tvb_get_ntohs(tvb, offset);
411     offset += 2;
412
413     /* Only interested in data requests or indications */
414     switch (top_tag) {
415         case 0x0400:  /* SendDataReq */
416         case 0x6200:  /* DataInd */
417             break;
418
419         default:
420             return FALSE;
421     }
422
423     /* Overall length field is next 2 bytes */
424     offset += 2;
425
426     /* Rx/Tx ops have different formats */
427
428     /*****************/
429     /* DataInd        */
430     if (top_tag == 0x6200) {
431         /* Next 2 bytes are associate ID */
432         offset += 2;
433
434         /* Next 2 bytes are destination port */
435         *dest_port_offset = offset;
436         offset += 2;
437
438         /* Destination address should follow - check tag */
439         tag = tvb_get_ntohs(tvb, offset);
440         if (tag != 0x0900) {
441             return FALSE;
442         }
443         else {
444             /* Skip tag */
445             offset += 2;
446
447             /* Length field */
448             length = tvb_get_ntohs(tvb, offset) / 2;
449             if ((length != 4) && (length != 16))
450             {
451                 return FALSE;
452             }
453             offset += 2;
454
455             /* Address data is here */
456             *dest_addr_offset = offset;
457             *dest_addr_length = length;
458
459             offset += length;
460         }
461
462         /* Not interested in remaining (fixed) fields */
463         if (tvb_reported_length_remaining(tvb, offset) > (4 + 2 + 2 + 4)) {
464             offset += (4 + 2 + 2 + 4);
465         }
466         else {
467             return FALSE;
468         }
469
470         /* Data should now be here */
471         tag = tvb_get_ntohs(tvb, offset);
472         offset += 2;
473         if (tag == 0x1900) {
474             /* 2-byte length field */
475             offset += 2;
476
477             /* Data is here!!! */
478             *data_offset = offset;
479             return TRUE;
480         }
481         else {
482             return FALSE;
483         }
484     }
485
486     /***************/
487     /* SendDataReq */
488     else if (top_tag == 0x0400) {
489         /* AssociateId should follow - check tag */
490         tag = tvb_get_ntohs(tvb, offset);
491         if (tag != 0x2400) {
492             return FALSE;
493         }
494         else {
495             /* Skip tag */
496             offset += 2;
497
498             /* Skip 2-byte value */
499             offset += 2;
500         }
501
502         /* Get tag */
503         tag = tvb_get_ntohs(tvb, offset);
504         offset += 2;
505
506         /* Some optional params */
507         while ((tag != 0x0c00) && (tvb_length_remaining(tvb, offset) > 4)) {
508             switch (tag) {
509                 case 0x0900:   /* Dest address */
510                     /* Length field */
511                     length = tvb_get_ntohs(tvb, offset) / 2;
512                     if ((length != 4) && (length != 16)) {
513                         return FALSE;
514                     }
515                     offset += 2;
516
517                     /* Address data is here */
518                     *dest_addr_offset = offset;
519                     *dest_addr_length = length;
520
521                     offset += length;
522                     break;
523
524                 case 0x0a00:   /* Dest port number */
525                     *dest_port_offset = offset;
526                     offset += 2;
527                     break;
528
529                 case 0x0d00:   /* StreamNum */
530                     *dest_port_offset = offset;
531                     offset += 2;
532                     break;
533
534
535                 default:
536                     return FALSE;
537             }
538
539             /* Get the next tag */
540             tag = tvb_get_ntohs(tvb, offset);
541             offset += 2;
542         }
543
544
545         /* Mandatory payload type */
546         if (tag != 0x0c00) {
547             return FALSE;
548         }
549         length = tvb_get_ntohs(tvb, offset) / 2;
550         offset += 2;
551         offset += length;
552
553
554         /* Optional options */
555         tag = tvb_get_ntohs(tvb, offset);
556         offset += 2;
557         if (tag == 0x0b00) {
558             length = tvb_get_ntohs(tvb, offset) / 2;
559             offset += 2;
560
561             offset += length;
562
563             /* Get next tag */
564             tag = tvb_get_ntohs(tvb, offset);
565             offset += 2;
566         }
567
568
569         /* Data should now be here!! */
570         if (tag == 0x1900) {
571             /* 2-byte length field */
572             offset += 2;
573
574             /* Data is here!!! */
575             *data_offset = offset;
576             return TRUE;
577         }
578         else {
579             return FALSE;
580         }
581     }
582
583     return FALSE;
584 }
585
586
587
588
589 /* Dissect an RRC LTE frame by first parsing the header entries then passing
590    the data to the RRC dissector, according to direction and channel type.
591    TODO: factor out common code between this function and dissect_pdcp_lte() */
592 static void dissect_rrc_lte(tvbuff_t *tvb, gint offset,
593                             packet_info *pinfo, proto_tree *tree)
594 {
595     guint8  tag;
596     dissector_handle_t protocol_handle = 0;
597     gboolean isUplink = FALSE;
598     LogicalChannelType logicalChannelType;
599     guint8   bcch_transport = 0;
600     tvbuff_t *rrc_tvb;
601
602     /* Top-level opcode */
603     tag = tvb_get_guint8(tvb, offset++);
604     switch (tag) {
605         case 0x00:    /* Data_Req_UE */
606         case 0x04:    /* Data_Ind_eNodeB */
607             isUplink = TRUE;
608             break;
609
610         case 0x02:    /* Data_Req_eNodeB */
611         case 0x03:    /* Data_Ind_UE */
612             isUplink = FALSE;
613             break;
614
615         default:
616             /* Unexpected opcode tag! */
617             return;
618     }
619
620     /* Skip length */
621     offset += skipASNLength(tvb_get_guint8(tvb, offset));
622
623     /* Get next tag */
624     tag = tvb_get_guint8(tvb, offset++);
625     switch (tag) {
626         case 0x12:    /* UE_Id_LCId */
627
628             /* Dedicated channel info */
629
630             /* Length will fit in one byte here */
631             offset++;
632
633             logicalChannelType = Channel_DCCH;
634
635             /* UEId */
636             proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid, tvb, offset, 2, FALSE);
637             offset += 2;
638
639             /* Get tag of channel type */
640             tag = tvb_get_guint8(tvb, offset++);
641
642             switch (tag) {
643                 case 0:
644                     offset++;
645                     col_append_fstr(pinfo->cinfo, COL_INFO, " SRB:%u",
646                                     tvb_get_guint8(tvb, offset));
647                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_srbid,
648                                         tvb, offset, 1, FALSE);
649
650                     break;
651                 case 1:
652                     offset++;
653                     col_append_fstr(pinfo->cinfo, COL_INFO, " DRB:%u",
654                                     tvb_get_guint8(tvb, offset));
655                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_drbid,
656                                         tvb, offset, 1, FALSE);
657                     break;
658
659                 default:
660                     /* Unexpected channel type */
661                     return;
662             }
663             break;
664
665         case 0x1a:     /* Cell_LCId */
666
667             /* Common channel info */
668
669             /* Skip length */
670             offset++;
671
672             /* Cell-id */
673             proto_tree_add_item(tree, hf_catapult_dct2000_lte_cellid,
674                                 tvb, offset, 2, FALSE);
675             offset += 2;
676
677             /* Logical channel type */
678             proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_channel_type,
679                                 tvb, offset, 1, FALSE);
680             logicalChannelType = (LogicalChannelType)tvb_get_guint8(tvb, offset++);
681             col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
682                             val_to_str(logicalChannelType, rlc_logical_channel_vals,
683                                        "UNKNOWN-CHANNEL"));
684
685             switch (logicalChannelType) {
686                 case Channel_BCCH:
687                     /* Skip length */
688                     offset++;
689
690                     /* Transport channel type */
691                     bcch_transport = tvb_get_guint8(tvb, offset);
692                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_bcch_transport,
693                                         tvb, offset, 1, FALSE);
694                     offset++;
695                     break;
696
697                 case Channel_CCCH:
698                     /* Skip length */
699                     offset++;
700
701                     /* UEId */
702                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
703                                         tvb, offset, 2, FALSE);
704                     offset += 2;
705                     break;
706
707                 default:
708                     break;
709             }
710             break;
711
712         default:
713             /* Unexpected tag */
714             return;
715     }
716
717     /* Data tag should follow */
718     tag = tvb_get_guint8(tvb, offset++);
719     if (tag != 0xaa) {
720         return;
721     }
722
723     /* Skip length */
724     offset += skipASNLength(tvb_get_guint8(tvb, offset));
725
726     /* Look up dissector handle corresponding to direction and channel type */
727     if (isUplink) {
728
729         /* Uplink channel types */
730         switch (logicalChannelType) {
731             case Channel_DCCH:
732                 protocol_handle = find_dissector("lte-rrc.ul.dcch");
733                 break;
734             case Channel_CCCH:
735                 protocol_handle = find_dissector("lte-rrc.ul.ccch");
736                 break;
737
738             default:
739                 /* Unknown Uplink channel type */
740                 break;
741         }
742     } else {
743
744         /* Downlink channel types */
745         switch (logicalChannelType) {
746             case Channel_DCCH:
747                 protocol_handle = find_dissector("lte-rrc.dl.dcch");
748                 break;
749             case Channel_CCCH:
750                 protocol_handle = find_dissector("lte-rrc.dl.ccch");
751                 break;
752             case Channel_PCCH:
753                 protocol_handle = find_dissector("lte-rrc.pcch");
754                 break;
755             case Channel_BCCH:
756                 if (bcch_transport == 1) {
757                     protocol_handle = find_dissector("lte-rrc.bcch.bch");
758                 }
759                 else {
760                     protocol_handle = find_dissector("lte-rrc.bcch.dl.sch");
761                 }
762                 break;
763
764             default:
765                 /* Unknown Downlink channel type */
766                 break;
767         }
768     }
769
770     /* Send to RRC dissector, if got here, have sub-dissector and some data left */
771     if ((protocol_handle != NULL) && (tvb_length_remaining(tvb, offset) > 0)) {
772         rrc_tvb = tvb_new_subset(tvb, offset, -1, tvb_length_remaining(tvb, offset));
773         call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree);
774     }
775 }
776
777
778 /* Dissect a PDCP LTE frame by first parsing the RLCPrim header then passing
779    the data to the PDCP LTE dissector */
780 static void dissect_pdcp_lte(tvbuff_t *tvb, gint offset,
781                              packet_info *pinfo, proto_tree *tree)
782 {
783     guint8                 opcode;
784     guint8                 tag;
785     struct pdcp_lte_info   *p_pdcp_lte_info = NULL;
786     tvbuff_t               *pdcp_lte_tvb;
787     guint16                ueid;
788
789     /* Look this up so can update channel info */
790     p_pdcp_lte_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
791     if (p_pdcp_lte_info == NULL) {
792         /* This really should be set...can't dissect anything without it */
793         return;
794     }
795
796     /* Top-level opcode */
797     opcode = tvb_get_guint8(tvb, offset);
798     if (tree) {
799         proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_op, tvb, offset, 1, FALSE);
800     }
801     offset++;
802
803     col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(opcode, rlc_op_vals, "Unknown"));
804
805     /* Assume UE side, so REQ is UL, IND is DL */
806     switch (opcode) {
807        case RLC_AM_DATA_REQ:
808        case RLC_UM_DATA_REQ:
809        case RLC_TR_DATA_REQ:
810            p_pdcp_lte_info->direction = DIRECTION_UPLINK;
811
812        default:
813            p_pdcp_lte_info->direction = DIRECTION_DOWNLINK;
814     }
815
816     /* Parse header */
817     switch (opcode) {
818         case RLC_AM_DATA_REQ:
819         case RLC_AM_DATA_IND:
820         case RLC_UM_DATA_REQ:
821         case RLC_UM_DATA_IND:
822         case RLC_TR_DATA_REQ:
823         case RLC_TR_DATA_IND:
824
825             /* Get next tag */
826             tag = tvb_get_guint8(tvb, offset++);
827             switch (tag) {
828                 case 0x10:    /* UE_Id_LCId */
829
830                     /* Dedicated channel info */
831
832                     /* Length will fit in one byte here */
833                     offset++;
834
835                     p_pdcp_lte_info->channelType = Channel_DCCH;
836
837                     /* UEId */
838                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid, tvb, offset, 2, FALSE);
839                     col_append_fstr(pinfo->cinfo, COL_INFO,
840                                     " UEId=%u", tvb_get_ntohs(tvb, offset));
841                     offset += 2;
842
843                     /* Get tag of channel type */
844                     tag = tvb_get_guint8(tvb, offset++);
845
846                     switch (tag) {
847                         case 0:
848                             offset++;
849                             col_append_fstr(pinfo->cinfo, COL_INFO, " SRB:%u",
850                                             tvb_get_guint8(tvb, offset));
851                             proto_tree_add_item(tree, hf_catapult_dct2000_lte_srbid,
852                                                 tvb, offset++, 1, FALSE);
853                             break;
854                         case 1:
855                             offset++;
856                             col_append_fstr(pinfo->cinfo, COL_INFO, " DRB:%u",
857                                             tvb_get_guint8(tvb, offset));
858                             proto_tree_add_item(tree, hf_catapult_dct2000_lte_drbid,
859                                                 tvb, offset++, 1, FALSE);
860                             break;
861
862                         default:
863                             /* Unexpected channel type */
864                             return;
865                     }
866                     break;
867
868                 case 0x1a:     /* Cell_LCId */
869
870                     /* Common channel info */
871
872                     /* Skip length */
873                     offset++;
874
875                     /* Cell-id */
876                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_cellid,
877                                         tvb, offset, 2, FALSE);
878                     offset += 2;
879
880                     /* Logical channel type */
881                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_channel_type,
882                                         tvb, offset, 1, FALSE);
883                     p_pdcp_lte_info->channelType = tvb_get_guint8(tvb, offset++);
884                     col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
885                                     val_to_str(p_pdcp_lte_info->channelType, rlc_logical_channel_vals,
886                                                "UNKNOWN-CHANNEL"));
887
888                     switch (p_pdcp_lte_info->channelType) {
889                         case Channel_BCCH:
890                             /* Skip length */
891                             offset++;
892
893                             /* Transport channel type */
894                             p_pdcp_lte_info->BCCHTransport = (LogicalChannelType)tvb_get_guint8(tvb, offset);
895                             proto_tree_add_item(tree, hf_catapult_dct2000_lte_bcch_transport,
896                                                 tvb, offset, 1, FALSE);
897                             offset++;
898                             break;
899
900                         case Channel_CCCH:
901                             /* Skip length */
902                             offset++;
903
904                             /* UEId */
905                             proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
906                                                 tvb, offset, 2, FALSE);
907                             ueid = tvb_get_ntohs(tvb, offset);
908                             offset += 2;
909
910                             col_append_fstr(pinfo->cinfo, COL_INFO, " UEId=%u", ueid);
911                             break;
912
913                         default:
914                             break;
915                     }
916                     break;
917
918                 default:
919                     /* Unexpected tag */
920                     return;
921             }
922
923             /* Other optional fields may follow */
924             tag = tvb_get_guint8(tvb, offset++);
925             while ((tag != 0x41) && (tvb_length_remaining(tvb, offset) > 2)) {
926
927                 if (tag == 0x35) {
928                     /* This is MUI */
929                     offset++;
930                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_mui,
931                                         tvb, offset, 2, FALSE);
932                     offset += 2;
933
934                     /* CNF follows MUI in AM */
935                     if ((opcode == RLC_AM_DATA_REQ) || (opcode == RLC_AM_DATA_IND)) {
936                         proto_tree_add_boolean(tree, hf_catapult_dct2000_lte_rlc_cnf,
937                                                tvb, offset, 1, tvb_get_guint8(tvb, offset));
938                         offset++;
939                     }
940                 }
941                 else if (tag == 0x45) {
942                     /* Discard Req */
943                     offset++;
944                     proto_tree_add_boolean(tree, hf_catapult_dct2000_lte_rlc_discard_req,
945                                            tvb, offset, 1, tvb_get_guint8(tvb, offset));
946                     offset++;
947                 }
948
949                 tag = tvb_get_guint8(tvb, offset++);
950             }
951
952
953             /********************************/
954             /* Should be at data tag now    */
955
956             /* Call PDCP LTE dissector */
957             pdcp_lte_tvb = tvb_new_subset(tvb, offset, -1, tvb_length_remaining(tvb, offset));
958             call_dissector_only(pdcp_lte_handle, pdcp_lte_tvb, pinfo, tree);
959
960             break;
961
962         default:
963             return;
964     }
965 }
966
967
968
969
970
971 /* Look up dissector by protocol name.  Fix up known name mis-matches.
972    This includes exact matches and prefixes (e.g. "diameter_rx" -> "diameter") */
973 static dissector_handle_t look_for_dissector(char *protocol_name)
974 {
975     /* Use known aliases and protocol name prefixes */
976     if (strcmp(protocol_name, "tbcp") == 0) {
977         return find_dissector("rtcp");
978     }
979     else
980     if (strncmp(protocol_name, "diameter", strlen("diameter")) == 0) {
981         return find_dissector("diameter");
982     }
983     else
984     if ((strcmp(protocol_name, "xcap_caps") == 0) ||
985         (strcmp(protocol_name, "soap") == 0) ||
986         (strcmp(protocol_name, "mm1") == 0) ||
987         (strcmp(protocol_name, "mm3") == 0) ||
988         (strcmp(protocol_name, "mm7") == 0)) {
989
990         return find_dissector("http");
991     }
992     else
993     if ((strcmp(protocol_name, "fp") == 0) ||
994         (strcmp(protocol_name, "fp_r4") == 0) ||
995         (strcmp(protocol_name, "fp_r5") == 0) ||
996         (strcmp(protocol_name, "fp_r6") == 0) ||
997         (strcmp(protocol_name, "fp_r7") == 0) ||
998         (strcmp(protocol_name, "fpiur_r5") == 0)) {
999
1000         return find_dissector("fp");
1001     }
1002     else
1003     if ((strcmp(protocol_name, "iuup_rtp_r5") == 0) ||
1004         (strcmp(protocol_name, "iuup_rtp_r6") == 0)) {
1005
1006         return find_dissector("rtp");
1007     }
1008     else
1009     if (strcmp(protocol_name, "sipt") == 0) {
1010         return find_dissector("sip");
1011     }
1012     else
1013     if (strncmp(protocol_name, "nbap_sctp", strlen("nbap_sctp")) == 0) {
1014         return find_dissector("nbap");
1015     }
1016     else
1017     if (strncmp(protocol_name, "gtp", strlen("gtp")) == 0) {
1018         return find_dissector("gtp");
1019     }
1020     else
1021     if (strcmp(protocol_name, "dhcpv4") == 0) {
1022         return find_dissector("bootp");
1023     }
1024     else
1025     if (strcmp(protocol_name, "wimax") == 0) {
1026         return find_dissector("wimaxasncp");
1027     }
1028     else
1029     if (strncmp(protocol_name, "sabp", strlen("sabp")) == 0) {
1030         return find_dissector("sabp");
1031     }
1032     else
1033     if (strcmp(protocol_name, "wtp") == 0) {
1034         return find_dissector("wtp-udp");
1035     }
1036     else
1037     /* Only match with s1ap if preference turned on */
1038     if (catapult_dct2000_dissect_lte_s1ap &&
1039         strncmp(protocol_name, "s1ap", strlen("s1ap")) == 0) {
1040
1041         return find_dissector("s1ap");
1042     }
1043     else
1044     if (strcmp(protocol_name, "gtpv2_r8_lte") == 0) {
1045         return find_dissector("gtpv2");
1046     }
1047
1048
1049     /* Try for an exact match */
1050     else {
1051         return find_dissector(protocol_name);
1052     }
1053 }
1054
1055
1056 /* Populate outhdr_values array with numbers found in outhdr_string */
1057 static void parse_outhdr_string(const guchar *outhdr_string)
1058 {
1059     int n = 0;
1060     guint outhdr_string_len = (guint)strlen((gchar*)outhdr_string);
1061
1062     /* Populate values array */
1063     for (outhdr_values_found=0; outhdr_values_found < MAX_OUTHDR_VALUES; ) {
1064         guint digits_start = n;
1065         guint digits;
1066
1067         /* Find digits */
1068         for (digits = 0; digits < outhdr_string_len; digits++, n++) {
1069             if (!isdigit(outhdr_string[n])) {
1070                 break;
1071             }
1072         }
1073
1074         if (digits == 0) {
1075             /* No more numbers left */
1076             break;
1077         }
1078
1079         /* Convert digits into value */
1080         outhdr_values[outhdr_values_found++] =
1081             atoi((char*)format_text((guchar*)outhdr_string+digits_start, digits));
1082
1083         /* Skip comma */
1084         n++;
1085     }
1086 }
1087
1088 /* Fill in an FP packet info struct and attach it to the packet for the FP
1089    dissector to use */
1090 void attach_fp_info(packet_info *pinfo, gboolean received, const char *protocol_name, int variant)
1091 {
1092     int  i=0;
1093     int  chan;
1094     int  tf_start, num_chans_start;
1095     gint node_type;
1096
1097     /* Only need to set info once per session. */
1098     struct fp_info *p_fp_info = p_get_proto_data(pinfo->fd, proto_fp);
1099     if (p_fp_info != NULL) {
1100         return;
1101     }
1102
1103     /* Allocate struct */
1104     p_fp_info = se_alloc0(sizeof(struct fp_info));
1105     if (!p_fp_info) {
1106         return;
1107     }
1108
1109     /* Check that the number of outhdr values looks sensible */
1110     if (((strcmp(protocol_name, "fpiur_r5") == 0) && (outhdr_values_found != 2)) ||
1111         (outhdr_values_found < 5)) {
1112
1113         return;
1114     }
1115
1116     /* 3gpp release (99, 4, 5, 6, 7) */
1117     if (strcmp(protocol_name, "fp") == 0) {
1118         p_fp_info->release = 99;
1119     }
1120     else if (strcmp(protocol_name, "fp_r4") == 0) {
1121         p_fp_info->release = 4;
1122     }
1123     else if (strcmp(protocol_name, "fp_r5") == 0) {
1124         p_fp_info->release = 5;
1125     }
1126     else if (strcmp(protocol_name, "fp_r6") == 0) {
1127         p_fp_info->release = 6;
1128     }
1129     else if (strcmp(protocol_name, "fp_r7") == 0) {
1130         p_fp_info->release = 7;
1131     }
1132     else if (strcmp(protocol_name, "fpiur_r5") == 0) {
1133         p_fp_info->release = 5;
1134     }
1135     else {
1136         /* Really shouldn't get here */
1137         DISSECTOR_ASSERT_NOT_REACHED();
1138         return;
1139     }
1140
1141     /* Release date is derived from variant number */
1142     /* Only R6 sub-versions currently influence format within a release */
1143     switch (p_fp_info->release) {
1144         case 6:
1145             switch (variant % 256) {
1146                 case 1:
1147                     p_fp_info->release_year = 2005;
1148                     p_fp_info->release_month = 6;
1149                     break;
1150                 case 2:
1151                     p_fp_info->release_year = 2005;
1152                     p_fp_info->release_month = 9;
1153                     break;
1154                 case 3:
1155                 default:
1156                     p_fp_info->release_year = 2006;
1157                     p_fp_info->release_month = 3;
1158                     break;
1159             }
1160             break;
1161         case 7:
1162             p_fp_info->release_year = 2008;
1163             p_fp_info->release_month = 3;
1164             break;
1165
1166         default:
1167             p_fp_info->release_year = 0;
1168             p_fp_info->release_month = 0;
1169     }
1170
1171
1172     /* Channel type */
1173     p_fp_info->channel = outhdr_values[i++];
1174
1175     /* Derive direction from node type/side */
1176     node_type = outhdr_values[i++];
1177     p_fp_info->is_uplink = (( received  && (node_type == 2)) ||
1178                             (!received  && (node_type == 1)));
1179
1180     /* Division type introduced for R7 */
1181     if (p_fp_info->release == 7) {
1182         p_fp_info->division = outhdr_values[i++];
1183     }
1184
1185     /* HS-DSCH config */
1186     if (p_fp_info->channel == CHANNEL_HSDSCH) {
1187         if (p_fp_info->release == 7) {
1188             /* Entity (MAC-hs or MAC-ehs) used */
1189             if (outhdr_values[i++]) {
1190                 p_fp_info->hsdsch_entity = ehs;
1191             }
1192         }
1193         else {
1194             /* This is the pre-R7 default */
1195             p_fp_info->hsdsch_entity = hs;
1196         }
1197     }
1198
1199
1200     /* IUR only uses the above... */
1201     if (strcmp(protocol_name, "fpiur_r5") == 0) {
1202         /* Store info in packet */
1203         p_fp_info->iface_type = IuR_Interface;
1204         p_add_proto_data(pinfo->fd, proto_fp, p_fp_info);
1205         return;
1206     }
1207
1208     /* DCH CRC present... */
1209     p_fp_info->dch_crc_present = outhdr_values[i++];
1210
1211     /* ... but don't trust for edch */
1212     if (p_fp_info->channel == CHANNEL_EDCH) {
1213         p_fp_info->dch_crc_present = 2; /* unknown */
1214     }
1215
1216     /* How many paging indications (if PCH data) */
1217     p_fp_info->paging_indications = outhdr_values[i++];
1218
1219     /* Number of channels (for coordinated channels) */
1220     p_fp_info->num_chans = outhdr_values[i++];
1221
1222     if (p_fp_info->channel != CHANNEL_EDCH) {
1223         /* TF size for each channel */
1224         tf_start = i;
1225         for (chan=0; chan < p_fp_info->num_chans; chan++) {
1226             p_fp_info->chan_tf_size[chan] = outhdr_values[tf_start+chan];
1227         }
1228
1229         /* Number of TBs for each channel */
1230         num_chans_start = tf_start + p_fp_info->num_chans;
1231         for (chan=0; chan < p_fp_info->num_chans; chan++) {
1232             p_fp_info->chan_num_tbs[chan] = outhdr_values[num_chans_start+chan];
1233         }
1234     }
1235     /* EDCH info */
1236     else {
1237         int n;
1238
1239         p_fp_info->no_ddi_entries = outhdr_values[i++];
1240
1241         /* DDI values */
1242         for (n=0; n < p_fp_info->no_ddi_entries; n++) {
1243             p_fp_info->edch_ddi[n] = outhdr_values[i++];
1244         }
1245
1246         /* Corresponding MAC-d sizes */
1247         for (n=0; n < p_fp_info->no_ddi_entries; n++) {
1248             p_fp_info->edch_macd_pdu_size[n] = outhdr_values[i++];
1249         }
1250     }
1251
1252     /* Interface must be IuB */
1253     p_fp_info->iface_type = IuB_Interface;
1254
1255     /* Store info in packet */
1256     p_add_proto_data(pinfo->fd, proto_fp, p_fp_info);
1257 }
1258
1259
1260 /* Fill in a MAC LTE packet info struct and attach it to the packet for that
1261    dissector to use */
1262 static void attach_mac_lte_info(packet_info *pinfo)
1263 {
1264     struct mac_lte_info *p_mac_lte_info;
1265     unsigned int i=0;
1266
1267     /* Only need to set info once per session. */
1268     p_mac_lte_info = p_get_proto_data(pinfo->fd, proto_mac_lte);
1269     if (p_mac_lte_info != NULL) {
1270         return;
1271     }
1272
1273     /* Allocate & zero struct */
1274     p_mac_lte_info = se_alloc0(sizeof(struct mac_lte_info));
1275     if (p_mac_lte_info == NULL) {
1276         return;
1277     }
1278
1279     /* Populate the struct from outhdr values */
1280     p_mac_lte_info->crcStatusValid = FALSE;
1281
1282     p_mac_lte_info->radioType = outhdr_values[i++];
1283     p_mac_lte_info->rntiType = outhdr_values[i++];
1284     p_mac_lte_info->direction = outhdr_values[i++];
1285     p_mac_lte_info->subframeNumber = outhdr_values[i++];
1286     p_mac_lte_info->isPredefinedData = outhdr_values[i++];
1287     p_mac_lte_info->rnti = outhdr_values[i++];
1288     p_mac_lte_info->ueid = outhdr_values[i++];
1289     p_mac_lte_info->length = outhdr_values[i++];
1290     if (outhdr_values_found > 8) {
1291         p_mac_lte_info->reTxCount = outhdr_values[i++];
1292     }
1293     if (outhdr_values_found > 9) {
1294         /* CRC only valid for Downlink */
1295         if (p_mac_lte_info->direction == DIRECTION_DOWNLINK) {
1296             p_mac_lte_info->crcStatusValid = TRUE;
1297             p_mac_lte_info->crcStatus = outhdr_values[i++];
1298         }
1299         else {
1300             i++;
1301         }
1302     }
1303
1304     /* Store info in packet */
1305     p_add_proto_data(pinfo->fd, proto_mac_lte, p_mac_lte_info);
1306 }
1307
1308
1309 /* Fill in a RLC LTE packet info struct and attach it to the packet for that
1310    dissector to use */
1311 static void attach_rlc_lte_info(packet_info *pinfo)
1312 {
1313     struct rlc_lte_info *p_rlc_lte_info;
1314     unsigned int i=0;
1315
1316     /* Only need to set info once per session. */
1317     p_rlc_lte_info = p_get_proto_data(pinfo->fd, proto_rlc_lte);
1318     if (p_rlc_lte_info != NULL) {
1319         return;
1320     }
1321
1322     /* Allocate & zero struct */
1323     p_rlc_lte_info = se_alloc0(sizeof(struct rlc_lte_info));
1324     if (p_rlc_lte_info == NULL) {
1325         return;
1326     }
1327
1328     p_rlc_lte_info->rlcMode = outhdr_values[i++];
1329     p_rlc_lte_info->direction = outhdr_values[i++];
1330     p_rlc_lte_info->priority = outhdr_values[i++];
1331     p_rlc_lte_info->UMSequenceNumberLength = outhdr_values[i++];
1332     p_rlc_lte_info->channelId = outhdr_values[i++];
1333     p_rlc_lte_info->channelType = outhdr_values[i++];
1334     p_rlc_lte_info->ueid = outhdr_values[i++];
1335     p_rlc_lte_info->pduLength = outhdr_values[i++];
1336
1337     /* Store info in packet */
1338     p_add_proto_data(pinfo->fd, proto_rlc_lte, p_rlc_lte_info);
1339 }
1340
1341 /* Fill in a PDCP LTE packet info struct and attach it to the packet for the PDCP LTE
1342    dissector to use */
1343 static void attach_pdcp_lte_info(packet_info *pinfo)
1344 {
1345     struct pdcp_lte_info *p_pdcp_lte_info;
1346     unsigned int i=0;
1347
1348     /* Only need to set info once per session. */
1349     p_pdcp_lte_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
1350     if (p_pdcp_lte_info != NULL) {
1351         return;
1352     }
1353
1354     /* Allocate & zero struct */
1355     p_pdcp_lte_info = se_alloc0(sizeof(struct pdcp_lte_info));
1356     if (p_pdcp_lte_info == NULL) {
1357         return;
1358     }
1359
1360     p_pdcp_lte_info->no_header_pdu = outhdr_values[i++];
1361     p_pdcp_lte_info->plane = outhdr_values[i++];
1362     if (p_pdcp_lte_info->plane != USER_PLANE) {
1363         p_pdcp_lte_info->plane = SIGNALING_PLANE;
1364     }
1365     p_pdcp_lte_info->seqnum_length = outhdr_values[i++];
1366
1367     p_pdcp_lte_info->rohc_compression = outhdr_values[i++];
1368     p_pdcp_lte_info->rohc_ip_version = outhdr_values[i++];
1369     p_pdcp_lte_info->cid_inclusion_info = outhdr_values[i++];
1370     p_pdcp_lte_info->large_cid_present = outhdr_values[i++];
1371     p_pdcp_lte_info->mode = outhdr_values[i++];
1372     p_pdcp_lte_info->rnd = outhdr_values[i++];
1373     p_pdcp_lte_info->udp_checkum_present = outhdr_values[i++];
1374     p_pdcp_lte_info->profile = outhdr_values[i++];
1375
1376     /* Store info in packet */
1377     p_add_proto_data(pinfo->fd, proto_pdcp_lte, p_pdcp_lte_info);
1378 }
1379
1380
1381 /* Attempt to show tty (raw character messages) as text lines. */
1382 static void dissect_tty_lines(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
1383 {
1384     gint        next_offset;
1385     proto_tree  *tty_tree;
1386     proto_item  *ti;
1387     int         lines = 0;
1388
1389     /* Create tty tree. */
1390     ti = proto_tree_add_item(tree, hf_catapult_dct2000_tty, tvb, offset, -1, FALSE);
1391     tty_tree = proto_item_add_subtree(ti, ett_catapult_dct2000);
1392
1393     /* Show the tty lines one at a time. */
1394     while (tvb_reported_length_remaining(tvb, offset) > 0) {
1395         /* Find the end of the line. */
1396         int linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
1397
1398         /* Extract & add the string. */
1399         char *string = (char*)tvb_get_ephemeral_string(tvb, offset, linelen);
1400         proto_tree_add_string_format(tty_tree, hf_catapult_dct2000_tty_line,
1401                                      tvb, offset,
1402                                      linelen, string,
1403                                      "%s", string);
1404         lines++;
1405
1406         /* Show first line in info column */
1407         if (lines == 1) {
1408             col_append_fstr(pinfo->cinfo, COL_INFO, "tty (%s", string);
1409         }
1410
1411         /* Move onto next line. */
1412         offset = next_offset;
1413     }
1414
1415     /* Close off summary of tty message in info column */
1416     if (lines != 0) {
1417         col_append_str(pinfo->cinfo, COL_INFO, (lines > 1) ? "...)" : ")");
1418     }
1419 }
1420
1421
1422 /* Scan the log comment looking for notable out-of-band MAC events that should
1423    be sent to the MAC dissector */
1424 static void check_for_oob_mac_lte_events(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
1425                                          const char *string)
1426 {
1427     guint ueid;
1428     guint rnti;
1429     guint rapid;
1430     guint rach_attempt_number;
1431     mac_lte_oob_event oob_event;
1432     struct mac_lte_info *p_mac_lte_info;
1433     tvbuff_t *mac_lte_tvb = NULL;
1434
1435     /* Look for strings matching expected formats */
1436     if (sscanf(string, ">> RACH Preamble Request[UE =  %u]    [RAPID =  %u]    [Attempt = %u]",
1437                &ueid, &rapid, &rach_attempt_number) == 3) {
1438         oob_event = ltemac_send_preamble;
1439     }
1440     else
1441     if (sscanf(string, ">> Schedule Request[UE =  %u] [RNTI = %u]", &ueid, &rnti) == 2) {
1442         oob_event = ltemac_send_sr;
1443     }
1444     else
1445     if (sscanf(string, ">> INFO MAC:    ProcessSRInd - CRNTI=%u", &rnti) == 1) {
1446         oob_event = ltemac_sr_failure;
1447     }
1448     else {
1449         /* No events found */
1450         return;
1451     }
1452
1453     /* We have an event */
1454     /* Only need to set info once per session. */
1455     p_mac_lte_info = p_get_proto_data(pinfo->fd, proto_mac_lte);
1456     if (p_mac_lte_info == NULL) {
1457
1458         /* Allocate & zero struct */
1459         p_mac_lte_info = se_alloc0(sizeof(struct mac_lte_info));
1460         if (p_mac_lte_info == NULL) {
1461             return;
1462         }
1463
1464         /* This indicates to MAC dissector that it has an oob event */
1465         p_mac_lte_info->length = 0;
1466
1467         switch (oob_event) {
1468             case ltemac_send_preamble:
1469                 p_mac_lte_info->ueid = ueid;
1470                 p_mac_lte_info->rapid = rapid;
1471                 p_mac_lte_info->rach_attempt_number = rach_attempt_number;
1472                 p_mac_lte_info->direction = DIRECTION_UPLINK;
1473                 break;
1474             case ltemac_send_sr:
1475                 p_mac_lte_info->ueid = ueid;
1476                 p_mac_lte_info->rnti = rnti;
1477                 p_mac_lte_info->direction = DIRECTION_UPLINK;
1478                 break;
1479             case ltemac_sr_failure:
1480                 p_mac_lte_info->rnti = rnti;
1481                 p_mac_lte_info->direction = DIRECTION_DOWNLINK;
1482                 break;
1483         }
1484
1485         p_mac_lte_info->radioType = FDD_RADIO;
1486         p_mac_lte_info->oob_event = oob_event;
1487
1488         /* Store info in packet */
1489         p_add_proto_data(pinfo->fd, proto_mac_lte, p_mac_lte_info);
1490     }
1491
1492     /* Call MAC dissector */
1493     mac_lte_tvb = tvb_new_subset(tvb, 0, 0, 0);
1494     call_dissector_only(mac_lte_handle, mac_lte_tvb, pinfo, tree);
1495 }
1496
1497
1498 /*****************************************/
1499 /* Main dissection function.             */
1500 /*****************************************/
1501 static void
1502 dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1503 {
1504     proto_tree  *dct2000_tree = NULL;
1505     proto_item  *ti = NULL;
1506     gint        offset = 0;
1507     gint        context_length;
1508     guint8      port_number;
1509     gint        protocol_start;
1510     gint        protocol_length;
1511     gint        timestamp_start;
1512     gint        timestamp_length;
1513     gint        variant_start;
1514     gint        variant_length;
1515     gint        outhdr_start;
1516     gint        outhdr_length;
1517     guint8      direction;
1518     tvbuff_t    *next_tvb;
1519     int         encap;
1520     dissector_handle_t protocol_handle = 0;
1521     dissector_handle_t heur_protocol_handle = 0;
1522     int sub_dissector_result = 0;
1523     char        *protocol_name;
1524     gboolean    is_comment;
1525
1526     /* Set Protocol */
1527     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCT2000");
1528
1529     /* Clear Info */
1530     col_clear(pinfo->cinfo, COL_INFO);
1531
1532     /* Create root (protocol) tree. */
1533     if (tree) {
1534         ti = proto_tree_add_item(tree, proto_catapult_dct2000, tvb, offset, -1, FALSE);
1535         dct2000_tree = proto_item_add_subtree(ti, ett_catapult_dct2000);
1536     }
1537
1538     /*********************************************************************/
1539     /* Note that these are the fields of the stub header as written out  */
1540     /* by the wiretap module                                             */
1541
1542     /* Context Name */
1543     context_length = tvb_strsize(tvb, offset);
1544     if (dct2000_tree) {
1545         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_context, tvb,
1546                             offset, context_length, FALSE);
1547     }
1548     offset += context_length;
1549
1550     /* Context port number */
1551     port_number = tvb_get_guint8(tvb, offset);
1552     if (dct2000_tree) {
1553         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_port_number, tvb,
1554                             offset, 1, FALSE);
1555     }
1556     offset++;
1557
1558     /* Timestamp in file */
1559     timestamp_start = offset;
1560     timestamp_length = tvb_strsize(tvb, offset);
1561     if (dct2000_tree) {
1562         /* TODO: this is *very* slow, but float version adds trailing digits when
1563                  displayed as a custom column... */
1564         proto_tree_add_double(dct2000_tree, hf_catapult_dct2000_timestamp, tvb,
1565                               offset, timestamp_length,
1566                               atof(tvb_get_ptr(tvb, offset, timestamp_length)));
1567     }
1568     offset += timestamp_length;
1569
1570
1571     /* DCT2000 protocol name */
1572     protocol_start = offset;
1573     protocol_length = tvb_strsize(tvb, offset);
1574     if (dct2000_tree) {
1575         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_protocol, tvb,
1576                             offset, protocol_length, FALSE);
1577     }
1578     protocol_name = (char*)tvb_get_ptr(tvb, protocol_start, protocol_length);
1579     is_comment = (strcmp(protocol_name, "comment") == 0);
1580     offset += protocol_length;
1581
1582
1583     /* Protocol Variant */
1584     variant_start = offset;
1585     variant_length = tvb_strsize(tvb, offset);
1586     if (!is_comment) {
1587         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_variant, tvb,
1588                             offset, variant_length, FALSE);
1589     }
1590     offset += variant_length;
1591
1592     /* Outhdr (shown as string) */
1593     outhdr_start = offset;
1594     outhdr_length = tvb_strsize(tvb, offset);
1595     if (!is_comment && (outhdr_length > 1)) {
1596         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_outhdr, tvb,
1597                             offset, outhdr_length, FALSE);
1598     }
1599     offset += outhdr_length;
1600
1601
1602     /* Direction */
1603     direction = tvb_get_guint8(tvb, offset);
1604     if (dct2000_tree) {
1605         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_direction, tvb,
1606                             offset, 1, FALSE);
1607     }
1608     offset++;
1609
1610     /* Read frame encapsulation set by wiretap */
1611     if (!is_comment) {
1612         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_encap, tvb, offset, 1, FALSE);
1613     }
1614     encap = tvb_get_guint8(tvb, offset);
1615     offset++;
1616
1617     /* Set selection length of dct2000 tree */
1618     proto_item_set_len(dct2000_tree, offset);
1619
1620     /* Add useful details to protocol tree label */
1621     proto_item_append_text(ti, "   context=%s.%u   t=%s   %c   prot=%s (v=%s)",
1622                            tvb_get_ptr(tvb, 0, context_length),
1623                            port_number,
1624                            tvb_get_ptr(tvb, timestamp_start, timestamp_length),
1625                            (direction == 0) ? 'S' : 'R',
1626                            protocol_name,
1627                            tvb_get_ptr(tvb, variant_start, variant_length));
1628
1629
1630
1631     /* FP protocols need info from outhdr attached */
1632     if ((strcmp(protocol_name, "fp") == 0) ||
1633         (strcmp(protocol_name, "fp_r4") == 0) ||
1634         (strcmp(protocol_name, "fp_r5") == 0) ||
1635         (strcmp(protocol_name, "fp_r6") == 0) ||
1636         (strcmp(protocol_name, "fp_r7") == 0) ||
1637         (strcmp(protocol_name, "fpiur_r5") == 0)) {
1638
1639         parse_outhdr_string(tvb_get_ptr(tvb, outhdr_start, outhdr_length));
1640         attach_fp_info(pinfo, direction, protocol_name,
1641                        atoi((char*)tvb_get_ptr(tvb, variant_start, variant_length)));
1642     }
1643
1644     /* LTE MAC needs info attached */
1645     else if (strcmp(protocol_name, "mac_r8_lte") == 0) {
1646         parse_outhdr_string(tvb_get_ptr(tvb, outhdr_start, outhdr_length));
1647         attach_mac_lte_info(pinfo);
1648     }
1649
1650     /* LTE RLC needs info attached */
1651     else if (strcmp(protocol_name, "rlc_r8_lte") == 0) {
1652         parse_outhdr_string(tvb_get_ptr(tvb, outhdr_start, outhdr_length));
1653         attach_rlc_lte_info(pinfo);
1654     }
1655
1656     /* LTE PDCP needs info attached */
1657     else if (strcmp(protocol_name, "pdcp_r8_lte") == 0) {
1658         parse_outhdr_string(tvb_get_ptr(tvb, outhdr_start, outhdr_length));
1659         attach_pdcp_lte_info(pinfo);
1660     }
1661
1662
1663     /* Note that the first item of pinfo->pseudo_header->dct2000 will contain
1664        the pseudo-header needed (in some cases) by the Wireshark dissector that
1665        this packet data will be handed off to. */
1666
1667
1668     /***********************************************************************/
1669     /* Now hand off to the dissector of intended packet encapsulation type */
1670
1671     /* Get protocol handle, and set p2p_dir where necessary.
1672        (packet-frame.c won't copy it from pseudo-header because it doesn't
1673         know about Catapult DCT2000 encap type...)
1674     */
1675     switch (encap) {
1676         case WTAP_ENCAP_RAW_IP:
1677             protocol_handle = find_dissector("ip");
1678             break;
1679         case WTAP_ENCAP_ETHERNET:
1680             protocol_handle = find_dissector("eth_withoutfcs");
1681             break;
1682         case WTAP_ENCAP_ISDN:
1683             protocol_handle = find_dissector("lapd");
1684             pinfo->p2p_dir = pinfo->pseudo_header->isdn.uton;
1685             break;
1686         case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED:
1687             protocol_handle = find_dissector("atm_untruncated");
1688             break;
1689         case WTAP_ENCAP_PPP:
1690             protocol_handle = find_dissector("ppp_hdlc");
1691             pinfo->p2p_dir = pinfo->pseudo_header->p2p.sent;
1692             break;
1693         case DCT2000_ENCAP_SSCOP:
1694             protocol_handle = find_dissector("sscop");
1695             break;
1696         case WTAP_ENCAP_FRELAY:
1697             protocol_handle = find_dissector("fr");
1698             break;
1699         case DCT2000_ENCAP_MTP2:
1700             protocol_handle = find_dissector("mtp2");
1701             break;
1702         case DCT2000_ENCAP_NBAP:
1703             protocol_handle = find_dissector("nbap");
1704             break;
1705
1706         case DCT2000_ENCAP_UNHANDLED:
1707             /**********************************************************/
1708             /* The wiretap module wasn't able to set an encapsulation */
1709             /* type, but it may still be possible to dissect the data */
1710             /* if we know about the protocol or if we can recognise   */
1711             /* and parse or skip a primitive header                   */
1712             /**********************************************************/
1713
1714             /* Show context.port in src or dest column as appropriate */
1715             if (direction == 0) {
1716                 col_add_fstr(pinfo->cinfo, COL_DEF_SRC,
1717                              "%s.%u",
1718                              tvb_get_ptr(tvb, 0, context_length),
1719                              port_number);
1720             }
1721             else
1722             if (direction == 1) {
1723                 col_add_fstr(pinfo->cinfo, COL_DEF_DST,
1724                              "%s.%u",
1725                              tvb_get_ptr(tvb, 0, context_length),
1726                              port_number);
1727             }
1728
1729
1730             /**************************************************************************/
1731             /* These protocols have no encapsulation type, just look them up directly */
1732             if (strcmp(protocol_name, "mac_r8_lte") == 0) {
1733                 protocol_handle = mac_lte_handle;
1734             }
1735
1736             else
1737             if (strcmp(protocol_name, "rlc_r8_lte") == 0) {
1738                 protocol_handle = rlc_lte_handle;
1739             }
1740
1741             else
1742             if (strcmp(protocol_name, "pdcp_r8_lte") == 0) {
1743                 /* Dissect proprietary header, then pass remainder to PDCP */
1744                 dissect_pdcp_lte(tvb, offset, pinfo, tree);
1745                 return;
1746             }
1747
1748
1749             /* Work with generic XML protocol. */
1750             else
1751             if (strcmp(protocol_name, "xml") == 0) {
1752                 protocol_handle = find_dissector("xml");
1753             }
1754
1755
1756             /* Attempt to show tty messages as raw text */
1757             else
1758             if (strcmp(protocol_name, "tty") == 0) {
1759                 dissect_tty_lines(tvb, pinfo, dct2000_tree, offset);
1760                 return;
1761             }
1762
1763             else
1764             if (strcmp(protocol_name, "sipprim") == 0) {
1765                 protocol_handle = find_dissector("sipprim");
1766             }
1767
1768             else
1769             if (strcmp(protocol_name, "comment") == 0) {
1770                 /* Extract & add the string. */
1771                 proto_item *string_ti;
1772                 char *string = (char*)tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
1773
1774                 /* Show comment string */
1775                 string_ti = proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_comment, tvb,
1776                                                 offset, -1, FALSE);
1777                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s", string);
1778
1779                 if (catapult_dct2000_dissect_mac_lte_oob_messages) {
1780                     /* Look into string for out-of-band MAC events, such as SRReq, SRInd */
1781                     check_for_oob_mac_lte_events(pinfo, tvb, tree, string);
1782                 }
1783
1784                 /* Look for and flag generic error messages */
1785                 if (strncmp(string, ">> ERR", 6) == 0) {
1786                     expert_add_info_format(pinfo, string_ti, PI_SEQUENCE, PI_ERROR,
1787                                           "%s", string);
1788                 }
1789                 return;
1790             }
1791
1792
1793             else
1794             if (catapult_dct2000_dissect_lte_rrc &&
1795                 ((strcmp(protocol_name, "rrc_r8_lte") == 0) ||
1796                  (strcmp(protocol_name, "rrcpdcpprim_r8_lte") == 0))) {
1797
1798                 /* Dissect proprietary header, then pass remainder
1799                    to RRC (depending upon direction and channel type) */
1800                 dissect_rrc_lte(tvb, offset, pinfo, tree);
1801                 return;
1802             }
1803
1804
1805             /* Many DCT2000 protocols have at least one IPPrim variant. If the
1806                protocol name can be matched to a dissector, try to find the
1807                UDP/TCP data inside and dissect it.
1808             */
1809
1810             if (!protocol_handle && catapult_dct2000_try_ipprim_heuristic) {
1811                 guint32      source_addr_offset = 0, dest_addr_offset = 0;
1812                 guint8       source_addr_length = 0, dest_addr_length = 0;
1813                 guint32      source_port_offset = 0, dest_port_offset = 0;
1814                 port_type    type_of_port = PT_NONE;
1815                 guint16      conn_id_offset = 0;
1816                 int          offset_before_ipprim_header = offset;
1817
1818                 /* Will give up if couldn't match protocol anyway... */
1819                 heur_protocol_handle = look_for_dissector(protocol_name);
1820                 if ((heur_protocol_handle != 0) &&
1821                     find_ipprim_data_offset(tvb, &offset, direction,
1822                                             &source_addr_offset, &source_addr_length,
1823                                             &dest_addr_offset, &dest_addr_length,
1824                                             &source_port_offset, &dest_port_offset,
1825                                             &type_of_port,
1826                                             &conn_id_offset)) {
1827
1828                     proto_tree *ipprim_tree;
1829                     proto_item *ipprim_ti;
1830
1831                     /* Will use this dissector then. */
1832                     protocol_handle = heur_protocol_handle;
1833
1834                     /* Add address parameters to tree */
1835                     /* Unfortunately can't automatically create a conversation filter for this...
1836                        I *could* create a fake IP header from these details, but then it would be tricky
1837                        to get the FP dissector called as it has no well-known ports or heuristics... */
1838                     ipprim_ti =  proto_tree_add_string_format(dct2000_tree, hf_catapult_dct2000_ipprim_addresses,
1839                                                        tvb, offset_before_ipprim_header, 0,
1840                                                        "", "IPPrim transport (%s): %s:%u -> %s:%u",
1841                                                        (type_of_port == PT_UDP) ? "UDP" : "TCP",
1842                                                        (source_addr_offset) ?
1843                                                            ((source_addr_length == 4) ?
1844                                                               (char *)get_hostname(tvb_get_ipv4(tvb, source_addr_offset)) :
1845                                                               "<ipv6-address>"
1846                                                             ) :
1847                                                            "0.0.0.0",
1848                                                        (source_port_offset) ?
1849                                                            tvb_get_ntohs(tvb, source_port_offset) :
1850                                                            0,
1851                                                        (dest_addr_offset) ?
1852                                                          ((source_addr_length == 4) ?
1853                                                               (char *)get_hostname(tvb_get_ipv4(tvb, dest_addr_offset)) :
1854                                                               "<ipv6-address>"
1855                                                             ) :
1856                                                            "0.0.0.0",
1857                                                        (dest_port_offset) ?
1858                                                            tvb_get_ntohs(tvb, dest_port_offset) :
1859                                                            0);
1860                     if ((type_of_port == PT_TCP) && (conn_id_offset != 0)) {
1861                         proto_item_append_text(ipprim_ti, " (conn_id=%u)", tvb_get_ntohs(tvb, conn_id_offset));
1862                     }
1863
1864                     /* Add these IPPRIM fields inside an IPPRIM subtree */
1865                     ipprim_tree = proto_item_add_subtree(ipprim_ti, ett_catapult_dct2000_ipprim);
1866
1867                     /* Try to add right stuff to pinfo so conversation stuff works... */
1868                     pinfo->ptype = type_of_port;
1869                     switch (type_of_port) {
1870                         case PT_UDP:
1871                             pinfo->ipproto = IP_PROTO_UDP;
1872                             break;
1873                         case PT_TCP:
1874                             pinfo->ipproto = IP_PROTO_TCP;
1875                             break;
1876                         default:
1877                             pinfo->ipproto = IP_PROTO_NONE;
1878                     }
1879
1880                     /* Add addresses & ports into ipprim tree.
1881                        Also set address info in pinfo for conversations... */
1882                     if (source_addr_offset != 0) {
1883                         proto_item *addr_ti;
1884
1885                         SET_ADDRESS(&pinfo->net_src,
1886                                     (source_addr_length == 4) ? AT_IPv4 : AT_IPv6,
1887                                     source_addr_length,
1888                                     (tvb_get_ptr(tvb, source_addr_offset, source_addr_length)));
1889                         SET_ADDRESS(&pinfo->src,
1890                                     (source_addr_length == 4) ? AT_IPv4 : AT_IPv6,
1891                                     source_addr_length,
1892                                     (tvb_get_ptr(tvb, source_addr_offset, source_addr_length)));
1893
1894                         proto_tree_add_item(ipprim_tree,
1895                                             (source_addr_length == 4) ? 
1896                                                 hf_catapult_dct2000_ipprim_src_addr_v4 :
1897                                                 hf_catapult_dct2000_ipprim_src_addr_v6,
1898                                             tvb, source_addr_offset, source_addr_length, FALSE);
1899
1900                         /* Add hidden item for "side-less" addr */
1901                         addr_ti = proto_tree_add_item(ipprim_tree,
1902                                                       (source_addr_length == 4) ?
1903                                                           hf_catapult_dct2000_ipprim_addr_v4 :
1904                                                           hf_catapult_dct2000_ipprim_addr_v6,
1905                                                       tvb, source_addr_offset,
1906                                                       source_addr_length, FALSE);
1907                         PROTO_ITEM_SET_HIDDEN(addr_ti);
1908                     }
1909                     if (source_port_offset != 0) {
1910                         proto_item *port_ti;
1911
1912                         pinfo->srcport = tvb_get_ntohs(tvb, source_port_offset);
1913
1914                         proto_tree_add_item(ipprim_tree,
1915                                             (type_of_port == PT_UDP) ?
1916                                                hf_catapult_dct2000_ipprim_udp_src_port :
1917                                                hf_catapult_dct2000_ipprim_tcp_src_port,
1918                                             tvb, source_port_offset, 2, FALSE);
1919                         port_ti = proto_tree_add_item(ipprim_tree,
1920                                                       (type_of_port == PT_UDP) ?
1921                                                           hf_catapult_dct2000_ipprim_udp_port :
1922                                                           hf_catapult_dct2000_ipprim_tcp_port,
1923                                                       tvb, source_port_offset, 2, FALSE);
1924                         PROTO_ITEM_SET_HIDDEN(port_ti);
1925                     }
1926                     if (dest_addr_offset != 0) {
1927                         proto_item *addr_ti;
1928
1929                         SET_ADDRESS(&pinfo->net_dst,
1930                                     (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
1931                                     dest_addr_length,
1932                                     (tvb_get_ptr(tvb, dest_addr_offset, dest_addr_length)));
1933                         SET_ADDRESS(&pinfo->dst,
1934                                     (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
1935                                     dest_addr_length,
1936                                     (tvb_get_ptr(tvb, dest_addr_offset, dest_addr_length)));
1937                         proto_tree_add_item(ipprim_tree,
1938                                             (dest_addr_length == 4) ? 
1939                                                 hf_catapult_dct2000_ipprim_dst_addr_v4 :
1940                                                 hf_catapult_dct2000_ipprim_dst_addr_v6,
1941                                             tvb, dest_addr_offset, dest_addr_length, FALSE);
1942
1943                         /* Add hidden item for "side-less" addr */
1944                         addr_ti = proto_tree_add_item(ipprim_tree,
1945                                                       (dest_addr_length == 4) ? 
1946                                                           hf_catapult_dct2000_ipprim_addr_v4 :
1947                                                           hf_catapult_dct2000_ipprim_addr_v6,
1948                                                       tvb, dest_addr_offset, dest_addr_length, FALSE);
1949                         PROTO_ITEM_SET_HIDDEN(addr_ti);
1950                     }
1951                     if (dest_port_offset != 0) {
1952                         proto_item *port_ti;
1953
1954                         pinfo->destport = tvb_get_ntohs(tvb, dest_port_offset);
1955
1956                         proto_tree_add_item(ipprim_tree,
1957                                             (type_of_port == PT_UDP) ?
1958                                                hf_catapult_dct2000_ipprim_udp_dst_port :
1959                                                hf_catapult_dct2000_ipprim_tcp_dst_port,
1960                                             tvb, dest_port_offset, 2, FALSE);
1961                         port_ti = proto_tree_add_item(ipprim_tree,
1962                                                       (type_of_port == PT_UDP) ?
1963                                                           hf_catapult_dct2000_ipprim_udp_port :
1964                                                           hf_catapult_dct2000_ipprim_tcp_port,
1965                                                       tvb, dest_port_offset, 2, FALSE);
1966                         PROTO_ITEM_SET_HIDDEN(port_ti);
1967                     }
1968                     if (conn_id_offset != 0) {
1969                         proto_tree_add_item(ipprim_tree,
1970                                             hf_catapult_dct2000_ipprim_conn_id,
1971                                             tvb, conn_id_offset, 2, FALSE);
1972                     }
1973
1974
1975                     /* Set source and dest columns now (will be overwriiten if
1976                        src and dst IP addresses set) */
1977                     if (source_addr_offset) {
1978                         col_append_fstr(pinfo->cinfo, COL_DEF_SRC,
1979                                         "(%s:%u)",
1980                                         (char*)get_hostname(tvb_get_ipv4(tvb, source_addr_offset)),
1981                                         tvb_get_ntohs(tvb, source_port_offset));
1982                     }
1983                     if (dest_addr_offset) {
1984                         col_append_fstr(pinfo->cinfo, COL_DEF_DST,
1985                                         "(%s:%u)",
1986                                         (char*)get_hostname(tvb_get_ipv4(tvb, dest_addr_offset)),
1987                                         tvb_get_ntohs(tvb, dest_port_offset));
1988                     }
1989
1990                     /* Set length for IPPrim tree */
1991                     proto_item_set_len(ipprim_tree, offset - offset_before_ipprim_header);
1992                 }
1993             }
1994
1995
1996             /* Try SCTP Prim heuristic if configured to */
1997             if (!protocol_handle && catapult_dct2000_try_sctpprim_heuristic) {
1998                 guint32      dest_addr_offset = 0;
1999                 guint16      dest_addr_length = 0;
2000                 guint32      dest_port_offset = 0;
2001                 int          offset_before_sctpprim_header = offset;
2002
2003                 heur_protocol_handle = look_for_dissector(protocol_name);
2004                 if ((heur_protocol_handle != 0) &&
2005                     (find_sctpprim_variant1_data_offset(tvb, &offset,
2006                                                         &dest_addr_offset,
2007                                                         &dest_addr_length,
2008                                                         &dest_port_offset) ||
2009                      find_sctpprim_variant3_data_offset(tvb, &offset,
2010                                                         &dest_addr_offset,
2011                                                         &dest_addr_length,
2012                                                         &dest_port_offset))) {
2013
2014                     proto_tree *sctpprim_tree;
2015                     proto_item *ti_local;
2016
2017                     /* Will use this dissector then. */
2018                     protocol_handle = heur_protocol_handle;
2019
2020                     ti_local =  proto_tree_add_string_format(dct2000_tree, hf_catapult_dct2000_sctpprim_addresses,
2021                                                        tvb, offset_before_sctpprim_header, 0,
2022                                                        "", "SCTPPrim transport:  -> %s:%u",
2023                                                        (dest_addr_offset) ?
2024                                                          ((dest_addr_length == 4) ?
2025                                                               (char *)get_hostname(tvb_get_ipv4(tvb, dest_addr_offset)) :
2026                                                               "<ipv6-address>"
2027                                                             ) :
2028                                                            "0.0.0.0",
2029                                                        (dest_port_offset) ?
2030                                                          tvb_get_ntohs(tvb, dest_port_offset) :
2031                                                          0);
2032
2033                     /* Add these SCTPPRIM fields inside an SCTPPRIM subtree */
2034                     sctpprim_tree = proto_item_add_subtree(ti_local, ett_catapult_dct2000_sctpprim);
2035
2036                     pinfo->ipproto = IP_PROTO_SCTP;
2037
2038                     /* Destination address */
2039                     if (dest_addr_offset != 0) {
2040                         proto_item *addr_ti;
2041
2042                         SET_ADDRESS(&pinfo->net_dst,
2043                                     (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2044                                     dest_addr_length,
2045                                     (tvb_get_ptr(tvb, dest_addr_offset, dest_addr_length)));
2046                         SET_ADDRESS(&pinfo->dst,
2047                                     (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2048                                     dest_addr_length,
2049                                     (tvb_get_ptr(tvb, dest_addr_offset, dest_addr_length)));
2050                         proto_tree_add_item(sctpprim_tree,
2051                                             (dest_addr_length == 4) ? 
2052                                                 hf_catapult_dct2000_sctpprim_dst_addr_v4 :
2053                                                 hf_catapult_dct2000_sctpprim_dst_addr_v6,
2054                                             tvb, dest_addr_offset, dest_addr_length, FALSE);
2055
2056                         /* Add hidden item for "side-less" addr */
2057                         addr_ti = proto_tree_add_item(sctpprim_tree,
2058                                                       (dest_addr_length == 4) ? 
2059                                                           hf_catapult_dct2000_sctpprim_addr_v4 :
2060                                                           hf_catapult_dct2000_sctpprim_addr_v6,
2061                                                       tvb, dest_addr_offset, dest_addr_length, FALSE);
2062                         PROTO_ITEM_SET_HIDDEN(addr_ti);
2063                     }
2064
2065                     if (dest_port_offset != 0) {
2066                         pinfo->destport = tvb_get_ntohs(tvb, dest_port_offset);
2067
2068                         proto_tree_add_item(sctpprim_tree,
2069                                             hf_catapult_dct2000_sctpprim_dst_port,
2070                                             tvb, dest_port_offset, 2, FALSE);
2071                     }
2072
2073                     /* Set length for SCTPPrim tree */
2074                     proto_item_set_len(sctpprim_tree, offset - offset_before_sctpprim_header);
2075                 }
2076             }
2077
2078             break;
2079
2080         default:
2081             /* !! If get here, there is a mismatch between
2082                this dissector and the wiretap module catapult_dct2000.c !!
2083             */
2084             DISSECTOR_ASSERT_NOT_REACHED();
2085             return;
2086     }
2087
2088
2089     /* Try appropriate dissector, if one has been selected */
2090     if (protocol_handle != 0) {
2091         /* Dissect the remainder of the frame using chosen protocol handle */
2092         next_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset);
2093         sub_dissector_result = call_dissector_only(protocol_handle, next_tvb, pinfo, tree);
2094     }
2095
2096
2097     if (protocol_handle == 0 || sub_dissector_result == 0) {
2098         /* Could get here because:
2099            - encap is DCT2000_ENCAP_UNHANDLED and we still didn't handle it, OR
2100            - desired protocol is unavailable (probably disabled), OR
2101            - protocol rejected our data
2102            Show remaining bytes as unparsed data */
2103         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_unparsed_data,
2104                             tvb, offset, -1, FALSE);
2105
2106         col_add_fstr(pinfo->cinfo, COL_INFO,
2107                      "Not dissected  (context=%s.%u   t=%s   %c   prot=%s (v=%s))",
2108                      tvb_get_ptr(tvb, 0, context_length),
2109                      port_number,
2110                      tvb_get_ptr(tvb, timestamp_start, timestamp_length),
2111                      (direction == 0) ? 'S' : 'R',
2112                      tvb_get_ptr(tvb, protocol_start, protocol_length),
2113                      tvb_get_ptr(tvb, variant_start, variant_length));
2114     }
2115     else {
2116         /* Show number of dissected bytes */
2117         if (dct2000_tree) {
2118             proto_item *ti_local = proto_tree_add_uint(dct2000_tree,
2119                                                  hf_catapult_dct2000_dissected_length,
2120                                                  tvb, 0, 0, tvb_reported_length(tvb)-offset);
2121             PROTO_ITEM_SET_GENERATED(ti_local);
2122         }
2123     }
2124 }
2125
2126
2127
2128 /******************************************************************************/
2129 /* Associate this protocol with the Catapult DCT2000 file encapsulation type. */
2130 /******************************************************************************/
2131 void proto_reg_handoff_catapult_dct2000(void)
2132 {
2133     dissector_handle_t catapult_dct2000_handle = find_dissector("dct2000");
2134
2135     dissector_add("wtap_encap", WTAP_ENCAP_CATAPULT_DCT2000, catapult_dct2000_handle);
2136
2137     mac_lte_handle = find_dissector("mac-lte");
2138     rlc_lte_handle = find_dissector("rlc-lte");
2139     pdcp_lte_handle = find_dissector("pdcp-lte");
2140 }
2141
2142 /****************************************/
2143 /* Register the protocol                */
2144 /****************************************/
2145 void proto_register_catapult_dct2000(void)
2146 {
2147     static hf_register_info hf[] =
2148     {
2149         { &hf_catapult_dct2000_context,
2150             { "Context",
2151               "dct2000.context", FT_STRING, BASE_NONE, NULL, 0x0,
2152               "Context name", HFILL
2153             }
2154         },
2155         { &hf_catapult_dct2000_port_number,
2156             { "Context Port number",
2157               "dct2000.context_port", FT_UINT8, BASE_DEC, NULL, 0x0,
2158               NULL, HFILL
2159             }
2160         },
2161         { &hf_catapult_dct2000_timestamp,
2162             { "Timestamp",
2163               "dct2000.timestamp", FT_DOUBLE, BASE_NONE, NULL, 0x0,
2164               "File timestamp", HFILL
2165             }
2166         },
2167         { &hf_catapult_dct2000_protocol,
2168             { "DCT2000 protocol",
2169               "dct2000.protocol", FT_STRING, BASE_NONE, NULL, 0x0,
2170               "Original (DCT2000) protocol name", HFILL
2171             }
2172         },
2173         { &hf_catapult_dct2000_variant,
2174             { "Protocol variant",
2175               "dct2000.variant", FT_STRING, BASE_NONE, NULL, 0x0,
2176               "DCT2000 protocol variant", HFILL
2177             }
2178         },
2179         { &hf_catapult_dct2000_outhdr,
2180             { "Out-header",
2181               "dct2000.outhdr", FT_STRING, BASE_NONE, NULL, 0x0,
2182               "DCT2000 protocol outhdr", HFILL
2183             }
2184         },
2185         { &hf_catapult_dct2000_direction,
2186             { "Direction",
2187               "dct2000.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
2188               "Frame direction (Sent or Received)", HFILL
2189             }
2190         },
2191         { &hf_catapult_dct2000_encap,
2192             { "Wireshark encapsulation",
2193               "dct2000.encapsulation", FT_UINT8, BASE_DEC, VALS(encap_vals), 0x0,
2194               "Wireshark frame encapsulation used", HFILL
2195             }
2196         },
2197         { &hf_catapult_dct2000_unparsed_data,
2198             { "Unparsed protocol data",
2199               "dct2000.unparsed_data", FT_BYTES, BASE_NONE, NULL, 0x0,
2200               "Unparsed DCT2000 protocol data", HFILL
2201             }
2202         },
2203         { &hf_catapult_dct2000_comment,
2204             { "Comment",
2205               "dct2000.comment", FT_STRING, BASE_NONE, NULL, 0x0,
2206               "Comment", HFILL
2207             }
2208         },
2209         { &hf_catapult_dct2000_dissected_length,
2210             { "Dissected length",
2211               "dct2000.dissected-length", FT_UINT16, BASE_DEC, NULL, 0x0,
2212               "Number of bytes dissected by subdissector(s)", HFILL
2213             }
2214         },
2215
2216         { &hf_catapult_dct2000_ipprim_addresses,
2217             { "IPPrim Addresses",
2218               "dct2000.ipprim", FT_STRING, BASE_NONE, NULL, 0x0,
2219               NULL, HFILL
2220             }
2221         },
2222         { &hf_catapult_dct2000_ipprim_src_addr_v4,
2223             { "Source Address",
2224               "dct2000.ipprim.src", FT_IPv4, BASE_NONE, NULL, 0x0,
2225               "IPPrim IPv4 Source Address", HFILL
2226             }
2227         },
2228         { &hf_catapult_dct2000_ipprim_src_addr_v6,
2229             { "Source Address",
2230               "dct2000.ipprim.srcv6", FT_IPv6, BASE_NONE, NULL, 0x0,
2231               "IPPrim IPv6 Source Address", HFILL
2232             }
2233         },
2234         { &hf_catapult_dct2000_ipprim_dst_addr_v4,
2235             { "Destination Address",
2236               "dct2000.ipprim.dst", FT_IPv4, BASE_NONE, NULL, 0x0,
2237               "IPPrim IPv4 Destination Address", HFILL
2238             }
2239         },
2240         { &hf_catapult_dct2000_ipprim_dst_addr_v6,
2241             { "Destination Address",
2242               "dct2000.ipprim.dstv6", FT_IPv6, BASE_NONE, NULL, 0x0,
2243               "IPPrim IPv6 Destination Address", HFILL
2244             }
2245         },
2246         { &hf_catapult_dct2000_ipprim_addr_v4,
2247             { "Address",
2248               "dct2000.ipprim.addr", FT_IPv4, BASE_NONE, NULL, 0x0,
2249               "IPPrim IPv4 Address", HFILL
2250             }
2251         },
2252         { &hf_catapult_dct2000_ipprim_addr_v6,
2253             { "Address",
2254               "dct2000.ipprim.addrv6", FT_IPv6, BASE_NONE, NULL, 0x0,
2255               "IPPrim IPv6 Address", HFILL
2256             }
2257         },
2258         { &hf_catapult_dct2000_ipprim_udp_src_port,
2259             { "UDP Source Port",
2260               "dct2000.ipprim.udp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
2261               "IPPrim UDP Source Port", HFILL
2262             }
2263         },
2264         { &hf_catapult_dct2000_ipprim_udp_dst_port,
2265             { "UDP Destination Port",
2266               "dct2000.ipprim.udp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
2267               "IPPrim UDP Destination Port", HFILL
2268             }
2269         },
2270         { &hf_catapult_dct2000_ipprim_udp_port,
2271             { "UDP Port",
2272               "dct2000.ipprim.udp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
2273               "IPPrim UDP Port", HFILL
2274             }
2275         },
2276         { &hf_catapult_dct2000_ipprim_tcp_src_port,
2277             { "TCP Source Port",
2278               "dct2000.ipprim.tcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
2279               "IPPrim TCP Source Port", HFILL
2280             }
2281         },
2282         { &hf_catapult_dct2000_ipprim_tcp_dst_port,
2283             { "TCP Destination Port",
2284               "dct2000.ipprim.tcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
2285               "IPPrim TCP Destination Port", HFILL
2286             }
2287         },
2288         { &hf_catapult_dct2000_ipprim_tcp_port,
2289             { "TCP Port",
2290               "dct2000.ipprim.tcp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
2291               "IPPrim TCP Port", HFILL
2292             }
2293         },
2294         { &hf_catapult_dct2000_ipprim_conn_id,
2295             { "Conn Id",
2296               "dct2000.ipprim.conn-id", FT_UINT16, BASE_DEC, NULL, 0x0,
2297               "IPPrim TCP Connection ID", HFILL
2298             }
2299         },
2300
2301         { &hf_catapult_dct2000_sctpprim_addresses,
2302             { "SCTPPrim Addresses",
2303               "dct2000.sctpprim", FT_STRING, BASE_NONE, NULL, 0x0,
2304               NULL, HFILL
2305             }
2306         },
2307         { &hf_catapult_dct2000_sctpprim_dst_addr_v4,
2308             { "Destination Address",
2309               "dct2000.sctpprim.dst", FT_IPv4, BASE_NONE, NULL, 0x0,
2310               "SCTPPrim IPv4 Destination Address", HFILL
2311             }
2312         },
2313         { &hf_catapult_dct2000_sctpprim_dst_addr_v6,
2314             { "Destination Address",
2315               "dct2000.sctpprim.dstv6", FT_IPv6, BASE_NONE, NULL, 0x0,
2316               "SCTPPrim IPv6 Destination Address", HFILL
2317             }
2318         },
2319         { &hf_catapult_dct2000_sctpprim_addr_v4,
2320             { "Address",
2321               "dct2000.sctpprim.addr", FT_IPv4, BASE_NONE, NULL, 0x0,
2322               "SCTPPrim IPv4 Address", HFILL
2323             }
2324         },
2325         { &hf_catapult_dct2000_sctpprim_addr_v6,
2326             { "Address",
2327               "dct2000.sctpprim.addrv6", FT_IPv6, BASE_NONE, NULL, 0x0,
2328               "SCTPPrim IPv6 Address", HFILL
2329             }
2330         },
2331         { &hf_catapult_dct2000_sctpprim_dst_port,
2332             { "UDP Destination Port",
2333               "dct2000.sctprim.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
2334               "SCTPPrim Destination Port", HFILL
2335             }
2336         },
2337
2338         { &hf_catapult_dct2000_tty,
2339             { "tty contents",
2340               "dct2000.tty", FT_NONE, BASE_NONE, NULL, 0x0,
2341               NULL, HFILL
2342             }
2343         },
2344         { &hf_catapult_dct2000_tty_line,
2345             { "tty line",
2346               "dct2000.tty-line", FT_STRING, BASE_NONE, NULL, 0x0,
2347               NULL, HFILL
2348             }
2349         },
2350
2351         { &hf_catapult_dct2000_lte_ueid,
2352             { "UE Id",
2353               "dct2000.lte.ueid", FT_UINT16, BASE_DEC, NULL, 0x0,
2354               "User Equipment Identifier", HFILL
2355             }
2356         },
2357         { &hf_catapult_dct2000_lte_srbid,
2358             { "srbid",
2359               "dct2000.lte.srbid", FT_UINT8, BASE_DEC, NULL, 0x0,
2360               "Signalling Radio Bearer Identifier", HFILL
2361             }
2362         },
2363         { &hf_catapult_dct2000_lte_drbid,
2364             { "drbid",
2365               "dct2000.lte.drbid", FT_UINT8, BASE_DEC, NULL, 0x0,
2366               "Data Radio Bearer Identifier", HFILL
2367             }
2368         },
2369         { &hf_catapult_dct2000_lte_cellid,
2370             { "Cell-Id",
2371               "dct2000.lte.cellid", FT_UINT16, BASE_DEC, NULL, 0x0,
2372               "Cell Identifier", HFILL
2373             }
2374         },
2375         { &hf_catapult_dct2000_lte_bcch_transport,
2376             { "BCCH Transport",
2377               "dct2000.lte.bcch-transport", FT_UINT16, BASE_DEC, VALS(bcch_transport_vals), 0x0,
2378               "BCCH Transport Channel", HFILL
2379             }
2380         },
2381         { &hf_catapult_dct2000_lte_rlc_op,
2382             { "RLC Op",
2383               "dct2000.lte.rlc-op", FT_UINT8, BASE_DEC, VALS(rlc_op_vals), 0x0,
2384               "RLC top-level op", HFILL
2385             }
2386         },
2387         { &hf_catapult_dct2000_lte_rlc_channel_type,
2388             { "RLC Logical Channel Type",
2389               "dct2000.lte.rlc-logchan-type", FT_UINT8, BASE_DEC, VALS(rlc_logical_channel_vals), 0x0,
2390               NULL, HFILL
2391             }
2392         },
2393         { &hf_catapult_dct2000_lte_rlc_mui,
2394             { "MUI",
2395               "dct2000.lte.rlc-mui", FT_UINT16, BASE_DEC, NULL, 0x0,
2396               "RLC MUI", HFILL
2397             }
2398         },
2399         { &hf_catapult_dct2000_lte_rlc_cnf,
2400             { "CNF",
2401               "dct2000.lte.rlc-cnf", FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0,
2402               "RLC CNF", HFILL
2403             }
2404         },
2405         { &hf_catapult_dct2000_lte_rlc_discard_req,
2406             { "Discard Req",
2407               "dct2000.lte.rlc-discard-req", FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0,
2408               "RLC Discard Req", HFILL
2409             }
2410         },
2411     };
2412
2413     static gint *ett[] =
2414     {
2415         &ett_catapult_dct2000,
2416         &ett_catapult_dct2000_ipprim,
2417         &ett_catapult_dct2000_sctpprim,
2418         &ett_catapult_dct2000_tty
2419     };
2420
2421     module_t *catapult_dct2000_module;
2422
2423     /* Register protocol. */
2424     proto_catapult_dct2000 = proto_register_protocol("Catapult DCT2000 packet",
2425                                                      "DCT2000",
2426                                                      "dct2000");
2427     proto_register_field_array(proto_catapult_dct2000, hf, array_length(hf));
2428     proto_register_subtree_array(ett, array_length(ett));
2429
2430     /* Allow dissector to find be found by name. */
2431     register_dissector("dct2000", dissect_catapult_dct2000, proto_catapult_dct2000);
2432
2433     /* Preferences */
2434     catapult_dct2000_module = prefs_register_protocol(proto_catapult_dct2000, NULL);
2435
2436     /* This preference no longer supported (introduces linkage dependency between
2437        dissectors and wiretap) */
2438     prefs_register_obsolete_preference(catapult_dct2000_module, "board_ports_only");
2439
2440     /* Determines whether for not-handled protocols we should try to parse it if:
2441        - it looks like its embedded in an ipprim message, AND
2442        - the DCT2000 protocol name can be matched to a Wireshark dissector name */
2443     prefs_register_bool_preference(catapult_dct2000_module, "ipprim_heuristic",
2444                                    "Use IP Primitive heuristic",
2445                                    "If a payload looks like its embedded in an "
2446                                    "IP primitive message, and there is a Wireshark "
2447                                    "dissector matching the DCT2000 protocol name, "
2448                                    "try parsing the payload using that dissector",
2449                                    &catapult_dct2000_try_ipprim_heuristic);
2450
2451     /* Determines whether for not-handled protocols we should try to parse it if:
2452        - it looks like its embedded in an sctpprim message, AND
2453        - the DCT2000 protocol name can be matched to a Wireshark dissector name */
2454     prefs_register_bool_preference(catapult_dct2000_module, "sctpprim_heuristic",
2455                                    "Use SCTP Primitive heuristic",
2456                                    "If a payload looks like its embedded in an "
2457                                    "SCTP primitive message, and there is a Wireshark "
2458                                    "dissector matching the DCT2000 protocol name, "
2459                                    "try parsing the payload using that dissector",
2460                                    &catapult_dct2000_try_sctpprim_heuristic);
2461
2462     /* Determines whether LTE RRC messages should be dissected */
2463     prefs_register_bool_preference(catapult_dct2000_module, "decode_lte_rrc",
2464                                    "Attempt to decode LTE RRC frames",
2465                                    "When set, attempt to decode LTE RRC frames. "
2466                                    "Note that this won't affect other protocols "
2467                                    "that also call the LTE RRC dissector",
2468                                    &catapult_dct2000_dissect_lte_rrc);
2469
2470     /* Determines whether LTE S1AP messages should be dissected */
2471     prefs_register_bool_preference(catapult_dct2000_module, "decode_lte_s1ap",
2472                                    "Attempt to decode LTE S1AP frames",
2473                                    "When set, attempt to decode LTE S1AP frames. "
2474                                    "Note that this won't affect other protocols "
2475                                    "that also call the LTE S1AP dissector",
2476                                    &catapult_dct2000_dissect_lte_s1ap);
2477
2478     /* Determines whether out-of-band messages should dissected */
2479     prefs_register_bool_preference(catapult_dct2000_module, "decode_mac_lte_oob_messages",
2480                                    "Look for out-of-band LTE MAC events messages in comments",
2481                                    "When set, look for formatted messages indicating "
2482                                    "specific events.  This may be quite slow, so should "
2483                                    "be disabled if LTE MAC is not being analysed",
2484                                    &catapult_dct2000_dissect_mac_lte_oob_messages);
2485 }
2486