Also avoid some unnecessary calls to strcmp() here, where the release
[metze/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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "config.h"
26
27 #include <glib.h>
28
29 #include <stdio.h>
30 #include <ctype.h>
31
32 #include <epan/packet.h>
33 #include <epan/conversation.h>
34 #include <epan/expert.h>
35 #include <epan/emem.h>
36 #include <epan/ipproto.h>
37 #include <epan/prefs.h>
38 #include <epan/strutil.h>
39 #include <epan/addr_resolv.h>
40
41 #include <wiretap/catapult_dct2000.h>
42 #include "packet-umts_fp.h"
43 #include "packet-rlc.h"
44
45 #include "packet-mac-lte.h"
46 #include "packet-rlc-lte.h"
47 #include "packet-pdcp-lte.h"
48
49 /* Protocol and registered fields. */
50 static int proto_catapult_dct2000 = -1;
51
52 static int hf_catapult_dct2000_context = -1;
53 static int hf_catapult_dct2000_port_number = -1;
54 static int hf_catapult_dct2000_timestamp = -1;
55 static int hf_catapult_dct2000_protocol = -1;
56 static int hf_catapult_dct2000_variant = -1;
57 static int hf_catapult_dct2000_outhdr = -1;
58 static int hf_catapult_dct2000_direction = -1;
59 static int hf_catapult_dct2000_encap = -1;
60 static int hf_catapult_dct2000_unparsed_data = -1;
61 static int hf_catapult_dct2000_comment = -1;
62 static int hf_catapult_dct2000_error_comment = -1;
63 static int hf_catapult_dct2000_tty = -1;
64 static int hf_catapult_dct2000_tty_line = -1;
65 static int hf_catapult_dct2000_dissected_length = -1;
66
67 static int hf_catapult_dct2000_ipprim_addresses = -1;
68 static int hf_catapult_dct2000_ipprim_src_addr_v4 = -1;
69 static int hf_catapult_dct2000_ipprim_src_addr_v6 = -1;
70 static int hf_catapult_dct2000_ipprim_dst_addr_v4 = -1;
71 static int hf_catapult_dct2000_ipprim_dst_addr_v6 = -1;
72 static int hf_catapult_dct2000_ipprim_addr_v4 = -1;
73 static int hf_catapult_dct2000_ipprim_addr_v6 = -1;
74 static int hf_catapult_dct2000_ipprim_udp_src_port = -1;
75 static int hf_catapult_dct2000_ipprim_udp_dst_port = -1;
76 static int hf_catapult_dct2000_ipprim_udp_port = -1;
77 static int hf_catapult_dct2000_ipprim_tcp_src_port = -1;
78 static int hf_catapult_dct2000_ipprim_tcp_dst_port = -1;
79 static int hf_catapult_dct2000_ipprim_tcp_port = -1;
80 static int hf_catapult_dct2000_ipprim_conn_id = -1;
81
82 static int hf_catapult_dct2000_sctpprim_addresses = -1;
83 static int hf_catapult_dct2000_sctpprim_dst_addr_v4 = -1;
84 static int hf_catapult_dct2000_sctpprim_dst_addr_v6 = -1;
85 static int hf_catapult_dct2000_sctpprim_addr_v4 = -1;
86 static int hf_catapult_dct2000_sctpprim_addr_v6 = -1;
87 static int hf_catapult_dct2000_sctpprim_dst_port = -1;
88
89 static int hf_catapult_dct2000_lte_ueid = -1;
90 static int hf_catapult_dct2000_lte_srbid = -1;
91 static int hf_catapult_dct2000_lte_drbid = -1;
92 static int hf_catapult_dct2000_lte_cellid = -1;
93 static int hf_catapult_dct2000_lte_bcch_transport = -1;
94 static int hf_catapult_dct2000_lte_rlc_op = -1;
95 static int hf_catapult_dct2000_lte_rlc_channel_type = -1;
96 static int hf_catapult_dct2000_lte_rlc_mui = -1;
97 static int hf_catapult_dct2000_lte_rlc_cnf = -1;
98 static int hf_catapult_dct2000_lte_rlc_discard_req = -1;
99
100 static int hf_catapult_dct2000_lte_ccpri_opcode = -1;
101 static int hf_catapult_dct2000_lte_ccpri_status = -1;
102 static int hf_catapult_dct2000_lte_ccpri_channel = -1;
103
104 static int hf_catapult_dct2000_lte_monitor_cpu_user = -1;
105 static int hf_catapult_dct2000_lte_monitor_cpu_sys = -1;
106 static int hf_catapult_dct2000_lte_monitor_cpu_load = -1;
107 static int hf_catapult_dct2000_lte_monitor_lte_scs_cpu_user = -1;
108 static int hf_catapult_dct2000_lte_monitor_lte_scs_cpu_sys = -1;
109
110
111 static int hf_catapult_dct2000_lte_nas_rrc_opcode = -1;
112 static int hf_catapult_dct2000_lte_nas_rrc_establish_cause = -1;
113 static int hf_catapult_dct2000_lte_nas_rrc_priority = -1;
114 static int hf_catapult_dct2000_lte_nas_rrc_release_cause = -1;
115
116
117 /* UMTS RLC fields */
118 static int hf_catapult_dct2000_ueid = -1;
119 static int hf_catapult_dct2000_rbid = -1;
120 static int hf_catapult_dct2000_ccch_id = -1;
121 static int hf_catapult_dct2000_no_crc_error = -1;
122 static int hf_catapult_dct2000_crc_error = -1;
123 static int hf_catapult_dct2000_clear_tx_buffer = -1;
124 static int hf_catapult_dct2000_buffer_occupancy = -1;
125 static int hf_catapult_dct2000_pdu_size = -1;
126 static int hf_catapult_dct2000_ueid_type = -1;
127 static int hf_catapult_dct2000_tx_priority = -1;
128 static int hf_catapult_dct2000_last_in_seg_set = -1;
129 static int hf_catapult_dct2000_rx_timing_deviation = -1;
130 static int hf_catapult_dct2000_transport_channel_type = -1;
131 static int hf_catapult_dct2000_no_padding_bits = -1;
132
133 /* Variables used for preferences */
134 static gboolean catapult_dct2000_try_ipprim_heuristic = TRUE;
135 static gboolean catapult_dct2000_try_sctpprim_heuristic = TRUE;
136 static gboolean catapult_dct2000_dissect_lte_rrc = TRUE;
137 static gboolean catapult_dct2000_dissect_lte_s1ap = TRUE;
138 static gboolean catapult_dct2000_dissect_mac_lte_oob_messages = TRUE;
139
140 /* Protocol subtree. */
141 static int ett_catapult_dct2000 = -1;
142 static int ett_catapult_dct2000_ipprim = -1;
143 static int ett_catapult_dct2000_sctpprim = -1;
144 static int ett_catapult_dct2000_tty = -1;
145
146 static const value_string direction_vals[] = {
147     { 0,   "Sent" },
148     { 1,   "Received" },
149     { 0,   NULL },
150 };
151
152 static const value_string encap_vals[] = {
153     { WTAP_ENCAP_RAW_IP,                 "Raw IP" },
154     { WTAP_ENCAP_ETHERNET,               "Ethernet" },
155     { WTAP_ENCAP_ISDN,                   "LAPD" },
156     { WTAP_ENCAP_ATM_PDUS_UNTRUNCATED,   "ATM (PDUs untruncated)" },
157     { WTAP_ENCAP_PPP,                    "PPP" },
158     { DCT2000_ENCAP_SSCOP,               "SSCOP" },
159     { WTAP_ENCAP_FRELAY,                 "Frame Relay" },
160     { WTAP_ENCAP_MTP2,                   "MTP2" },
161     { DCT2000_ENCAP_NBAP,                "NBAP" },
162     { DCT2000_ENCAP_UNHANDLED,           "No Direct Encapsulation" },
163     { 0,                                 NULL },
164 };
165
166 static const value_string bcch_transport_vals[] = {
167     { BCH_TRANSPORT,    "BCH" },
168     { DLSCH_TRANSPORT,  "DLSCH" },
169     { 0,   NULL },
170 };
171
172
173 #define RLC_MGMT_ASSIGN                 0x41
174 #define RLC_AM_DATA_REQ                 0x60
175 #define RLC_AM_DATA_IND                 0x61
176 #define RLC_AM_DATA_CONF                0x62
177 #define RLC_UM_DATA_REQ                 0x70
178 #define RLC_UM_DATA_IND                 0x71
179 #define RLC_UM_DATA_CONF                0x74
180 #define RLC_TR_DATA_REQ                 0x80
181 #define RLC_TR_DATA_IND                 0x81
182 #define RLC_TR_DATA_CONF                0x83
183
184 static const value_string rlc_op_vals[] = {
185     { RLC_AM_DATA_REQ,   "[UL] [AM]" },
186     { RLC_AM_DATA_IND,   "[DL] [AM]" },
187     { RLC_UM_DATA_REQ,   "[UL] [UM]"},
188     { RLC_UM_DATA_IND,   "[DL] [UM]"},
189     { RLC_TR_DATA_REQ,   "[UL] [TM]"},
190     { RLC_TR_DATA_IND,   "[DL] [TM]"},
191     { 0,   NULL }
192 };
193
194
195 static const value_string rlc_logical_channel_vals[] = {
196     { Channel_DCCH,  "DCCH"},
197     { Channel_BCCH,  "BCCH"},
198     { Channel_CCCH,  "CCCH"},
199     { Channel_PCCH,  "PCCH"},
200     { 0,             NULL}
201 };
202
203
204 #define CCPRI_REQ 1
205 #define CCPRI_IND 2
206
207 static const value_string ccpri_opcode_vals[] = {
208     { CCPRI_REQ,     "REQUEST"},
209     { CCPRI_IND,     "INDICATION"},
210     { 0,             NULL}
211 };
212
213 static const value_string ccpri_status_vals[] = {
214     { 0,     "OK"},
215     { 1,     "ERROR"},
216     { 0,     NULL}
217 };
218
219 static const value_string rlc_rbid_vals[] = {
220     { 1,     "DCH1"},
221     { 2,     "DCH2"},
222     { 3,     "DCH3"},
223     { 4,     "DCH4"},
224     { 5,     "DCH5"},
225     { 6,     "DCH6"},
226     { 7,     "DCH7"},
227     { 8,     "DCH8"},
228     { 9,     "DCH9"},
229     { 10,    "DCH10"},
230     { 11,    "DCH11"},
231     { 12,    "DCH12"},
232     { 13,    "DCH13"},
233     { 14,    "DCH14"},
234     { 15,    "DCH15"},
235     { 17,    "BCCH"},
236     { 18,    "CCCH"},
237     { 19,    "PCCH"},
238     { 20,    "SHCCH"},
239     { 21,    "CTCH"},
240     { 23,    "MCCH"},
241     { 24,    "MSCH"},
242     { 25,    "MTCH"},
243     { 0,     NULL}
244 };
245
246 static const value_string ueid_type_vals[] = {
247     { 0,     "URNTI"},
248     { 1,     "CRNTI"},
249     { 0,     NULL}
250 };
251
252 static const value_string tx_priority_vals[] = {
253     { 0,     "Normal"},
254     { 1,     "High"},
255     { 0,     NULL}
256 };
257
258 static const value_string transport_channel_type_vals[] = {
259     { 1,     "RACH"},
260     { 2,     "FACH"},
261     { 3,     "BCH"},
262     { 4,     "PCH"},
263     { 6,     "USCH"},
264     { 7,     "DSCH"},
265     { 8,     "DCH"},
266     { 9,     "HSDSCH"},
267     { 10,    "EDCH"},
268     { 0,     NULL}
269 };
270
271 #define LTE_NAS_RRC_DATA_IND       0x02
272 #define LTE_NAS_RRC_DATA_REQ       0x03
273 #define LTE_NAS_RRC_ESTABLISH_REQ  0x06
274 #define LTE_NAS_RRC_RELEASE_IND    0x08
275
276 static const value_string lte_nas_rrc_opcode_vals[] = {
277     { LTE_NAS_RRC_DATA_IND,        "Data-Ind"},
278     { LTE_NAS_RRC_DATA_REQ,        "Data-Req"},
279     { LTE_NAS_RRC_ESTABLISH_REQ,   "Establish-Req"},
280     { LTE_NAS_RRC_RELEASE_IND,     "Release-Ind"},
281     { 0,     NULL}
282 };
283
284
285
286 #define MAX_OUTHDR_VALUES 32
287
288 static guint outhdr_values[MAX_OUTHDR_VALUES];
289 static guint outhdr_values_found = 0;
290
291 extern int proto_fp;
292 extern int proto_rlc;
293
294 extern int proto_rlc_lte;
295 extern int proto_pdcp_lte;
296
297 static dissector_handle_t mac_lte_handle;
298 static dissector_handle_t rlc_lte_handle;
299 static dissector_handle_t pdcp_lte_handle;
300
301 void proto_register_catapult_dct2000(void);
302
303 static dissector_handle_t look_for_dissector(const char *protocol_name);
304 static void parse_outhdr_string(const guchar *outhdr_string, gint outhdr_length);
305
306 static void attach_fp_info(packet_info *pinfo, gboolean received,
307                            const char *protocol_name, int variant);
308 static void attach_rlc_info(packet_info *pinfo, guint32 urnti, guint8 rbid,
309                             gboolean is_sent);
310
311 static void attach_mac_lte_info(packet_info *pinfo);
312 static void attach_rlc_lte_info(packet_info *pinfo);
313 static void attach_pdcp_lte_info(packet_info *pinfo);
314
315
316
317 /* Return the number of bytes used to encode the length field
318    (we're not interested in the length value itself) */
319 static int skipASNLength(guint8 value)
320 {
321     if ((value & 0x80) == 0)
322     {
323         return 1;
324     }
325     else
326     {
327         return ((value & 0x03) == 1) ? 2 : 3;
328     }
329 }
330
331
332 /* Look for the protocol data within an ipprim packet.
333    Only set *data_offset if data field found. */
334 static gboolean find_ipprim_data_offset(tvbuff_t *tvb, int *data_offset, guint8 direction,
335                                         guint32 *source_addr_offset, guint8 *source_addr_length,
336                                         guint32 *dest_addr_offset,   guint8 *dest_addr_length,
337                                         guint32 *source_port_offset, guint32 *dest_port_offset,
338                                         port_type *type_of_port,
339                                         guint16 *conn_id_offset)
340 {
341     guint8 length;
342     int    offset = *data_offset;
343
344     /* Get the ipprim command code. */
345     guint8 tag = tvb_get_guint8(tvb, offset++);
346
347     /* Only accept UDP or TCP data request or indication */
348     switch (tag) {
349         case 0x23:  /* UDP data request */
350         case 0x24:  /* UDP data indication */
351             *type_of_port = PT_UDP;
352             break;
353         case 0x45:  /* TCP data request */
354         case 0x46:  /* TCP data indication */
355             *type_of_port = PT_TCP;
356             break;
357         default:
358             return FALSE;
359     }
360
361     /* Skip any other TLC fields before reach payload */
362     while (tvb_length_remaining(tvb, offset) > 2) {
363         /* Look at next tag */
364         tag = tvb_get_guint8(tvb, offset++);
365
366         /* Is this the data payload we're expecting? */
367         if (((tag == 0x34) && (*type_of_port == PT_UDP)) ||
368             ((tag == 0x48) && (*type_of_port == PT_TCP))) {
369
370             *data_offset = offset;
371             return TRUE;
372         }
373         else {
374             /* Read length in next byte */
375             length = tvb_get_guint8(tvb, offset++);
376
377             if (tag == 0x31 && length >=4) {
378                 /* Remote IP address */
379                 if (direction == 0) {
380                     /* Sent *to* remote, so dest */
381                     *dest_addr_offset = offset;
382                     *dest_addr_length = (length/4) * 4;
383                 }
384                 else {
385                     *source_addr_offset = offset;
386                     *source_addr_length = (length/4) * 4;
387                 }
388
389                 /* Remote port follows (if present) */
390                 if ((length % 4) == 2) {
391                     if (direction == 0) {
392                         *dest_port_offset = offset + *dest_addr_length;
393                     }
394                     else {
395                         *source_port_offset = offset + *source_addr_length;
396                     }
397                 }
398             }
399             else
400             if (tag == 0x32) {
401                 if (length == 4 || length == 16) {
402                     /* Local IP address */
403                     if (direction == 0) {
404                         /* Sent *from* local, so source */
405                         *source_addr_offset = offset;
406                         *source_addr_length = length;
407                     }
408                     else {
409                         *dest_addr_offset = offset;
410                         *dest_addr_length = length;
411                     }
412                 }
413             }
414             else
415             if (tag == 0x33 && length == 2) {
416                 /* Get local port */
417                 if (direction == 0) {
418                     /* Sent from local, so source */
419                     *source_port_offset = offset;
420                 }
421                 else {
422                     *dest_port_offset = offset;
423                 }
424             }
425             else
426             if (tag == 0x36 && length == 2) {
427                 /* Get conn_id */
428                 *conn_id_offset = offset;
429             }
430
431             /* Skip the length of the indicated value */
432             offset += length;
433         }
434     }
435
436     /* No data found... */
437     return FALSE;
438 }
439
440
441
442 /* Look for the protocol data within an sctpprim (variant 1 or 2...) packet.
443    Only set *data_offset if data field found. */
444 static gboolean find_sctpprim_variant1_data_offset(tvbuff_t *tvb, int *data_offset,
445                                                    guint32 *dest_addr_offset,
446                                                    guint16 *dest_addr_length,
447                                                    guint32 *dest_port_offset)
448 {
449     int offset = *data_offset;
450
451     /* Get the sctpprim command code. */
452     guint8 first_tag = tvb_get_guint8(tvb, offset++);
453     guint8 tag;
454     guint8 first_length_byte;
455
456     /* Only accept interested in data requests or indications */
457     switch (first_tag) {
458         case 0x04:  /* data request */
459         case 0x62:  /* data indication */
460             break;
461         default:
462             return FALSE;
463     }
464
465     first_length_byte = tvb_get_guint8(tvb, offset);
466     offset += skipASNLength(first_length_byte);
467
468     /* Skip any other fields before reach payload */
469     while (tvb_length_remaining(tvb, offset) > 2) {
470         /* Look at next tag */
471         tag = tvb_get_guint8(tvb, offset++);
472
473         /* Is this the data payload we're expecting? */
474         if (tag == 0x19) {
475             *data_offset = offset;
476             return TRUE;
477         }
478         else {
479             /* Skip length field */
480             offset++;
481             switch (tag) {
482                 case 0x0a: /* destPort */
483                     *dest_port_offset = offset;
484                     offset += 2;
485                     break;
486
487                 case 0x01: /* sctpInstanceNum */
488                 case 0x1e: /* strseqnum */
489                 case 0x0d: /* streamnum */
490                     offset += 2;
491                     continue;
492
493                 case 0x09: /* ipv4Address */
494                     *dest_addr_offset = offset;
495                     *dest_addr_length = 4;
496                     offset += 4;
497                     break;
498
499                 case 0x1d:
500                 case 0x0c: /* payloadType */
501                     offset += 4;
502                     continue;
503
504                 default:
505                     /* Fail if not a known header field */
506                     return FALSE;
507             }
508         }
509     }
510
511     /* No data found... */
512     return FALSE;
513 }
514
515 /* Look for the protocol data within an sctpprim (variant 3) packet.
516    Only set *data_offset if data field found. */
517 static gboolean find_sctpprim_variant3_data_offset(tvbuff_t *tvb, int *data_offset,
518                                                    guint32 *dest_addr_offset,
519                                                    guint16 *dest_addr_length,
520                                                    guint32 *dest_port_offset)
521 {
522     guint16 tag    = 0;
523     guint16 length = 0;
524     int     offset = *data_offset;
525
526     /* Get the sctpprim (2 byte) command code. */
527     guint16 top_tag = tvb_get_ntohs(tvb, offset);
528     offset += 2;
529
530     /* Only interested in data requests or indications */
531     switch (top_tag) {
532         case 0x0400:  /* SendDataReq */
533         case 0x6200:  /* DataInd */
534             break;
535
536         default:
537             return FALSE;
538     }
539
540     /* Overall length field is next 2 bytes */
541     offset += 2;
542
543     /* Rx/Tx ops have different formats */
544
545     /*****************/
546     /* DataInd        */
547     if (top_tag == 0x6200) {
548         /* Next 2 bytes are associate ID */
549         offset += 2;
550
551         /* Next 2 bytes are destination port */
552         *dest_port_offset = offset;
553         offset += 2;
554
555         /* Destination address should follow - check tag */
556         tag = tvb_get_ntohs(tvb, offset);
557         if (tag != 0x0900) {
558             return FALSE;
559         }
560         else {
561             /* Skip tag */
562             offset += 2;
563
564             /* Length field */
565             length = tvb_get_ntohs(tvb, offset) / 2;
566             if ((length != 4) && (length != 16))
567             {
568                 return FALSE;
569             }
570             offset += 2;
571
572             /* Address data is here */
573             *dest_addr_offset = offset;
574             *dest_addr_length = length;
575
576             offset += length;
577         }
578
579         /* Not interested in remaining (fixed) fields */
580         if (tvb_reported_length_remaining(tvb, offset) > (4 + 2 + 2 + 4)) {
581             offset += (4 + 2 + 2 + 4);
582         }
583         else {
584             return FALSE;
585         }
586
587         /* Data should now be here */
588         tag = tvb_get_ntohs(tvb, offset);
589         offset += 2;
590         if (tag == 0x1900) {
591             /* 2-byte length field */
592             offset += 2;
593
594             /* Data is here!!! */
595             *data_offset = offset;
596             return TRUE;
597         }
598         else {
599             return FALSE;
600         }
601     }
602
603     /***************/
604     /* SendDataReq */
605     else if (top_tag == 0x0400) {
606         /* AssociateId should follow - check tag */
607         tag = tvb_get_ntohs(tvb, offset);
608         if (tag != 0x2400) {
609             return FALSE;
610         }
611         else {
612             /* Skip tag */
613             offset += 2;
614
615             /* Skip 2-byte value */
616             offset += 2;
617         }
618
619         /* Get tag */
620         tag = tvb_get_ntohs(tvb, offset);
621         offset += 2;
622
623         /* Some optional params */
624         while ((tag != 0x0c00) && (tvb_length_remaining(tvb, offset) > 4)) {
625             switch (tag) {
626                 case 0x0900:   /* Dest address */
627                     /* Length field */
628                     length = tvb_get_ntohs(tvb, offset) / 2;
629                     if ((length != 4) && (length != 16)) {
630                         return FALSE;
631                     }
632                     offset += 2;
633
634                     /* Address data is here */
635                     *dest_addr_offset = offset;
636                     *dest_addr_length = length;
637
638                     offset += length;
639                     break;
640
641                 case 0x0a00:   /* Dest port number */
642                     *dest_port_offset = offset;
643                     offset += 2;
644                     break;
645
646                 case 0x0d00:   /* StreamNum */
647                     *dest_port_offset = offset;
648                     offset += 2;
649                     break;
650
651
652                 default:
653                     return FALSE;
654             }
655
656             /* Get the next tag */
657             tag = tvb_get_ntohs(tvb, offset);
658             offset += 2;
659         }
660
661
662         /* Mandatory payload type */
663         if (tag != 0x0c00) {
664             return FALSE;
665         }
666         length = tvb_get_ntohs(tvb, offset) / 2;
667         offset += 2;
668         offset += length;
669
670
671         /* Optional options */
672         tag = tvb_get_ntohs(tvb, offset);
673         offset += 2;
674         if (tag == 0x0b00) {
675             length = tvb_get_ntohs(tvb, offset) / 2;
676             offset += 2;
677
678             offset += length;
679
680             /* Get next tag */
681             tag = tvb_get_ntohs(tvb, offset);
682             offset += 2;
683         }
684
685
686         /* Data should now be here!! */
687         if (tag == 0x1900) {
688             /* 2-byte length field */
689             offset += 2;
690
691             /* Data is here!!! */
692             *data_offset = offset;
693             return TRUE;
694         }
695         else {
696             return FALSE;
697         }
698     }
699
700     return FALSE;
701 }
702
703
704 /* Dissect a UMTS RLC frame by:
705    - parsing the primitive header
706    - passing those values + outhdeader to dissector
707    - calling the UMTS RLC dissector */
708 static void dissect_rlc_umts(tvbuff_t *tvb, gint offset,
709                              packet_info *pinfo, proto_tree *tree,
710                              gboolean is_sent)
711 {
712     guint8              tag;
713     gboolean            ueid_set        = FALSE, rbid_set=FALSE;
714     guint32             ueid            = 0;
715     guint8              rbid            = 0;
716     guint8              length;
717     tvbuff_t           *rlc_tvb;
718     dissector_handle_t  rlc_umts_handle = 0;
719
720     /* Top-level opcode */
721     tag = tvb_get_guint8(tvb, offset++);
722     switch (tag) {
723         case 0xc0:    /* mac data request */
724         case 0xc1:    /* mac data indication */
725             break;
726
727         default:
728             /* No data to dissect */
729             return;
730     }
731
732     /* Keep going until reach data tag or end of frame */
733     while ((tag != 0x41) && tvb_length_remaining(tvb, offset)) { /* i.e. Data */
734         tag = tvb_get_guint8(tvb, offset++);
735         switch (tag) {
736             case 0x72:  /* UE Id */
737                 ueid = tvb_get_ntohl(tvb, offset);
738                 proto_tree_add_item(tree, hf_catapult_dct2000_ueid, tvb, offset, 4, ENC_BIG_ENDIAN);
739                 offset += 4;
740                 ueid_set = TRUE;
741                 break;
742             case 0xa2:  /* RBID */
743                 offset++;  /* skip length */
744                 rbid = tvb_get_guint8(tvb, offset);
745                 proto_tree_add_item(tree, hf_catapult_dct2000_rbid, tvb, offset, 1, ENC_BIG_ENDIAN);
746                 offset++;
747                 rbid_set = TRUE;
748                 break;
749             case 0x22:  /* CCCH-id setting rbid to CCCH! */
750                 offset++;  /* skip length */
751                 proto_tree_add_item(tree, hf_catapult_dct2000_ccch_id, tvb, offset, 1, ENC_BIG_ENDIAN);
752                 offset++;
753                 rbid = 18;
754                 break;
755             case 0xc4:  /* No CRC error */
756                 proto_tree_add_item(tree, hf_catapult_dct2000_no_crc_error, tvb, offset-1, 1, ENC_NA);
757                 break;
758             case 0xc5:  /* CRC error */
759                 proto_tree_add_item(tree, hf_catapult_dct2000_crc_error, tvb, offset-1, 1, ENC_NA);
760                 break;
761             case 0xf7:  /* Clear Tx Buffer */
762                 proto_tree_add_item(tree, hf_catapult_dct2000_clear_tx_buffer, tvb, offset-1, 1, ENC_NA);
763                 break;
764
765             case 0x41:  /* Data !!! */
766                 offset += skipASNLength(tvb_get_guint8(tvb, offset));
767                 break;
768
769             default:
770                 /* For other fields, just skip length and following data */
771                 length = tvb_get_guint8(tvb, offset++);
772                 switch (tag) {
773                     case 0x42:   /* Buffer Occupancy */
774                         proto_tree_add_item(tree, hf_catapult_dct2000_buffer_occupancy, tvb, offset, length, ENC_BIG_ENDIAN);
775                         break;
776                     case 0x49:   /* PDU Size */
777                         proto_tree_add_item(tree, hf_catapult_dct2000_pdu_size, tvb, offset, 2, ENC_LITTLE_ENDIAN);
778                         break;
779                     case 0x47:   /* UEId type */
780                         proto_tree_add_item(tree, hf_catapult_dct2000_ueid_type, tvb, offset, 1, ENC_BIG_ENDIAN);
781                         break;
782                     case 0x4e:   /* Tx Priority */
783                         proto_tree_add_item(tree, hf_catapult_dct2000_tx_priority, tvb, offset, 1, ENC_BIG_ENDIAN);
784                         break;
785                     case 0x4c:   /* Last in seg set */
786                         proto_tree_add_item(tree, hf_catapult_dct2000_last_in_seg_set, tvb, offset, 1, ENC_BIG_ENDIAN);
787                         break;
788                     case 0x43:   /* Rx timing deviation */
789                         proto_tree_add_item(tree, hf_catapult_dct2000_rx_timing_deviation, tvb, offset, 1, ENC_BIG_ENDIAN);
790                         break;
791                     case 0x46:   /* Transport channel type */
792                         proto_tree_add_item(tree, hf_catapult_dct2000_transport_channel_type, tvb, offset, 1, ENC_BIG_ENDIAN);
793                         break;
794                     case 0xc2:   /* Number of padding bits */
795                         proto_tree_add_item(tree, hf_catapult_dct2000_no_padding_bits, tvb, offset, 1, ENC_BIG_ENDIAN);
796                         break;
797
798                     default:
799                         break;
800
801
802                 }
803                 offset += length;
804         }
805     }
806
807     /* Have we got enough info to call dissector */
808     if ((tag == 0x41) && ueid_set && rbid_set) {
809         attach_rlc_info(pinfo, ueid, rbid, is_sent);
810
811         /* Set appropriate RLC dissector handle */
812         switch (rbid) {
813             case 1:  case 2:  case 3:  case 4:  case 5:
814             case 6:  case 7:  case 8:  case 9:  case 10:
815             case 11: case 12: case 13: case 14: case 15:
816                 /* DCH channels. */
817                 /*   TODO: can't really tell if these are control or transport...
818                      maybe control with preferences (UAT?) between "rlc.ps_dtch" and "rlc.dcch" ? */
819                 rlc_umts_handle = find_dissector("rlc.dch_unknown");
820                 break;
821             case 18:
822                 rlc_umts_handle = find_dissector("rlc.ccch");
823                 break;
824             case 21:
825                 rlc_umts_handle = find_dissector("rlc.ctch");
826                 break;
827
828             default:
829                 /* Give up here */
830                 return;
831         }
832
833         /* Call UMTS RLC dissector */
834         if (rlc_umts_handle != 0) {
835             rlc_tvb = tvb_new_subset(tvb, offset, -1, tvb_length_remaining(tvb, offset));
836             call_dissector_only(rlc_umts_handle, rlc_tvb, pinfo, tree, NULL);
837         }
838     }
839 }
840
841
842
843 /* Dissect an RRC LTE frame by first parsing the header entries then passing
844    the data to the RRC dissector, according to direction and channel type.
845    TODO: factor out common code between this function and dissect_pdcp_lte() */
846 static void dissect_rrc_lte(tvbuff_t *tvb, gint offset,
847                             packet_info *pinfo, proto_tree *tree)
848 {
849     guint8              tag;
850     dissector_handle_t  protocol_handle = 0;
851     gboolean            isUplink        = FALSE;
852     LogicalChannelType  logicalChannelType;
853     guint16             cell_id;
854     guint8              bcch_transport  = 0;
855     tvbuff_t           *rrc_tvb;
856
857     /* Top-level opcode */
858     tag = tvb_get_guint8(tvb, offset++);
859     switch (tag) {
860         case 0x00:    /* Data_Req_UE */
861         case 0x04:    /* Data_Ind_eNodeB */
862             isUplink = TRUE;
863             break;
864
865         case 0x02:    /* Data_Req_eNodeB */
866         case 0x03:    /* Data_Ind_UE */
867             isUplink = FALSE;
868             break;
869
870         default:
871             /* Unexpected opcode tag! */
872             return;
873     }
874
875     /* Skip length */
876     offset += skipASNLength(tvb_get_guint8(tvb, offset));
877
878     /* Get next tag */
879     tag = tvb_get_guint8(tvb, offset++);
880     switch (tag) {
881         case 0x12:    /* UE_Id_LCId */
882
883             /* Dedicated channel info */
884
885             /* Length will fit in one byte here */
886             offset++;
887
888             logicalChannelType = Channel_DCCH;
889
890             /* UEId */
891             proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid, tvb, offset, 2, ENC_BIG_ENDIAN);
892             offset += 2;
893
894             /* Get tag of channel type */
895             tag = tvb_get_guint8(tvb, offset++);
896
897             switch (tag) {
898                 case 0:
899                     offset++;
900                     col_append_fstr(pinfo->cinfo, COL_INFO, " SRB:%u",
901                                     tvb_get_guint8(tvb, offset));
902                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_srbid,
903                                         tvb, offset, 1, ENC_BIG_ENDIAN);
904                     offset++;
905                     break;
906                 case 1:
907                     offset++;
908                     col_append_fstr(pinfo->cinfo, COL_INFO, " DRB:%u",
909                                     tvb_get_guint8(tvb, offset));
910                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_drbid,
911                                         tvb, offset, 1, ENC_BIG_ENDIAN);
912                     offset++;
913                     break;
914
915                 default:
916                     /* Unexpected channel type */
917                     return;
918             }
919             break;
920
921         case 0x1a:     /* Cell_LCId */
922
923             /* Common channel info */
924
925             /* Skip length */
926             offset++;
927
928             /* Cell-id */
929             proto_tree_add_item(tree, hf_catapult_dct2000_lte_cellid,
930                                 tvb, offset, 2, ENC_BIG_ENDIAN);
931             cell_id = tvb_get_ntohs(tvb, offset);
932             offset += 2;
933
934             /* Logical channel type */
935             proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_channel_type,
936                                 tvb, offset, 1, ENC_BIG_ENDIAN);
937             logicalChannelType = (LogicalChannelType)tvb_get_guint8(tvb, offset);
938             offset++;
939
940             /* Won't be seen if RRC decoder is called... */
941             col_append_fstr(pinfo->cinfo, COL_INFO, " cell-id=%u %s",
942                             cell_id,
943                             val_to_str_const(logicalChannelType, rlc_logical_channel_vals,
944                                              "UNKNOWN-CHANNEL"));
945
946
947             switch (logicalChannelType) {
948                 case Channel_BCCH:
949                     /* Skip length */
950                     offset++;
951
952                     /* Transport channel type */
953                     bcch_transport = tvb_get_guint8(tvb, offset);
954                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_bcch_transport,
955                                         tvb, offset, 1, ENC_BIG_ENDIAN);
956                     offset++;
957                     break;
958
959                 case Channel_CCCH:
960                     /* Skip length */
961                     offset++;
962
963                     /* UEId */
964                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
965                                         tvb, offset, 2, ENC_BIG_ENDIAN);
966                     offset += 2;
967                     break;
968
969                 default:
970                     break;
971             }
972             break;
973
974         default:
975             /* Unexpected tag */
976             return;
977     }
978
979     /* Data tag should follow */
980     tag = tvb_get_guint8(tvb, offset++);
981     if (tag != 0xaa) {
982         return;
983     }
984
985     /* Skip length */
986     offset += skipASNLength(tvb_get_guint8(tvb, offset));
987
988     /* Look up dissector handle corresponding to direction and channel type */
989     if (isUplink) {
990
991         /* Uplink channel types */
992         switch (logicalChannelType) {
993             case Channel_DCCH:
994                 protocol_handle = find_dissector("lte_rrc.ul_dcch");
995                 break;
996             case Channel_CCCH:
997                 protocol_handle = find_dissector("lte_rrc.ul_ccch");
998                 break;
999
1000             default:
1001                 /* Unknown Uplink channel type */
1002                 break;
1003         }
1004     } else {
1005
1006         /* Downlink channel types */
1007         switch (logicalChannelType) {
1008             case Channel_DCCH:
1009                 protocol_handle = find_dissector("lte_rrc.dl_dcch");
1010                 break;
1011             case Channel_CCCH:
1012                 protocol_handle = find_dissector("lte_rrc.dl_ccch");
1013                 break;
1014             case Channel_PCCH:
1015                 protocol_handle = find_dissector("lte_rrc.pcch");
1016                 break;
1017             case Channel_BCCH:
1018                 if (bcch_transport == 1) {
1019                     protocol_handle = find_dissector("lte_rrc.bcch_bch");
1020                 }
1021                 else {
1022                     protocol_handle = find_dissector("lte_rrc.bcch_dl_sch");
1023                 }
1024                 break;
1025
1026             default:
1027                 /* Unknown Downlink channel type */
1028                 break;
1029         }
1030     }
1031
1032     /* Send to RRC dissector, if got here, have sub-dissector and some data left */
1033     if ((protocol_handle != NULL) && (tvb_length_remaining(tvb, offset) > 0)) {
1034         rrc_tvb = tvb_new_subset(tvb, offset, -1, tvb_length_remaining(tvb, offset));
1035         call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree, NULL);
1036     }
1037 }
1038
1039
1040 /* Dissect an CCPRI LTE frame by first parsing the header entries then passing
1041    the data to the CPRI C&M dissector */
1042 static void dissect_ccpri_lte(tvbuff_t *tvb, gint offset,
1043                               packet_info *pinfo, proto_tree *tree)
1044 {
1045     guint8              opcode;
1046     guint8              tag;
1047     tvbuff_t           *ccpri_tvb;
1048     dissector_handle_t  protocol_handle = 0;
1049     guint16             length;
1050
1051     /* Top-level opcode */
1052     proto_tree_add_item(tree, hf_catapult_dct2000_lte_ccpri_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
1053     opcode = tvb_get_guint8(tvb, offset++);
1054
1055     /* Skip 2-byte length field */
1056     offset += 2;
1057
1058     /* Cell-id */
1059     proto_tree_add_item(tree, hf_catapult_dct2000_lte_cellid,
1060                         tvb, offset, 2, ENC_BIG_ENDIAN);
1061     offset += 2;
1062
1063     /* Status (ind only) */
1064     if (opcode == 2) {
1065         proto_item *ti;
1066         guint8 status = tvb_get_guint8(tvb, offset);
1067         ti = proto_tree_add_item(tree, hf_catapult_dct2000_lte_ccpri_status,
1068                                  tvb, offset, 1, ENC_BIG_ENDIAN);
1069         offset++;
1070
1071         if (status != 0) {
1072             expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_ERROR,
1073                                    "CCPRI Indication has error status");
1074
1075         }
1076     }
1077
1078     /* Channel ID */
1079     proto_tree_add_item(tree, hf_catapult_dct2000_lte_ccpri_channel,
1080                         tvb, offset, 1, ENC_BIG_ENDIAN);
1081     offset++;
1082
1083     /* Data tag must follow */
1084     tag = tvb_get_guint8(tvb, offset++);
1085     if (tag != 2) {
1086         return;
1087     }
1088
1089     /* Skip length */
1090     length = tvb_get_ntohs(tvb, offset);
1091     offset += 2;
1092
1093     /* Send remainder to lapb dissector (lapb needs patch with preference
1094        set to call cpri C&M dissector instead of X.25) */
1095     protocol_handle = find_dissector("lapb");
1096     if ((protocol_handle != NULL) && (tvb_length_remaining(tvb, offset) > 0)) {
1097         ccpri_tvb = tvb_new_subset(tvb, offset, length, length);
1098         call_dissector_only(protocol_handle, ccpri_tvb, pinfo, tree, NULL);
1099     }
1100 }
1101
1102
1103
1104
1105 /* Dissect a PDCP LTE frame by first parsing the RLCPrim header then passing
1106    the data to the PDCP LTE dissector */
1107 static void dissect_pdcp_lte(tvbuff_t *tvb, gint offset,
1108                              packet_info *pinfo, proto_tree *tree)
1109 {
1110     guint8                opcode;
1111     guint8                tag;
1112     struct pdcp_lte_info *p_pdcp_lte_info = NULL;
1113     tvbuff_t             *pdcp_lte_tvb;
1114     guint16               ueid;
1115     guint8                channelId;
1116
1117     /* Look this up so can update channel info */
1118     p_pdcp_lte_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
1119     if (p_pdcp_lte_info == NULL) {
1120         /* This really should be set...can't dissect anything without it */
1121         return;
1122     }
1123
1124     /* Top-level opcode */
1125     opcode = tvb_get_guint8(tvb, offset);
1126     if (tree) {
1127         proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_op, tvb, offset, 1, ENC_BIG_ENDIAN);
1128     }
1129     offset++;
1130
1131     col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(opcode, rlc_op_vals, "Unknown"));
1132
1133     /* Assume UE side, so REQ is UL, IND is DL */
1134     switch (opcode) {
1135        case RLC_AM_DATA_REQ:
1136        case RLC_UM_DATA_REQ:
1137        case RLC_TR_DATA_REQ:
1138            p_pdcp_lte_info->direction = DIRECTION_UPLINK;
1139            break;
1140
1141        default:
1142            p_pdcp_lte_info->direction = DIRECTION_DOWNLINK;
1143     }
1144
1145     /* Parse header */
1146     switch (opcode) {
1147         case RLC_AM_DATA_REQ:
1148         case RLC_AM_DATA_IND:
1149         case RLC_UM_DATA_REQ:
1150         case RLC_UM_DATA_IND:
1151         case RLC_TR_DATA_REQ:
1152         case RLC_TR_DATA_IND:
1153
1154             /* Get next tag */
1155             tag = tvb_get_guint8(tvb, offset++);
1156             switch (tag) {
1157                 case 0x10:    /* UE_Id_LCId */
1158
1159                     /* Dedicated channel info */
1160
1161                     /* Length will fit in one byte here */
1162                     offset++;
1163
1164                     p_pdcp_lte_info->channelType = Channel_DCCH;
1165
1166                     /* UEId */
1167                     ueid = tvb_get_ntohs(tvb, offset);
1168                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid, tvb, offset, 2, ENC_BIG_ENDIAN);
1169                     col_append_fstr(pinfo->cinfo, COL_INFO,
1170                                     " UEId=%u", ueid);
1171                     p_pdcp_lte_info->ueid = ueid;
1172                     offset += 2;
1173
1174                     /* Get tag of channel type */
1175                     tag = tvb_get_guint8(tvb, offset++);
1176
1177                     switch (tag) {
1178                         case 0:
1179                             offset++;
1180                             channelId = tvb_get_guint8(tvb, offset);
1181                             col_append_fstr(pinfo->cinfo, COL_INFO, " SRB:%u",
1182                                             channelId);
1183                             proto_tree_add_item(tree, hf_catapult_dct2000_lte_srbid,
1184                                                 tvb, offset++, 1, ENC_BIG_ENDIAN);
1185                             p_pdcp_lte_info->channelId = channelId;
1186                             break;
1187                         case 1:
1188                             offset++;
1189                             channelId = tvb_get_guint8(tvb, offset);
1190                             col_append_fstr(pinfo->cinfo, COL_INFO, " DRB:%u",
1191                                             channelId);
1192                             proto_tree_add_item(tree, hf_catapult_dct2000_lte_drbid,
1193                                                 tvb, offset++, 1, ENC_BIG_ENDIAN);
1194                             p_pdcp_lte_info->channelId = channelId;
1195                             break;
1196
1197                         default:
1198                             /* Unexpected channel type */
1199                             return;
1200                     }
1201                     break;
1202
1203                 case 0x1a:     /* Cell_LCId */
1204
1205                     /* Common channel info */
1206
1207                     /* Skip length */
1208                     offset++;
1209
1210                     /* Cell-id */
1211                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_cellid,
1212                                         tvb, offset, 2, ENC_BIG_ENDIAN);
1213                     offset += 2;
1214
1215                     /* Logical channel type */
1216                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_channel_type,
1217                                         tvb, offset, 1, ENC_BIG_ENDIAN);
1218                     p_pdcp_lte_info->channelType = tvb_get_guint8(tvb, offset++);
1219                     col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
1220                                     val_to_str_const(p_pdcp_lte_info->channelType, rlc_logical_channel_vals,
1221                                                      "UNKNOWN-CHANNEL"));
1222
1223                     switch (p_pdcp_lte_info->channelType) {
1224                         case Channel_BCCH:
1225                             /* Skip length */
1226                             offset++;
1227
1228                             /* Transport channel type */
1229                             p_pdcp_lte_info->BCCHTransport = tvb_get_guint8(tvb, offset);
1230                             proto_tree_add_item(tree, hf_catapult_dct2000_lte_bcch_transport,
1231                                                 tvb, offset, 1, ENC_BIG_ENDIAN);
1232                             offset++;
1233                             break;
1234
1235                         case Channel_CCCH:
1236                             /* Skip length */
1237                             offset++;
1238
1239                             /* UEId */
1240                             proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
1241                                                 tvb, offset, 2, ENC_BIG_ENDIAN);
1242                             ueid = tvb_get_ntohs(tvb, offset);
1243                             offset += 2;
1244
1245                             col_append_fstr(pinfo->cinfo, COL_INFO, " UEId=%u", ueid);
1246                             break;
1247
1248                         default:
1249                             break;
1250                     }
1251                     break;
1252
1253                 default:
1254                     /* Unexpected tag */
1255                     return;
1256             }
1257
1258             /* Other optional fields may follow */
1259             tag = tvb_get_guint8(tvb, offset++);
1260             while ((tag != 0x41) && (tvb_length_remaining(tvb, offset) > 2)) {
1261
1262                 if (tag == 0x35) {
1263                     /* This is MUI */
1264                     offset++;
1265                     proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_mui,
1266                                         tvb, offset, 2, ENC_BIG_ENDIAN);
1267                     offset += 2;
1268
1269                     /* CNF follows MUI in AM */
1270                     if ((opcode == RLC_AM_DATA_REQ) || (opcode == RLC_AM_DATA_IND)) {
1271                         proto_tree_add_boolean(tree, hf_catapult_dct2000_lte_rlc_cnf,
1272                                                tvb, offset, 1, tvb_get_guint8(tvb, offset));
1273                         offset++;
1274                     }
1275                 }
1276                 else if (tag == 0x45) {
1277                     /* Discard Req */
1278                     offset++;
1279                     proto_tree_add_boolean(tree, hf_catapult_dct2000_lte_rlc_discard_req,
1280                                            tvb, offset, 1, tvb_get_guint8(tvb, offset));
1281                     offset++;
1282                 }
1283
1284                 tag = tvb_get_guint8(tvb, offset++);
1285             }
1286
1287
1288             /********************************/
1289             /* Should be at data tag now    */
1290
1291             /* Call PDCP LTE dissector */
1292             pdcp_lte_tvb = tvb_new_subset(tvb, offset, -1, tvb_length_remaining(tvb, offset));
1293             call_dissector_only(pdcp_lte_handle, pdcp_lte_tvb, pinfo, tree, NULL);
1294
1295             break;
1296
1297         default:
1298             return;
1299     }
1300 }
1301
1302
1303
1304
1305
1306 /* Look up dissector by protocol name.  Fix up known name mis-matches.
1307    This includes exact matches and prefixes (e.g. "diameter_rx" -> "diameter") */
1308 static dissector_handle_t look_for_dissector(const char *protocol_name)
1309 {
1310     /* Use known aliases and protocol name prefixes */
1311     if (strcmp(protocol_name, "tbcp") == 0) {
1312         return find_dissector("rtcp");
1313     }
1314     else
1315     if (strncmp(protocol_name, "diameter", strlen("diameter")) == 0) {
1316         return find_dissector("diameter");
1317     }
1318     else
1319     if ((strcmp(protocol_name, "xcap_caps") == 0) ||
1320         (strcmp(protocol_name, "soap") == 0) ||
1321         (strcmp(protocol_name, "mm1") == 0) ||
1322         (strcmp(protocol_name, "mm3") == 0) ||
1323         (strcmp(protocol_name, "mm7") == 0)) {
1324
1325         return find_dissector("http");
1326     }
1327     else
1328     if ((strcmp(protocol_name, "fp") == 0) ||
1329         (strncmp(protocol_name, "fp_r", 4) == 0) ||
1330         (strcmp(protocol_name, "fpiur_r5") == 0)) {
1331
1332         return find_dissector("fp");
1333     }
1334     else
1335     if ((strcmp(protocol_name, "iuup_rtp_r5") == 0) ||
1336         (strcmp(protocol_name, "iuup_rtp_r6") == 0)) {
1337
1338         return find_dissector("rtp");
1339     }
1340     else
1341     if (strcmp(protocol_name, "sipt") == 0) {
1342         return find_dissector("sip");
1343     }
1344     else
1345     if (strncmp(protocol_name, "nbap_sctp", strlen("nbap_sctp")) == 0) {
1346         return find_dissector("nbap");
1347     }
1348     else
1349     if (strncmp(protocol_name, "gtp", strlen("gtp")) == 0) {
1350         return find_dissector("gtp");
1351     }
1352     else
1353     if (strcmp(protocol_name, "dhcpv4") == 0) {
1354         return find_dissector("bootp");
1355     }
1356     else
1357     if (strcmp(protocol_name, "wimax") == 0) {
1358         return find_dissector("wimaxasncp");
1359     }
1360     else
1361     if (strncmp(protocol_name, "sabp", strlen("sabp")) == 0) {
1362         return find_dissector("sabp");
1363     }
1364     else
1365     if (strcmp(protocol_name, "wtp") == 0) {
1366         return find_dissector("wtp-udp");
1367     }
1368     else
1369     /* Only match with s1ap if preference turned on */
1370     if (catapult_dct2000_dissect_lte_s1ap &&
1371         strncmp(protocol_name, "s1ap", strlen("s1ap")) == 0) {
1372
1373         return find_dissector("s1ap");
1374     }
1375     else
1376     /* Always try lookup for now */
1377     if ((strncmp(protocol_name, "x2ap_r8_lte", strlen("x2ap_r8_lte")) == 0) ||
1378         (strncmp(protocol_name, "x2ap_r9_lte", strlen("x2ap_r9_lte")) == 0)) {
1379
1380         return find_dissector("x2ap");
1381     }
1382
1383     else
1384     if ((strcmp(protocol_name, "gtpv2_r8_lte") == 0) ||
1385         (strcmp(protocol_name, "gtpv2_r9_lte") == 0)) {
1386         return find_dissector("gtpv2");
1387     }
1388
1389
1390     /* Try for an exact match */
1391     else {
1392         return find_dissector(protocol_name);
1393     }
1394 }
1395
1396
1397 /* Populate outhdr_values array with numbers found in outhdr_string */
1398 static void parse_outhdr_string(const guchar *outhdr_string, gint outhdr_string_len)
1399 {
1400     int   n                 = 0;
1401
1402     /* Populate values array */
1403     for (outhdr_values_found=0; outhdr_values_found < MAX_OUTHDR_VALUES; ) {
1404
1405         guint  digit_array[MAX_OUTHDR_VALUES];
1406         guint  number_digits = 0;
1407
1408         guint   number = 0;
1409         guint   multiplier = 1;
1410         guint   d;
1411
1412         /* Find digits */
1413         for ( ; n < outhdr_string_len; n++) {
1414             if (!isdigit(outhdr_string[n])) {
1415                 break;
1416             }
1417             else {
1418                 digit_array[number_digits++] = outhdr_string[n] - '0';
1419             }
1420         }
1421
1422         if (number_digits == 0) {
1423             /* No more numbers left */
1424             break;
1425         }
1426
1427         /* Convert digits into value (much faster than format_text() + atoi()) */
1428         for (d=number_digits; d > 0; d--) {
1429             number += ((digit_array[d-1]) * multiplier);
1430             multiplier *= 10;
1431         }
1432         outhdr_values[outhdr_values_found++] = number;
1433
1434         /* Skip comma */
1435         n++;
1436     }
1437 }
1438
1439
1440
1441 /* Fill in an FP packet info struct and attach it to the packet for the FP
1442    dissector to use */
1443 static void attach_fp_info(packet_info *pinfo, gboolean received, const char *protocol_name, int variant)
1444 {
1445     int  i=0;
1446     int  chan;
1447     int  tf_start, num_chans_start;
1448     gint node_type;
1449     int  calculated_variant;
1450
1451     /* Only need to set info once per session. */
1452     struct fp_info *p_fp_info = p_get_proto_data(pinfo->fd, proto_fp);
1453     if (p_fp_info != NULL) {
1454         return;
1455     }
1456
1457     /* Allocate struct */
1458     p_fp_info = se_alloc0(sizeof(struct fp_info));
1459
1460     /* Check that the number of outhdr values looks sensible */
1461     if (((strcmp(protocol_name, "fpiur_r5") == 0) && (outhdr_values_found != 2)) ||
1462         (outhdr_values_found < 5)) {
1463
1464         return;
1465     }
1466
1467     /* 3gpp release (99, 4, 5, 6, 7) */
1468     if (strcmp(protocol_name, "fp") == 0) {
1469         p_fp_info->release = 99;
1470     }
1471     else if (strcmp(protocol_name, "fp_r4") == 0) {
1472         p_fp_info->release = 4;
1473     }
1474     else if (strcmp(protocol_name, "fp_r5") == 0) {
1475         p_fp_info->release = 5;
1476     }
1477     else if (strcmp(protocol_name, "fp_r6") == 0) {
1478         p_fp_info->release = 6;
1479     }
1480     else if (strcmp(protocol_name, "fp_r7") == 0) {
1481         p_fp_info->release = 7;
1482     }
1483     else if (strcmp(protocol_name, "fp_r8") == 0) {
1484         p_fp_info->release = 8;
1485     }
1486     else if (strcmp(protocol_name, "fpiur_r5") == 0) {
1487         p_fp_info->release = 5;
1488     }
1489     else {
1490         /* Really shouldn't get here */
1491         DISSECTOR_ASSERT_NOT_REACHED();
1492         return;
1493     }
1494
1495     /* Release date is derived from variant number */
1496     /* Only R6 sub-versions currently influence format within a release */
1497     switch (p_fp_info->release) {
1498         case 6:
1499             if (variant < 256) {
1500                 calculated_variant = variant;
1501             }
1502             else {
1503                 calculated_variant = variant / 256;
1504             }
1505
1506             switch (calculated_variant) {
1507                 case 1:
1508                     p_fp_info->release_year = 2005;
1509                     p_fp_info->release_month = 6;
1510                     break;
1511                 case 2:
1512                     p_fp_info->release_year = 2005;
1513                     p_fp_info->release_month = 9;
1514                     break;
1515                 case 3:
1516                 default:
1517                     p_fp_info->release_year = 2006;
1518                     p_fp_info->release_month = 3;
1519                     break;
1520             }
1521             break;
1522         case 7:
1523             p_fp_info->release_year = 2008;
1524             p_fp_info->release_month = 3;
1525             break;
1526
1527         case 8:
1528             p_fp_info->release_year = 2010;
1529             p_fp_info->release_month = 6;
1530             break;
1531
1532
1533         default:
1534             p_fp_info->release_year = 0;
1535             p_fp_info->release_month = 0;
1536     }
1537
1538
1539     /* Channel type */
1540     p_fp_info->channel = outhdr_values[i++];
1541     /* Sad hack until this value is filled in properly */
1542     if (p_fp_info->channel == 0) {
1543         p_fp_info->channel = CHANNEL_DCH;
1544     }
1545
1546     /* Derive direction from node type/side */
1547     node_type = outhdr_values[i++];
1548     p_fp_info->is_uplink = (( received  && (node_type == 2)) ||
1549                             (!received  && (node_type == 1)));
1550
1551     /* Division type introduced for R7 */
1552     if ((p_fp_info->release == 7) ||
1553         (p_fp_info->release == 8)) {
1554         p_fp_info->division = outhdr_values[i++];
1555     }
1556
1557     /* HS-DSCH config */
1558     if (p_fp_info->channel == CHANNEL_HSDSCH) {
1559         if ((p_fp_info->release == 7) ||
1560             (p_fp_info->release == 8)) {
1561             /* Entity (MAC-hs or MAC-ehs) used */
1562             if (outhdr_values[i++]) {
1563                 p_fp_info->hsdsch_entity = ehs;
1564             }
1565         }
1566         else {
1567             /* This is the pre-R7 default */
1568             p_fp_info->hsdsch_entity = hs;
1569         }
1570     }
1571
1572
1573     /* IUR only uses the above... */
1574     if (strcmp(protocol_name, "fpiur_r5") == 0) {
1575         /* Store info in packet */
1576         p_fp_info->iface_type = IuR_Interface;
1577         p_add_proto_data(pinfo->fd, proto_fp, p_fp_info);
1578         return;
1579     }
1580
1581     /* DCH CRC present... */
1582     p_fp_info->dch_crc_present = outhdr_values[i++];
1583
1584     /* ... but don't trust for edch */
1585     if (p_fp_info->channel == CHANNEL_EDCH) {
1586         p_fp_info->dch_crc_present = 2; /* unknown */
1587     }
1588
1589     /* How many paging indications (if PCH data) */
1590     p_fp_info->paging_indications = outhdr_values[i++];
1591
1592     /* Number of channels (for coordinated channels) */
1593     p_fp_info->num_chans = outhdr_values[i++];
1594
1595     /* EDCH-Common is always T2 */
1596     if (p_fp_info->channel == CHANNEL_EDCH_COMMON) {
1597         p_fp_info->edch_type = 1;
1598     }
1599
1600     if (p_fp_info->channel != CHANNEL_EDCH) {
1601         /* TF size for each channel */
1602         tf_start = i;
1603         for (chan=0; chan < p_fp_info->num_chans; chan++) {
1604             p_fp_info->chan_tf_size[chan] = outhdr_values[tf_start+chan];
1605         }
1606
1607         /* Number of TBs for each channel */
1608         num_chans_start = tf_start + p_fp_info->num_chans;
1609         for (chan=0; chan < p_fp_info->num_chans; chan++) {
1610             p_fp_info->chan_num_tbs[chan] = outhdr_values[num_chans_start+chan];
1611         }
1612     }
1613     /* EDCH info */
1614     else {
1615         int n;
1616
1617         p_fp_info->no_ddi_entries = outhdr_values[i++];
1618
1619         /* DDI values */
1620         for (n=0; n < p_fp_info->no_ddi_entries; n++) {
1621             p_fp_info->edch_ddi[n] = outhdr_values[i++];
1622         }
1623
1624         /* Corresponding MAC-d sizes */
1625         for (n=0; n < p_fp_info->no_ddi_entries; n++) {
1626             p_fp_info->edch_macd_pdu_size[n] = outhdr_values[i++];
1627         }
1628
1629         if (strcmp(protocol_name, "fp_r8") == 0) {
1630             p_fp_info->edch_type = outhdr_values[i];
1631         }
1632         else {
1633             p_fp_info->edch_type = 0;
1634         }
1635     }
1636
1637     /* Interface must be IuB */
1638     p_fp_info->iface_type = IuB_Interface;
1639
1640     /* Store info in packet */
1641     p_add_proto_data(pinfo->fd, proto_fp, p_fp_info);
1642 }
1643
1644
1645 /* Fill in an RLC packet info struct and attach it to the packet for the RLC
1646    dissector to use */
1647 static void attach_rlc_info(packet_info *pinfo, guint32 urnti, guint8 rbid, gboolean is_sent)
1648 {
1649     /* Only need to set info once per session. */
1650     struct fp_info  *p_fp_info;
1651     struct rlc_info *p_rlc_info = p_get_proto_data(pinfo->fd, proto_rlc);
1652
1653     if (p_rlc_info != NULL) {
1654         return;
1655     }
1656
1657     /* Check that the number of outhdr values looks correct */
1658     if (outhdr_values_found != 2) {
1659         return;
1660     }
1661
1662     /* Allocate structs */
1663     p_rlc_info = se_alloc0(sizeof(struct rlc_info));
1664     p_fp_info = se_alloc0(sizeof(struct fp_info));
1665
1666     /* Fill in struct fields for first (only) PDU in this frame */
1667
1668     /* Urnti.  Just use UEId */
1669     p_rlc_info->urnti[0] = urnti;
1670
1671     /* ciphered (off by default) */
1672     p_rlc_info->ciphered[0] = FALSE;
1673
1674     /* deciphered (off by default) */
1675     p_rlc_info->deciphered[0] = FALSE;
1676
1677     /* Mode. */
1678     switch (outhdr_values[1]) {
1679         case 1:
1680             p_rlc_info->mode[0] = RLC_TM;
1681             break;
1682         case 2:
1683             p_rlc_info->mode[0] = RLC_UM;
1684             break;
1685         case 3:
1686             p_rlc_info->mode[0] = RLC_AM;
1687             break;
1688         case 4:
1689             p_rlc_info->mode[0] = RLC_UM;
1690             p_rlc_info->ciphered[0] = TRUE;
1691             break;
1692         case 5:
1693             p_rlc_info->mode[0] = RLC_AM;
1694             p_rlc_info->ciphered[0] = TRUE;
1695             break;
1696         default:
1697             return;
1698     }
1699
1700     /* rbid. TODO: does this need conversion? */
1701     p_rlc_info->rbid[0] = rbid;
1702
1703     /* li_size */
1704     p_rlc_info->li_size[0] = outhdr_values[0];
1705
1706     /* Store info in packet */
1707     p_add_proto_data(pinfo->fd, proto_rlc, p_rlc_info);
1708
1709     /* Also store minimal FP info consulted by RLC dissector
1710        TODO: Don't really know direction, but use S/R flag to make
1711        logs in same context consistent. Will be correct for NodeB logs,
1712        but RLC dissector seems to not use anyway... */
1713     p_fp_info->is_uplink = is_sent;
1714     p_fp_info->cur_tb = 0; /* Always the first/only one */
1715     p_add_proto_data(pinfo->fd, proto_fp, p_fp_info);
1716 }
1717
1718
1719 /* Fill in a MAC LTE packet info struct and attach it to the packet for that
1720    dissector to use */
1721 static void attach_mac_lte_info(packet_info *pinfo)
1722 {
1723     struct mac_lte_info *p_mac_lte_info;
1724     unsigned int         i = 0;
1725
1726     /* Only need to set info once per session. */
1727     p_mac_lte_info = get_mac_lte_proto_data(pinfo);
1728     if (p_mac_lte_info != NULL) {
1729         return;
1730     }
1731
1732     /* Allocate & zero struct */
1733     p_mac_lte_info = se_alloc0(sizeof(struct mac_lte_info));
1734
1735     /* Populate the struct from outhdr values */
1736     p_mac_lte_info->crcStatusValid = FALSE;  /* not set yet */
1737
1738     p_mac_lte_info->radioType = outhdr_values[i++] + 1;
1739     p_mac_lte_info->rntiType = outhdr_values[i++];
1740     p_mac_lte_info->direction = outhdr_values[i++];
1741     /* Set these extra PHY present flags to FALSE by default */
1742     if (p_mac_lte_info->direction == DIRECTION_UPLINK) {
1743         p_mac_lte_info->detailed_phy_info.ul_info.present = FALSE;
1744     }
1745     else {
1746         p_mac_lte_info->detailed_phy_info.dl_info.present = FALSE;
1747     }
1748
1749     p_mac_lte_info->subframeNumber = outhdr_values[i++];
1750     p_mac_lte_info->isPredefinedData = outhdr_values[i++];
1751     p_mac_lte_info->rnti = outhdr_values[i++];
1752     p_mac_lte_info->ueid = outhdr_values[i++];
1753     p_mac_lte_info->length = outhdr_values[i++];
1754     if (outhdr_values_found > 8) {
1755         p_mac_lte_info->reTxCount = outhdr_values[i++];
1756     }
1757     if (outhdr_values_found == 10) {
1758         /* CRC only valid for Downlink */
1759         if (p_mac_lte_info->direction == DIRECTION_DOWNLINK) {
1760             p_mac_lte_info->crcStatusValid = TRUE;
1761             p_mac_lte_info->detailed_phy_info.dl_info.crc_status = outhdr_values[i++];
1762         }
1763         else {
1764             i++;
1765         }
1766     }
1767
1768     p_mac_lte_info->dl_retx = dl_retx_unknown;
1769
1770     if (outhdr_values_found > 10) {
1771         /* Extra PHY parameters */
1772         if (p_mac_lte_info->direction == DIRECTION_DOWNLINK) {
1773             p_mac_lte_info->detailed_phy_info.dl_info.present = outhdr_values[i++];
1774             p_mac_lte_info->detailed_phy_info.dl_info.dci_format = outhdr_values[i++];
1775             p_mac_lte_info->detailed_phy_info.dl_info.resource_allocation_type = outhdr_values[i++];
1776             p_mac_lte_info->detailed_phy_info.dl_info.aggregation_level = outhdr_values[i++];
1777             p_mac_lte_info->detailed_phy_info.dl_info.mcs_index = outhdr_values[i++];
1778             p_mac_lte_info->detailed_phy_info.dl_info.redundancy_version_index = outhdr_values[i++];
1779             if (outhdr_values[i++]) {
1780                 p_mac_lte_info->dl_retx = dl_retx_yes;
1781             }
1782             else {
1783                 p_mac_lte_info->dl_retx = dl_retx_no;
1784             }
1785             p_mac_lte_info->detailed_phy_info.dl_info.resource_block_length = outhdr_values[i++];
1786             p_mac_lte_info->crcStatusValid = TRUE;
1787             p_mac_lte_info->detailed_phy_info.dl_info.crc_status = outhdr_values[i++];
1788             if (outhdr_values_found > 18) {
1789                 p_mac_lte_info->detailed_phy_info.dl_info.harq_id = outhdr_values[i++];
1790                 p_mac_lte_info->detailed_phy_info.dl_info.ndi = outhdr_values[i++];
1791             }
1792             if (outhdr_values_found > 20) {
1793                 p_mac_lte_info->detailed_phy_info.dl_info.transport_block = outhdr_values[i++];
1794             }
1795         }
1796         else {
1797             /* Uplink */
1798             p_mac_lte_info->detailed_phy_info.ul_info.present = outhdr_values[i++];
1799             p_mac_lte_info->detailed_phy_info.ul_info.modulation_type = outhdr_values[i++];
1800             p_mac_lte_info->detailed_phy_info.ul_info.tbs_index = outhdr_values[i++];
1801             p_mac_lte_info->detailed_phy_info.ul_info.resource_block_length = outhdr_values[i++];
1802             p_mac_lte_info->detailed_phy_info.ul_info.resource_block_start = outhdr_values[i++];
1803             /* Skip retx flag */
1804             i++;
1805
1806             if (outhdr_values_found == 16) {
1807                 p_mac_lte_info->subframeNumberOfGrantPresent = TRUE;
1808                 p_mac_lte_info->subframeNumberOfGrant = outhdr_values[i++];
1809             }
1810             if (outhdr_values_found > 16) {
1811                 p_mac_lte_info->detailed_phy_info.ul_info.harq_id = outhdr_values[i++];
1812                 p_mac_lte_info->detailed_phy_info.ul_info.ndi = outhdr_values[i++];
1813
1814                 p_mac_lte_info->subframeNumberOfGrantPresent = TRUE;
1815                 p_mac_lte_info->subframeNumberOfGrant = outhdr_values[i++];
1816             }
1817         }
1818     }
1819
1820     /* System frame number */
1821     if (i < outhdr_values_found) {
1822         p_mac_lte_info->sysframeNumber = outhdr_values[i++];
1823     }
1824
1825     if ((p_mac_lte_info->direction == DIRECTION_UPLINK) &&
1826         (i < outhdr_values_found)) {
1827
1828         p_mac_lte_info->isPHICHNACK = outhdr_values[i];
1829     }
1830
1831     if (p_mac_lte_info->direction == DIRECTION_UPLINK) {
1832         /* R10 parameter not set yet */
1833         p_mac_lte_info->isExtendedBSRSizes = FALSE;
1834     }
1835
1836     /* Store info in packet */
1837     set_mac_lte_proto_data(pinfo, p_mac_lte_info);
1838 }
1839
1840
1841 /* Fill in a RLC LTE packet info struct and attach it to the packet for that
1842    dissector to use */
1843 static void attach_rlc_lte_info(packet_info *pinfo)
1844 {
1845     struct rlc_lte_info *p_rlc_lte_info;
1846     unsigned int         i = 0;
1847
1848     /* Only need to set info once per session. */
1849     p_rlc_lte_info = p_get_proto_data(pinfo->fd, proto_rlc_lte);
1850     if (p_rlc_lte_info != NULL) {
1851         return;
1852     }
1853
1854     /* Allocate & zero struct */
1855     p_rlc_lte_info = se_alloc0(sizeof(struct rlc_lte_info));
1856
1857     p_rlc_lte_info->rlcMode = outhdr_values[i++];
1858     p_rlc_lte_info->direction = outhdr_values[i++];
1859     p_rlc_lte_info->priority = outhdr_values[i++];
1860     p_rlc_lte_info->UMSequenceNumberLength = outhdr_values[i++];
1861     p_rlc_lte_info->channelId = outhdr_values[i++];
1862     p_rlc_lte_info->channelType = outhdr_values[i++];
1863     p_rlc_lte_info->ueid = outhdr_values[i++];
1864     p_rlc_lte_info->pduLength = outhdr_values[i];
1865
1866     /* Store info in packet */
1867     p_add_proto_data(pinfo->fd, proto_rlc_lte, p_rlc_lte_info);
1868 }
1869
1870 /* Fill in a PDCP LTE packet info struct and attach it to the packet for the PDCP LTE
1871    dissector to use */
1872 static void attach_pdcp_lte_info(packet_info *pinfo)
1873 {
1874     struct pdcp_lte_info *p_pdcp_lte_info;
1875     unsigned int          i = 0;
1876
1877     /* Only need to set info once per session. */
1878     p_pdcp_lte_info = p_get_proto_data(pinfo->fd, proto_pdcp_lte);
1879     if (p_pdcp_lte_info != NULL) {
1880         return;
1881     }
1882
1883     /* Allocate & zero struct */
1884     p_pdcp_lte_info = se_alloc0(sizeof(struct pdcp_lte_info));
1885
1886     p_pdcp_lte_info->no_header_pdu = outhdr_values[i++];
1887     p_pdcp_lte_info->plane = outhdr_values[i++];
1888     if (p_pdcp_lte_info->plane != USER_PLANE) {
1889         p_pdcp_lte_info->plane = SIGNALING_PLANE;
1890     }
1891     p_pdcp_lte_info->seqnum_length = outhdr_values[i++];
1892
1893     p_pdcp_lte_info->rohc_compression = outhdr_values[i++];
1894     p_pdcp_lte_info->rohc_ip_version = outhdr_values[i++];
1895     p_pdcp_lte_info->cid_inclusion_info = outhdr_values[i++];
1896     p_pdcp_lte_info->large_cid_present = outhdr_values[i++];
1897     p_pdcp_lte_info->mode = outhdr_values[i++];
1898     p_pdcp_lte_info->rnd = outhdr_values[i++];
1899     p_pdcp_lte_info->udp_checkum_present = outhdr_values[i++];
1900     p_pdcp_lte_info->profile = outhdr_values[i];
1901
1902     /* Remaining 2 (fixed) fields are ah_length and gre_checksum */
1903
1904     /* Store info in packet */
1905     p_add_proto_data(pinfo->fd, proto_pdcp_lte, p_pdcp_lte_info);
1906 }
1907
1908
1909 /* Attempt to show tty (raw character messages) as text lines. */
1910 static void dissect_tty_lines(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
1911 {
1912     gint        next_offset;
1913     proto_tree *tty_tree;
1914     proto_item *ti;
1915     int         lines = 0;
1916
1917     /* Create tty tree. */
1918     ti = proto_tree_add_item(tree, hf_catapult_dct2000_tty, tvb, offset, -1, ENC_NA);
1919     tty_tree = proto_item_add_subtree(ti, ett_catapult_dct2000_tty);
1920
1921     /* Show the tty lines one at a time. */
1922     while (tvb_reported_length_remaining(tvb, offset) > 0) {
1923         /* Find the end of the line. */
1924         int linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
1925
1926         /* Extract & add the string. */
1927         char *string = (char*)tvb_get_ephemeral_string(tvb, offset, linelen);
1928         if (isascii(string[0])) {
1929             /* If looks printable treat as string... */
1930             proto_tree_add_string_format(tty_tree, hf_catapult_dct2000_tty_line,
1931                                          tvb, offset,
1932                                          linelen, string,
1933                                          "%s", string);
1934         }
1935         else {
1936             /* Otherwise show as $hex */
1937             int n, idx;
1938             char *hex_string;
1939             int tty_string_length = tvb_length_remaining(tvb, offset);
1940             int hex_string_length = 1+(2*tty_string_length)+1;
1941             hex_string = ep_alloc(hex_string_length);
1942
1943             idx = g_snprintf(hex_string, hex_string_length, "$");
1944
1945             /* Write hex out to new string */
1946             for (n=0; n < tty_string_length; n++) {
1947                 idx += g_snprintf(hex_string+idx, 3, "%02x",
1948                                   tvb_get_guint8(tvb, offset+n));
1949             }
1950             string = hex_string;
1951         }
1952         lines++;
1953
1954         /* Show first line in info column */
1955         if (lines == 1) {
1956             col_append_fstr(pinfo->cinfo, COL_INFO, "tty (%s", string);
1957             proto_item_append_text(ti, " (%s)", string);
1958         }
1959
1960         /* Move onto next line. */
1961         offset = next_offset;
1962     }
1963
1964     /* Close off summary of tty message in info column */
1965     if (lines != 0) {
1966         col_append_str(pinfo->cinfo, COL_INFO, (lines > 1) ? "...)" : ")");
1967     }
1968 }
1969
1970
1971 /* Scan the log comment looking for notable out-of-band MAC events that should
1972    be sent to the MAC dissector */
1973 static void check_for_oob_mac_lte_events(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
1974                                          const char *string)
1975 {
1976     guint                number_of_ues;
1977     guint                ueids[MAX_SRs];
1978     guint                rntis[MAX_SRs];
1979     guint                rapid;
1980     guint                rach_attempt_number;
1981     mac_lte_oob_event    oob_event;
1982     struct mac_lte_info *p_mac_lte_info;
1983     tvbuff_t            *mac_lte_tvb = NULL;
1984     guint16              n;
1985
1986     /* Look for strings matching expected formats */
1987     if (sscanf(string, ">> RACH Preamble Request[UE =  %u]    [RAPID =  %u]    [Attempt = %u]",
1988                &ueids[0], &rapid, &rach_attempt_number) == 3) {
1989         oob_event = ltemac_send_preamble;
1990     }
1991     else
1992     if (sscanf(string, ">> Schedule Request[UE =  %u] [RNTI = %u]", &ueids[0], &rntis[0]) == 2) {
1993         /* Older, single SR format */
1994         oob_event = ltemac_send_sr;
1995         number_of_ues = 1;
1996     }
1997     else
1998     if (sscanf(string, ">> Schedule Requests (%u)  [UE=%u][RNTI=%u]",
1999                &number_of_ues, &ueids[0], &rntis[0]) == 3) {
2000         const char *current_position;
2001
2002         /* Newer, multi-UE format */
2003         oob_event = ltemac_send_sr;
2004
2005         /* Parse other ueid/rnti pairs */
2006         number_of_ues = MIN(number_of_ues, MAX_SRs);
2007         if (number_of_ues > 1) {
2008             current_position = string;
2009
2010             for (n=1; n < number_of_ues; n++) {
2011
2012                 /* Find the start of the next entry */
2013                 current_position = strstr(current_position, "] ");
2014                 if (current_position != NULL) {
2015                     current_position += 2;
2016                 }
2017                 else {
2018                     /* This is an error - shouldn't happen */
2019                     return;
2020                 }
2021
2022                 /* Read this entry */
2023                 if (sscanf(current_position, "[UE=%u][RNTI=%u]", &ueids[n], &rntis[n]) != 2) {
2024                     /* Assuming that if we can't read this one there is no point trying others */
2025                     number_of_ues = n;
2026                     break;
2027                 }
2028             }
2029         }
2030     }
2031     else
2032     if (sscanf(string, ">> INFO MAC:    SR failed for UE %u (CRNTI=%u)", &ueids[0], &rntis[0]) == 2) {
2033         oob_event = ltemac_sr_failure;
2034     }
2035     else {
2036         /* No events found */
2037         return;
2038     }
2039
2040     /* We have an event */
2041     /* Only need to set info once per session. */
2042     p_mac_lte_info = get_mac_lte_proto_data(pinfo);
2043     if (p_mac_lte_info == NULL) {
2044
2045         /* Allocate & zero struct */
2046         p_mac_lte_info = se_alloc0(sizeof(struct mac_lte_info));
2047
2048         /* This indicates to MAC dissector that it has an oob event */
2049         p_mac_lte_info->length = 0;
2050
2051         switch (oob_event) {
2052             case ltemac_send_preamble:
2053                 p_mac_lte_info->ueid = ueids[0];
2054                 p_mac_lte_info->rapid = rapid;
2055                 p_mac_lte_info->rach_attempt_number = rach_attempt_number;
2056                 p_mac_lte_info->direction = DIRECTION_UPLINK;
2057                 break;
2058             case ltemac_send_sr:
2059                 for (n=0; n < number_of_ues; n++) {
2060                     p_mac_lte_info->oob_ueid[n] = ueids[n];
2061                     p_mac_lte_info->oob_rnti[n] = rntis[n];
2062                 }
2063                 p_mac_lte_info->number_of_srs = number_of_ues;
2064                 p_mac_lte_info->direction = DIRECTION_UPLINK;
2065                 break;
2066             case ltemac_sr_failure:
2067                 p_mac_lte_info->rnti = rntis[0];
2068                 p_mac_lte_info->ueid = ueids[0];
2069                 p_mac_lte_info->direction = DIRECTION_DOWNLINK;
2070                 break;
2071         }
2072
2073         p_mac_lte_info->radioType = FDD_RADIO; /* TODO: will be the same as rest of log... */
2074         p_mac_lte_info->oob_event = oob_event;
2075
2076         /* Store info in packet */
2077         set_mac_lte_proto_data(pinfo, p_mac_lte_info);
2078     }
2079
2080     /* Call MAC dissector */
2081     mac_lte_tvb = tvb_new_subset(tvb, 0, 0, 0);
2082     call_dissector_only(mac_lte_handle, mac_lte_tvb, pinfo, tree, NULL);
2083 }
2084
2085
2086 /*****************************************/
2087 /* Main dissection function.             */
2088 /*****************************************/
2089 static void
2090 dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2091 {
2092     proto_tree         *dct2000_tree = NULL;
2093     proto_item         *ti           = NULL;
2094     gint                offset       = 0;
2095     gint                context_length;
2096     const char         *context_name;
2097     guint8              port_number;
2098     gint                protocol_length;
2099     gint                timestamp_length;
2100     const char         *timestamp_string;
2101     gint                variant_length;
2102     const char         *variant_string;
2103     gint                outhdr_length;
2104     const char         *outhdr_string;
2105     guint8              direction;
2106     tvbuff_t           *next_tvb;
2107     int                 encap;
2108     dissector_handle_t  protocol_handle = 0;
2109     dissector_handle_t  heur_protocol_handle = 0;
2110     int                 sub_dissector_result = 0;
2111     const char         *protocol_name;
2112     gboolean            is_comment;
2113
2114     /* Set Protocol */
2115     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCT2000");
2116
2117     /* Clear Info */
2118     col_clear(pinfo->cinfo, COL_INFO);
2119
2120     /* Create root (protocol) tree. */
2121     if (tree) {
2122         ti = proto_tree_add_item(tree, proto_catapult_dct2000, tvb, offset, -1, ENC_NA);
2123         dct2000_tree = proto_item_add_subtree(ti, ett_catapult_dct2000);
2124     }
2125
2126     /*********************************************************************/
2127     /* Note that these are the fields of the stub header as written out  */
2128     /* by the wiretap module                                             */
2129
2130     /* Context Name */
2131     context_name = tvb_get_stringz(tvb, offset, &context_length);
2132     if (dct2000_tree) {
2133         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_context, tvb,
2134                             offset, context_length, ENC_ASCII|ENC_NA);
2135     }
2136     offset += context_length;
2137
2138     /* Context port number */
2139     port_number = tvb_get_guint8(tvb, offset);
2140     if (dct2000_tree) {
2141         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_port_number, tvb,
2142                             offset, 1, ENC_BIG_ENDIAN);
2143     }
2144     offset++;
2145
2146     /* Timestamp in file */
2147     timestamp_string = tvb_get_stringz(tvb, offset, &timestamp_length);
2148     if (dct2000_tree) {
2149         /* TODO: this is *very* slow, but float version adds trailing digits when
2150                  displayed as a custom column... */
2151         proto_tree_add_double(dct2000_tree, hf_catapult_dct2000_timestamp, tvb,
2152                               offset, timestamp_length,
2153                               atof(timestamp_string));
2154     }
2155     offset += timestamp_length;
2156
2157
2158     /* DCT2000 protocol name */
2159     protocol_name = tvb_get_stringz(tvb, offset, &protocol_length);
2160     if (dct2000_tree) {
2161         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_protocol, tvb,
2162                             offset, protocol_length, ENC_ASCII|ENC_NA);
2163     }
2164     is_comment = (strcmp(protocol_name, "comment") == 0);
2165     offset += protocol_length;
2166
2167
2168     /* Protocol Variant */
2169     variant_string = tvb_get_stringz(tvb, offset, &variant_length);
2170     if (!is_comment) {
2171         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_variant, tvb,
2172                             offset, variant_length, ENC_ASCII|ENC_NA);
2173     }
2174     offset += variant_length;
2175
2176     /* Outhdr (shown as string) */
2177     outhdr_string = tvb_get_stringz(tvb, offset, &outhdr_length);
2178     if (!is_comment && (outhdr_length > 1)) {
2179         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_outhdr, tvb,
2180                             offset, outhdr_length, ENC_ASCII|ENC_NA);
2181     }
2182     offset += outhdr_length;
2183
2184
2185     /* Direction */
2186     direction = tvb_get_guint8(tvb, offset);
2187     if (dct2000_tree) {
2188         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_direction, tvb,
2189                             offset, 1, ENC_BIG_ENDIAN);
2190     }
2191     offset++;
2192
2193     /* Read frame encapsulation set by wiretap */
2194     if (!is_comment) {
2195         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_encap, tvb, offset, 1, ENC_BIG_ENDIAN);
2196     }
2197     encap = tvb_get_guint8(tvb, offset);
2198     offset++;
2199
2200     /* Add useful details to protocol tree label */
2201     proto_item_append_text(ti, "   context=%s.%u   t=%s   %c   prot=%s (v=%s)",
2202                            context_name,
2203                            port_number,
2204                            timestamp_string,
2205                            (direction == 0) ? 'S' : 'R',
2206                            protocol_name,
2207                            variant_string);
2208
2209
2210
2211     /* FP protocols need info from outhdr attached */
2212     if ((strcmp(protocol_name, "fp") == 0) ||
2213         (strncmp(protocol_name, "fp_r", 4) == 0) ||
2214         (strcmp(protocol_name, "fpiur_r5") == 0)) {
2215
2216         parse_outhdr_string(outhdr_string, outhdr_length);
2217         attach_fp_info(pinfo, direction, protocol_name, atoi(variant_string));
2218     }
2219
2220     /* RLC protocols need info from outhdr attached */
2221     else if ((strcmp(protocol_name, "rlc") == 0) ||
2222              (strcmp(protocol_name, "rlc_r4") == 0) ||
2223              (strcmp(protocol_name, "rlc_r5") == 0) ||
2224              (strcmp(protocol_name, "rlc_r6") == 0) ||
2225              (strcmp(protocol_name, "rlc_r7") == 0) ||
2226              (strcmp(protocol_name, "rlc_r8") == 0) ||
2227              (strcmp(protocol_name, "rlc_r9") == 0)) {
2228
2229         parse_outhdr_string(outhdr_string, outhdr_length);
2230         /* Can't attach info yet.  Need combination of outheader values
2231            and fields parsed from primitive header... */
2232     }
2233
2234     /* LTE MAC needs info attached */
2235     else if ((strcmp(protocol_name, "mac_r8_lte") == 0) ||
2236              (strcmp(protocol_name, "mac_r9_lte") == 0)) {
2237         parse_outhdr_string(outhdr_string, outhdr_length);
2238         attach_mac_lte_info(pinfo);
2239     }
2240
2241     /* LTE RLC needs info attached */
2242     else if ((strcmp(protocol_name, "rlc_r8_lte") == 0) ||
2243              (strcmp(protocol_name, "rlc_r9_lte") == 0)) {
2244         parse_outhdr_string(outhdr_string, outhdr_length);
2245         attach_rlc_lte_info(pinfo);
2246     }
2247
2248     /* LTE PDCP needs info attached */
2249     else if ((strcmp(protocol_name, "pdcp_r8_lte") == 0) ||
2250              (strcmp(protocol_name, "pdcp_r9_lte") == 0)) {
2251         parse_outhdr_string(outhdr_string, outhdr_length);
2252         attach_pdcp_lte_info(pinfo);
2253     }
2254
2255
2256     else if ((strcmp(protocol_name, "nas_rrc_r8_lte") == 0) ||
2257              (strcmp(protocol_name, "nas_rrc_r9_lte") == 0)) {
2258         gboolean nas_body_found = TRUE;
2259         guint8 opcode = tvb_get_guint8(tvb, offset);
2260         proto_tree_add_item(tree, hf_catapult_dct2000_lte_nas_rrc_opcode,
2261                             tvb, offset++, 1, ENC_BIG_ENDIAN);
2262
2263         offset++;   /* Skip overall length */
2264
2265         switch (opcode) {
2266             case LTE_NAS_RRC_DATA_IND:
2267             case LTE_NAS_RRC_DATA_REQ:
2268                 /* UEId */
2269                 offset++; /* tag */
2270                 offset += 2; /* 2 wasted bytes of UEId*/
2271                 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
2272                                     tvb, offset, 2, ENC_BIG_ENDIAN);
2273                 offset += 2;
2274                 break;
2275             case LTE_NAS_RRC_ESTABLISH_REQ:
2276                 /* UEId */
2277                 offset++; /* tag */
2278                 offset += 2; /* 2 wasted bytes of UEId*/
2279                 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
2280                                     tvb, offset, 2, ENC_BIG_ENDIAN);
2281                 offset += 2;
2282
2283                 /* Establish cause. TODO: value_string */
2284                 offset += 2;  /* tag + length */
2285                 proto_tree_add_item(tree, hf_catapult_dct2000_lte_nas_rrc_establish_cause,
2286                                     tvb, offset++, 1, ENC_BIG_ENDIAN);
2287
2288                 /* Priority.  TODO: Vals are low | high */
2289                 offset += 2;  /* tag + length */
2290                 proto_tree_add_item(tree, hf_catapult_dct2000_lte_nas_rrc_priority,
2291                                     tvb, offset++, 1, ENC_BIG_ENDIAN);
2292                 break;
2293             case LTE_NAS_RRC_RELEASE_IND:
2294                 /* UEId */
2295                 offset++; /* tag */
2296                 offset += 2; /* 2 wasted bytes of UEId*/
2297                 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
2298                                     tvb, offset, 2, ENC_BIG_ENDIAN);
2299                 offset += 2;
2300
2301                 /* Release cause.  TODO: value_string */
2302                 offset += 2;  /* tag + length */
2303                 proto_tree_add_item(tree, hf_catapult_dct2000_lte_nas_rrc_release_cause,
2304                                     tvb, offset++, 1, ENC_BIG_ENDIAN);
2305                 break;
2306
2307             default:
2308                 nas_body_found = FALSE;
2309                 break;
2310         }
2311
2312         /* Look up dissector if if looks right */
2313         if (nas_body_found) {
2314             offset += 2;  /* L3 tag + len */
2315             protocol_handle = find_dissector("nas-eps");
2316         }
2317     }
2318
2319     /* Note that the first item of pinfo->pseudo_header->dct2000 will contain
2320        the pseudo-header needed (in some cases) by the Wireshark dissector that
2321        this packet data will be handed off to. */
2322
2323
2324     /***********************************************************************/
2325     /* Now hand off to the dissector of intended packet encapsulation type */
2326
2327     /* Get protocol handle, and set p2p_dir where necessary.
2328        (packet-frame.c won't copy it from pseudo-header because it doesn't
2329         know about Catapult DCT2000 encap type...)
2330     */
2331     switch (encap) {
2332         case WTAP_ENCAP_RAW_IP:
2333             protocol_handle = find_dissector("ip");
2334 #if 0
2335             /* TODO: this doesn't work yet.
2336                pseudo_header isn't copied from wtap to pinfo... */
2337             if ((pinfo->pseudo_header != NULL) &&
2338                 (pinfo->pseudo_header->dct2000.inner_pseudo_header.pdcp.ueid != 0)) {
2339
2340                 proto_item *ti;
2341
2342                 /* Add PDCP thread info as generated fields */
2343                 ti = proto_tree_add_uint(dct2000_tree, hf_catapult_dct2000_lte_ueid, tvb, 0, 0,
2344                                          pinfo->pseudo_header->dct2000.inner_pseudo_header.pdcp.ueid);
2345                 PROTO_ITEM_SET_GENERATED(ti);
2346                 ti = proto_tree_add_uint(dct2000_tree, hf_catapult_dct2000_lte_drbid, tvb, 0, 0,
2347                                          pinfo->pseudo_header->dct2000.inner_pseudo_header.pdcp.drbid);
2348                 PROTO_ITEM_SET_GENERATED(ti);
2349             }
2350 #endif
2351             break;
2352         case WTAP_ENCAP_ETHERNET:
2353             protocol_handle = find_dissector("eth_withoutfcs");
2354             break;
2355         case WTAP_ENCAP_ISDN:
2356             protocol_handle = find_dissector("lapd");
2357             pinfo->p2p_dir = pinfo->pseudo_header->isdn.uton;
2358             break;
2359         case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED:
2360             protocol_handle = find_dissector("atm_untruncated");
2361             break;
2362         case WTAP_ENCAP_PPP:
2363             protocol_handle = find_dissector("ppp_hdlc");
2364             pinfo->p2p_dir = pinfo->pseudo_header->p2p.sent;
2365             break;
2366         case DCT2000_ENCAP_SSCOP:
2367             protocol_handle = find_dissector("sscop");
2368             break;
2369         case WTAP_ENCAP_FRELAY:
2370             protocol_handle = find_dissector("fr");
2371             break;
2372         case DCT2000_ENCAP_MTP2:
2373             protocol_handle = find_dissector("mtp2");
2374             break;
2375         case DCT2000_ENCAP_NBAP:
2376             protocol_handle = find_dissector("nbap");
2377             break;
2378
2379         case DCT2000_ENCAP_UNHANDLED:
2380             /**********************************************************/
2381             /* The wiretap module wasn't able to set an encapsulation */
2382             /* type, but it may still be possible to dissect the data */
2383             /* if we know about the protocol or if we can recognise   */
2384             /* and parse or skip a primitive header                   */
2385             /**********************************************************/
2386
2387             /* Show context.port in src or dest column as appropriate */
2388             if (direction == 0) {
2389                 col_add_fstr(pinfo->cinfo, COL_DEF_SRC,
2390                              "%s.%u",
2391                              context_name,
2392                              port_number);
2393             }
2394             else
2395             if (direction == 1) {
2396                 col_add_fstr(pinfo->cinfo, COL_DEF_DST,
2397                              "%s.%u",
2398                              context_name,
2399                              port_number);
2400             }
2401
2402
2403             /**************************************************************************/
2404             /* These protocols have no encapsulation type, just look them up directly */
2405
2406             if ((strcmp(protocol_name, "rlc") == 0) ||
2407                 (strcmp(protocol_name, "rlc_r4") == 0) ||
2408                 (strcmp(protocol_name, "rlc_r5") == 0) ||
2409                 (strcmp(protocol_name, "rlc_r6") == 0) ||
2410                 (strcmp(protocol_name, "rlc_r7") == 0) ||
2411                 (strcmp(protocol_name, "rlc_r8") == 0) ||
2412                 (strcmp(protocol_name, "rlc_r9") == 0)) {
2413
2414                 dissect_rlc_umts(tvb, offset, pinfo, tree, direction);
2415                 return;
2416             }
2417
2418             else
2419             if ((strcmp(protocol_name, "mac_r8_lte") == 0) ||
2420                 (strcmp(protocol_name, "mac_r9_lte") == 0)) {
2421                 protocol_handle = mac_lte_handle;
2422             }
2423
2424             else
2425             if ((strcmp(protocol_name, "rlc_r8_lte") == 0) ||
2426                 (strcmp(protocol_name, "rlc_r9_lte") == 0)) {
2427                 protocol_handle = rlc_lte_handle;
2428             }
2429
2430             else
2431             if ((strcmp(protocol_name, "pdcp_r8_lte") == 0) ||
2432                 (strcmp(protocol_name, "pdcp_r9_lte") == 0)) {
2433                 /* Dissect proprietary header, then pass remainder to PDCP */
2434                 dissect_pdcp_lte(tvb, offset, pinfo, tree);
2435                 return;
2436             }
2437
2438
2439             /* Work with generic XML protocol. */
2440             else
2441             if (strcmp(protocol_name, "xml") == 0) {
2442                 protocol_handle = find_dissector("xml");
2443             }
2444
2445
2446             /* Attempt to show tty messages as raw text */
2447             else
2448             if (strcmp(protocol_name, "tty") == 0) {
2449                 dissect_tty_lines(tvb, pinfo, dct2000_tree, offset);
2450                 return;
2451             }
2452
2453             else
2454             if (strcmp(protocol_name, "sipprim") == 0) {
2455                 protocol_handle = find_dissector("sipprim");
2456             }
2457
2458             else
2459             if (strcmp(protocol_name, "comment") == 0) {
2460                 /* Extract & add the string. */
2461                 proto_item *string_ti;
2462                 char *string = (char*)tvb_get_ephemeral_string(tvb, offset, tvb_length_remaining(tvb, offset));
2463
2464                 /* Show comment string */
2465                 string_ti = proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_comment, tvb,
2466                                                 offset, -1, ENC_ASCII|ENC_NA);
2467                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s", string);
2468
2469                 if (catapult_dct2000_dissect_mac_lte_oob_messages) {
2470                     /* Look into string for out-of-band MAC events, such as SRReq, SRInd */
2471                     check_for_oob_mac_lte_events(pinfo, tvb, tree, string);
2472                 }
2473
2474                 /* Look for and flag generic error messages */
2475                 if (strncmp(string, ">> ERR", 6) == 0) {
2476                     proto_item *error_ti = proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_error_comment, tvb,
2477                                                                offset, -1, ENC_NA);
2478                     PROTO_ITEM_SET_GENERATED(error_ti);
2479                     expert_add_info_format(pinfo, string_ti, PI_SEQUENCE, PI_ERROR,
2480                                           "%s", string);
2481                 }
2482
2483                 #define MONITOR_PREFIX ">> INFO ALL:    Monitor: CPU=["
2484                 if (strncmp(string, MONITOR_PREFIX, strlen(MONITOR_PREFIX)) == 0) {
2485                     gint user_cpu, sys_cpu, load_cpu;
2486                     gint memory_free, memory_load;
2487                     gint lte_scs_user_cpu, lte_scs_system_cpu;
2488                     int matched;
2489                     matched = sscanf(string+strlen(MONITOR_PREFIX),
2490                                      "User%%=%d Sys%%=%d Load%%=%d] Memory=[FreeMb=%d Load%%=%d] LTE_SCS_CPU=[User%%=%d Sys%%=%d]",
2491                                      &user_cpu, &sys_cpu, &load_cpu,
2492                                      &memory_free, &memory_load,
2493                                      &lte_scs_user_cpu, &lte_scs_system_cpu);
2494                     if (matched == 7) {
2495                         /* Overall CPU */
2496                         ti = proto_tree_add_uint(tree, hf_catapult_dct2000_lte_monitor_cpu_user,
2497                                                  tvb, 0, 0, user_cpu);
2498                         PROTO_ITEM_SET_GENERATED(ti);
2499
2500                         ti = proto_tree_add_uint(tree, hf_catapult_dct2000_lte_monitor_cpu_sys,
2501                                                  tvb, 0, 0, sys_cpu);
2502                         PROTO_ITEM_SET_GENERATED(ti);
2503
2504                         ti = proto_tree_add_uint(tree, hf_catapult_dct2000_lte_monitor_cpu_load,
2505                                                  tvb, 0, 0, load_cpu);
2506                         PROTO_ITEM_SET_GENERATED(ti);
2507
2508                         /* LTE_SCS CPU */
2509                         ti = proto_tree_add_uint(tree, hf_catapult_dct2000_lte_monitor_lte_scs_cpu_user,
2510                                                  tvb, 0, 0, lte_scs_user_cpu);
2511                         PROTO_ITEM_SET_GENERATED(ti);
2512
2513                         ti = proto_tree_add_uint(tree, hf_catapult_dct2000_lte_monitor_lte_scs_cpu_sys,
2514                                                  tvb, 0, 0, lte_scs_system_cpu);
2515                         PROTO_ITEM_SET_GENERATED(ti);
2516                     }
2517                 }
2518                 return;
2519             }
2520
2521
2522             else
2523             if (catapult_dct2000_dissect_lte_rrc &&
2524                 ((strcmp(protocol_name, "rrc_r8_lte") == 0) ||
2525                  (strcmp(protocol_name, "rrcpdcpprim_r8_lte") == 0) ||
2526                  (strcmp(protocol_name, "rrc_r9_lte") == 0) ||
2527                  (strcmp(protocol_name, "rrcpdcpprim_r9_lte") == 0))) {
2528
2529                 /* Dissect proprietary header, then pass remainder
2530                    to RRC (depending upon direction and channel type) */
2531                 dissect_rrc_lte(tvb, offset, pinfo, tree);
2532                 return;
2533             }
2534
2535             else
2536             if ((strcmp(protocol_name, "ccpri_r8_lte") == 0) ||
2537                 (strcmp(protocol_name, "ccpri_r9_lte") == 0)) {
2538
2539                 /* Dissect proprietary header, then pass remainder to lapb */
2540                 dissect_ccpri_lte(tvb, offset, pinfo, tree);
2541                 return;
2542             }
2543
2544             /* Many DCT2000 protocols have at least one IPPrim variant. If the
2545                protocol name can be matched to a dissector, try to find the
2546                UDP/TCP data inside and dissect it.
2547             */
2548
2549             if (!protocol_handle && catapult_dct2000_try_ipprim_heuristic) {
2550                 guint32      source_addr_offset = 0, dest_addr_offset = 0;
2551                 guint8       source_addr_length = 0, dest_addr_length = 0;
2552                 guint32      source_port_offset = 0, dest_port_offset = 0;
2553                 port_type    type_of_port = PT_NONE;
2554                 guint16      conn_id_offset = 0;
2555                 int          offset_before_ipprim_header = offset;
2556
2557                 /* Will give up if couldn't match protocol anyway... */
2558                 heur_protocol_handle = look_for_dissector(protocol_name);
2559                 if ((heur_protocol_handle != 0) &&
2560                     find_ipprim_data_offset(tvb, &offset, direction,
2561                                             &source_addr_offset, &source_addr_length,
2562                                             &dest_addr_offset, &dest_addr_length,
2563                                             &source_port_offset, &dest_port_offset,
2564                                             &type_of_port,
2565                                             &conn_id_offset)) {
2566
2567                     proto_tree *ipprim_tree;
2568                     proto_item *ipprim_ti;
2569                     struct     e_in6_addr sourcev6, destv6;
2570
2571                     /* Fetch IPv6 addresses */
2572                     if (source_addr_length != 4) {
2573                         tvb_get_ipv6(tvb, source_addr_offset, &sourcev6);
2574                     }
2575                     if (dest_addr_length != 4) {
2576                         tvb_get_ipv6(tvb, dest_addr_offset, &destv6);
2577                     }
2578
2579
2580                     /* Will use this dissector then. */
2581                     protocol_handle = heur_protocol_handle;
2582
2583                     /* Add address parameters to tree */
2584                     /* Unfortunately can't automatically create a conversation filter for this...
2585                        I *could* create a fake IP header from these details, but then it would be tricky
2586                        to get the FP dissector called as it has no well-known ports or heuristics... */
2587                     ipprim_ti =  proto_tree_add_string_format(dct2000_tree, hf_catapult_dct2000_ipprim_addresses,
2588                                                        tvb, offset_before_ipprim_header, 0,
2589                                                        "", "IPPrim transport (%s): %s:%u -> %s:%u",
2590                                                        (type_of_port == PT_UDP) ? "UDP" : "TCP",
2591                                                        (source_addr_offset) ?
2592                                                            ((source_addr_length == 4) ?
2593                                                               get_hostname(tvb_get_ipv4(tvb, source_addr_offset)) :
2594                                                               get_hostname6(&sourcev6)
2595                                                             ) :
2596                                                            "0.0.0.0",
2597                                                        (source_port_offset) ?
2598                                                            tvb_get_ntohs(tvb, source_port_offset) :
2599                                                            0,
2600                                                        (dest_addr_offset) ?
2601                                                          ((source_addr_length == 4) ?
2602                                                               get_hostname(tvb_get_ipv4(tvb, dest_addr_offset)) :
2603                                                               get_hostname6(&destv6)
2604                                                             ) :
2605                                                            "0.0.0.0",
2606                                                        (dest_port_offset) ?
2607                                                            tvb_get_ntohs(tvb, dest_port_offset) :
2608                                                            0);
2609                     if ((type_of_port == PT_TCP) && (conn_id_offset != 0)) {
2610                         proto_item_append_text(ipprim_ti, " (conn_id=%u)", tvb_get_ntohs(tvb, conn_id_offset));
2611                     }
2612
2613                     /* Add these IPPRIM fields inside an IPPRIM subtree */
2614                     ipprim_tree = proto_item_add_subtree(ipprim_ti, ett_catapult_dct2000_ipprim);
2615
2616                     /* Try to add right stuff to pinfo so conversation stuff works... */
2617                     pinfo->ptype = type_of_port;
2618                     switch (type_of_port) {
2619                         case PT_UDP:
2620                             pinfo->ipproto = IP_PROTO_UDP;
2621                             break;
2622                         case PT_TCP:
2623                             pinfo->ipproto = IP_PROTO_TCP;
2624                             break;
2625                         default:
2626                             pinfo->ipproto = IP_PROTO_NONE;
2627                     }
2628
2629                     /* Add addresses & ports into ipprim tree.
2630                        Also set address info in pinfo for conversations... */
2631                     if (source_addr_offset != 0) {
2632                         proto_item *addr_ti;
2633
2634                         SET_ADDRESS(&pinfo->net_src,
2635                                     (source_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2636                                     source_addr_length,
2637                                     (tvb_get_ptr(tvb, source_addr_offset, source_addr_length)));
2638                         SET_ADDRESS(&pinfo->src,
2639                                     (source_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2640                                     source_addr_length,
2641                                     (tvb_get_ptr(tvb, source_addr_offset, source_addr_length)));
2642
2643                         proto_tree_add_item(ipprim_tree,
2644                                             (source_addr_length == 4) ?
2645                                                 hf_catapult_dct2000_ipprim_src_addr_v4 :
2646                                                 hf_catapult_dct2000_ipprim_src_addr_v6,
2647                                             tvb, source_addr_offset, source_addr_length,
2648                                             (source_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2649
2650                         /* Add hidden item for "side-less" addr */
2651                         addr_ti = proto_tree_add_item(ipprim_tree,
2652                                                       (source_addr_length == 4) ?
2653                                                           hf_catapult_dct2000_ipprim_addr_v4 :
2654                                                           hf_catapult_dct2000_ipprim_addr_v6,
2655                                                       tvb, source_addr_offset, source_addr_length,
2656                                                       (source_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2657                         PROTO_ITEM_SET_HIDDEN(addr_ti);
2658                     }
2659                     if (source_port_offset != 0) {
2660                         proto_item *port_ti;
2661
2662                         pinfo->srcport = tvb_get_ntohs(tvb, source_port_offset);
2663
2664                         proto_tree_add_item(ipprim_tree,
2665                                             (type_of_port == PT_UDP) ?
2666                                                hf_catapult_dct2000_ipprim_udp_src_port :
2667                                                hf_catapult_dct2000_ipprim_tcp_src_port,
2668                                             tvb, source_port_offset, 2, ENC_BIG_ENDIAN);
2669                         port_ti = proto_tree_add_item(ipprim_tree,
2670                                                       (type_of_port == PT_UDP) ?
2671                                                           hf_catapult_dct2000_ipprim_udp_port :
2672                                                           hf_catapult_dct2000_ipprim_tcp_port,
2673                                                       tvb, source_port_offset, 2, ENC_BIG_ENDIAN);
2674                         PROTO_ITEM_SET_HIDDEN(port_ti);
2675                     }
2676                     if (dest_addr_offset != 0) {
2677                         proto_item *addr_ti;
2678
2679                         SET_ADDRESS(&pinfo->net_dst,
2680                                     (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2681                                     dest_addr_length,
2682                                     (tvb_get_ptr(tvb, dest_addr_offset, dest_addr_length)));
2683                         SET_ADDRESS(&pinfo->dst,
2684                                     (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2685                                     dest_addr_length,
2686                                     (tvb_get_ptr(tvb, dest_addr_offset, dest_addr_length)));
2687                         proto_tree_add_item(ipprim_tree,
2688                                             (dest_addr_length == 4) ?
2689                                                 hf_catapult_dct2000_ipprim_dst_addr_v4 :
2690                                                 hf_catapult_dct2000_ipprim_dst_addr_v6,
2691                                             tvb, dest_addr_offset, dest_addr_length,
2692                                             (dest_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2693
2694                         /* Add hidden item for "side-less" addr */
2695                         addr_ti = proto_tree_add_item(ipprim_tree,
2696                                                       (dest_addr_length == 4) ?
2697                                                           hf_catapult_dct2000_ipprim_addr_v4 :
2698                                                           hf_catapult_dct2000_ipprim_addr_v6,
2699                                                       tvb, dest_addr_offset, dest_addr_length,
2700                                                       (dest_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2701                         PROTO_ITEM_SET_HIDDEN(addr_ti);
2702                     }
2703                     if (dest_port_offset != 0) {
2704                         proto_item *port_ti;
2705
2706                         pinfo->destport = tvb_get_ntohs(tvb, dest_port_offset);
2707
2708                         proto_tree_add_item(ipprim_tree,
2709                                             (type_of_port == PT_UDP) ?
2710                                                hf_catapult_dct2000_ipprim_udp_dst_port :
2711                                                hf_catapult_dct2000_ipprim_tcp_dst_port,
2712                                             tvb, dest_port_offset, 2, ENC_BIG_ENDIAN);
2713                         port_ti = proto_tree_add_item(ipprim_tree,
2714                                                       (type_of_port == PT_UDP) ?
2715                                                           hf_catapult_dct2000_ipprim_udp_port :
2716                                                           hf_catapult_dct2000_ipprim_tcp_port,
2717                                                       tvb, dest_port_offset, 2, ENC_BIG_ENDIAN);
2718                         PROTO_ITEM_SET_HIDDEN(port_ti);
2719                     }
2720                     if (conn_id_offset != 0) {
2721                         proto_tree_add_item(ipprim_tree,
2722                                             hf_catapult_dct2000_ipprim_conn_id,
2723                                             tvb, conn_id_offset, 2, ENC_BIG_ENDIAN);
2724                     }
2725
2726
2727                     /* Set source and dest columns now (will be overwriiten if
2728                        src and dst IP addresses set) */
2729                     if (source_addr_offset) {
2730                         col_append_fstr(pinfo->cinfo, COL_DEF_SRC,
2731                                         "(%s:%u)",
2732                                         get_hostname(tvb_get_ipv4(tvb, source_addr_offset)),
2733                                         tvb_get_ntohs(tvb, source_port_offset));
2734                     }
2735                     if (dest_addr_offset) {
2736                         col_append_fstr(pinfo->cinfo, COL_DEF_DST,
2737                                         "(%s:%u)",
2738                                         get_hostname(tvb_get_ipv4(tvb, dest_addr_offset)),
2739                                         tvb_get_ntohs(tvb, dest_port_offset));
2740                     }
2741
2742                     /* Set length for IPPrim tree */
2743                     proto_item_set_len(ipprim_tree, offset - offset_before_ipprim_header);
2744                 }
2745             }
2746
2747
2748             /* Try SCTP Prim heuristic if configured to */
2749             if (!protocol_handle && catapult_dct2000_try_sctpprim_heuristic) {
2750                 guint32      dest_addr_offset = 0;
2751                 guint16      dest_addr_length = 0;
2752                 guint32      dest_port_offset = 0;
2753                 int          offset_before_sctpprim_header = offset;
2754
2755                 heur_protocol_handle = look_for_dissector(protocol_name);
2756                 if ((heur_protocol_handle != 0) &&
2757                     (find_sctpprim_variant1_data_offset(tvb, &offset,
2758                                                         &dest_addr_offset,
2759                                                         &dest_addr_length,
2760                                                         &dest_port_offset) ||
2761                      find_sctpprim_variant3_data_offset(tvb, &offset,
2762                                                         &dest_addr_offset,
2763                                                         &dest_addr_length,
2764                                                         &dest_port_offset))) {
2765
2766                     proto_tree *sctpprim_tree;
2767                     proto_item *ti_local;
2768
2769                     /* Will use this dissector then. */
2770                     protocol_handle = heur_protocol_handle;
2771
2772                     ti_local =  proto_tree_add_string_format(dct2000_tree, hf_catapult_dct2000_sctpprim_addresses,
2773                                                        tvb, offset_before_sctpprim_header, 0,
2774                                                        "", "SCTPPrim transport:  -> %s:%u",
2775                                                        (dest_addr_offset) ?
2776                                                          ((dest_addr_length == 4) ?
2777                                                               get_hostname(tvb_get_ipv4(tvb, dest_addr_offset)) :
2778                                                               "<ipv6-address>"
2779                                                             ) :
2780                                                            "0.0.0.0",
2781                                                        (dest_port_offset) ?
2782                                                          tvb_get_ntohs(tvb, dest_port_offset) :
2783                                                          0);
2784
2785                     /* Add these SCTPPRIM fields inside an SCTPPRIM subtree */
2786                     sctpprim_tree = proto_item_add_subtree(ti_local, ett_catapult_dct2000_sctpprim);
2787
2788                     pinfo->ipproto = IP_PROTO_SCTP;
2789
2790                     /* Destination address */
2791                     if (dest_addr_offset != 0) {
2792                         proto_item *addr_ti;
2793
2794                         SET_ADDRESS(&pinfo->net_dst,
2795                                     (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2796                                     dest_addr_length,
2797                                     (tvb_get_ptr(tvb, dest_addr_offset, dest_addr_length)));
2798                         SET_ADDRESS(&pinfo->dst,
2799                                     (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2800                                     dest_addr_length,
2801                                     (tvb_get_ptr(tvb, dest_addr_offset, dest_addr_length)));
2802                         proto_tree_add_item(sctpprim_tree,
2803                                             (dest_addr_length == 4) ?
2804                                                 hf_catapult_dct2000_sctpprim_dst_addr_v4 :
2805                                                 hf_catapult_dct2000_sctpprim_dst_addr_v6,
2806                                             tvb, dest_addr_offset, dest_addr_length,
2807                                             (dest_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2808
2809                         /* Add hidden item for "side-less" addr */
2810                         addr_ti = proto_tree_add_item(sctpprim_tree,
2811                                                       (dest_addr_length == 4) ?
2812                                                           hf_catapult_dct2000_sctpprim_addr_v4 :
2813                                                           hf_catapult_dct2000_sctpprim_addr_v6,
2814                                                       tvb, dest_addr_offset, dest_addr_length,
2815                                                       (dest_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2816                         PROTO_ITEM_SET_HIDDEN(addr_ti);
2817                     }
2818
2819                     if (dest_port_offset != 0) {
2820                         pinfo->destport = tvb_get_ntohs(tvb, dest_port_offset);
2821
2822                         proto_tree_add_item(sctpprim_tree,
2823                                             hf_catapult_dct2000_sctpprim_dst_port,
2824                                             tvb, dest_port_offset, 2, ENC_BIG_ENDIAN);
2825                     }
2826
2827                     /* Set length for SCTPPrim tree */
2828                     proto_item_set_len(sctpprim_tree, offset - offset_before_sctpprim_header);
2829                 }
2830             }
2831
2832             /* Last chance: is there a (private) registered protocol of the form
2833                "dct2000.protocol" ? */
2834             if (protocol_handle == 0) {
2835                 /* TODO: only look inside preference? */
2836                 char dotted_protocol_name[64+128];
2837                 g_snprintf(dotted_protocol_name, 64+128, "dct2000.%s", protocol_name);
2838                 protocol_handle = find_dissector(dotted_protocol_name);
2839             }
2840
2841             break;
2842
2843         default:
2844             /* !! If get here, there is a mismatch between
2845                this dissector and the wiretap module catapult_dct2000.c !!
2846             */
2847             DISSECTOR_ASSERT_NOT_REACHED();
2848             return;
2849     }
2850
2851     /* Set selection length of dct2000 tree */
2852     proto_item_set_len(dct2000_tree, offset);
2853
2854     /* Try appropriate dissector, if one has been selected */
2855     if (protocol_handle != 0) {
2856         /* Dissect the remainder of the frame using chosen protocol handle */
2857         next_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset);
2858         sub_dissector_result = call_dissector_only(protocol_handle, next_tvb, pinfo, tree, NULL);
2859     }
2860
2861
2862     if (protocol_handle == 0 || sub_dissector_result == 0) {
2863         /* Could get here because:
2864            - encap is DCT2000_ENCAP_UNHANDLED and we still didn't handle it, OR
2865            - desired protocol is unavailable (probably disabled), OR
2866            - protocol rejected our data
2867            Show remaining bytes as unparsed data */
2868         proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_unparsed_data,
2869                             tvb, offset, -1, ENC_NA);
2870
2871         col_add_fstr(pinfo->cinfo, COL_INFO,
2872                      "Not dissected  (context=%s.%u   t=%s   %c   prot=%s (v=%s))",
2873                      context_name,
2874                      port_number,
2875                      timestamp_string,
2876                      (direction == 0) ? 'S' : 'R',
2877                      protocol_name,
2878                      variant_string);
2879     }
2880     else {
2881         /* Show number of dissected bytes */
2882         if (dct2000_tree) {
2883             proto_item *ti_local = proto_tree_add_uint(dct2000_tree,
2884                                                  hf_catapult_dct2000_dissected_length,
2885                                                  tvb, 0, 0, tvb_reported_length(tvb)-offset);
2886             PROTO_ITEM_SET_GENERATED(ti_local);
2887         }
2888     }
2889 }
2890
2891
2892
2893 /******************************************************************************/
2894 /* Associate this protocol with the Catapult DCT2000 file encapsulation type. */
2895 /******************************************************************************/
2896 void proto_reg_handoff_catapult_dct2000(void)
2897 {
2898     dissector_handle_t catapult_dct2000_handle = find_dissector("dct2000");
2899
2900     dissector_add_uint("wtap_encap", WTAP_ENCAP_CATAPULT_DCT2000, catapult_dct2000_handle);
2901
2902     mac_lte_handle = find_dissector("mac-lte");
2903     rlc_lte_handle = find_dissector("rlc-lte");
2904     pdcp_lte_handle = find_dissector("pdcp-lte");
2905 }
2906
2907 /****************************************/
2908 /* Register the protocol                */
2909 /****************************************/
2910 void proto_register_catapult_dct2000(void)
2911 {
2912     static hf_register_info hf[] =
2913     {
2914         { &hf_catapult_dct2000_context,
2915             { "Context",
2916               "dct2000.context", FT_STRING, BASE_NONE, NULL, 0x0,
2917               "Context name", HFILL
2918             }
2919         },
2920         { &hf_catapult_dct2000_port_number,
2921             { "Context Port number",
2922               "dct2000.context_port", FT_UINT8, BASE_DEC, NULL, 0x0,
2923               NULL, HFILL
2924             }
2925         },
2926         { &hf_catapult_dct2000_timestamp,
2927             { "Timestamp",
2928               "dct2000.timestamp", FT_DOUBLE, BASE_NONE, NULL, 0x0,
2929               "File timestamp", HFILL
2930             }
2931         },
2932         { &hf_catapult_dct2000_protocol,
2933             { "DCT2000 protocol",
2934               "dct2000.protocol", FT_STRING, BASE_NONE, NULL, 0x0,
2935               "Original (DCT2000) protocol name", HFILL
2936             }
2937         },
2938         { &hf_catapult_dct2000_variant,
2939             { "Protocol variant",
2940               "dct2000.variant", FT_STRING, BASE_NONE, NULL, 0x0,
2941               "DCT2000 protocol variant", HFILL
2942             }
2943         },
2944         { &hf_catapult_dct2000_outhdr,
2945             { "Out-header",
2946               "dct2000.outhdr", FT_STRING, BASE_NONE, NULL, 0x0,
2947               "DCT2000 protocol outhdr", HFILL
2948             }
2949         },
2950         { &hf_catapult_dct2000_direction,
2951             { "Direction",
2952               "dct2000.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
2953               "Frame direction (Sent or Received)", HFILL
2954             }
2955         },
2956         { &hf_catapult_dct2000_encap,
2957             { "Wireshark encapsulation",
2958               "dct2000.encapsulation", FT_UINT8, BASE_DEC, VALS(encap_vals), 0x0,
2959               "Wireshark frame encapsulation used", HFILL
2960             }
2961         },
2962         { &hf_catapult_dct2000_unparsed_data,
2963             { "Unparsed protocol data",
2964               "dct2000.unparsed_data", FT_BYTES, BASE_NONE, NULL, 0x0,
2965               "Unparsed DCT2000 protocol data", HFILL
2966             }
2967         },
2968         { &hf_catapult_dct2000_comment,
2969             { "Comment",
2970               "dct2000.comment", FT_STRING, BASE_NONE, NULL, 0x0,
2971               NULL, HFILL
2972             }
2973         },
2974         { &hf_catapult_dct2000_error_comment,
2975             { "Error comment",
2976               "dct2000.error-comment", FT_NONE, BASE_NONE, NULL, 0x0,
2977               NULL, HFILL
2978             }
2979         },
2980         { &hf_catapult_dct2000_dissected_length,
2981             { "Dissected length",
2982               "dct2000.dissected-length", FT_UINT16, BASE_DEC, NULL, 0x0,
2983               "Number of bytes dissected by subdissector(s)", HFILL
2984             }
2985         },
2986
2987         { &hf_catapult_dct2000_ipprim_addresses,
2988             { "IPPrim Addresses",
2989               "dct2000.ipprim", FT_STRING, BASE_NONE, NULL, 0x0,
2990               NULL, HFILL
2991             }
2992         },
2993         { &hf_catapult_dct2000_ipprim_src_addr_v4,
2994             { "Source Address",
2995               "dct2000.ipprim.src", FT_IPv4, BASE_NONE, NULL, 0x0,
2996               "IPPrim IPv4 Source Address", HFILL
2997             }
2998         },
2999         { &hf_catapult_dct2000_ipprim_src_addr_v6,
3000             { "Source Address",
3001               "dct2000.ipprim.srcv6", FT_IPv6, BASE_NONE, NULL, 0x0,
3002               "IPPrim IPv6 Source Address", HFILL
3003             }
3004         },
3005         { &hf_catapult_dct2000_ipprim_dst_addr_v4,
3006             { "Destination Address",
3007               "dct2000.ipprim.dst", FT_IPv4, BASE_NONE, NULL, 0x0,
3008               "IPPrim IPv4 Destination Address", HFILL
3009             }
3010         },
3011         { &hf_catapult_dct2000_ipprim_dst_addr_v6,
3012             { "Destination Address",
3013               "dct2000.ipprim.dstv6", FT_IPv6, BASE_NONE, NULL, 0x0,
3014               "IPPrim IPv6 Destination Address", HFILL
3015             }
3016         },
3017         { &hf_catapult_dct2000_ipprim_addr_v4,
3018             { "Address",
3019               "dct2000.ipprim.addr", FT_IPv4, BASE_NONE, NULL, 0x0,
3020               "IPPrim IPv4 Address", HFILL
3021             }
3022         },
3023         { &hf_catapult_dct2000_ipprim_addr_v6,
3024             { "Address",
3025               "dct2000.ipprim.addrv6", FT_IPv6, BASE_NONE, NULL, 0x0,
3026               "IPPrim IPv6 Address", HFILL
3027             }
3028         },
3029         { &hf_catapult_dct2000_ipprim_udp_src_port,
3030             { "UDP Source Port",
3031               "dct2000.ipprim.udp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
3032               "IPPrim UDP Source Port", HFILL
3033             }
3034         },
3035         { &hf_catapult_dct2000_ipprim_udp_dst_port,
3036             { "UDP Destination Port",
3037               "dct2000.ipprim.udp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
3038               "IPPrim UDP Destination Port", HFILL
3039             }
3040         },
3041         { &hf_catapult_dct2000_ipprim_udp_port,
3042             { "UDP Port",
3043               "dct2000.ipprim.udp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
3044               "IPPrim UDP Port", HFILL
3045             }
3046         },
3047         { &hf_catapult_dct2000_ipprim_tcp_src_port,
3048             { "TCP Source Port",
3049               "dct2000.ipprim.tcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
3050               "IPPrim TCP Source Port", HFILL
3051             }
3052         },
3053         { &hf_catapult_dct2000_ipprim_tcp_dst_port,
3054             { "TCP Destination Port",
3055               "dct2000.ipprim.tcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
3056               "IPPrim TCP Destination Port", HFILL
3057             }
3058         },
3059         { &hf_catapult_dct2000_ipprim_tcp_port,
3060             { "TCP Port",
3061               "dct2000.ipprim.tcp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
3062               "IPPrim TCP Port", HFILL
3063             }
3064         },
3065         { &hf_catapult_dct2000_ipprim_conn_id,
3066             { "Conn Id",
3067               "dct2000.ipprim.conn-id", FT_UINT16, BASE_DEC, NULL, 0x0,
3068               "IPPrim TCP Connection ID", HFILL
3069             }
3070         },
3071
3072         { &hf_catapult_dct2000_sctpprim_addresses,
3073             { "SCTPPrim Addresses",
3074               "dct2000.sctpprim", FT_STRING, BASE_NONE, NULL, 0x0,
3075               NULL, HFILL
3076             }
3077         },
3078         { &hf_catapult_dct2000_sctpprim_dst_addr_v4,
3079             { "Destination Address",
3080               "dct2000.sctpprim.dst", FT_IPv4, BASE_NONE, NULL, 0x0,
3081               "SCTPPrim IPv4 Destination Address", HFILL
3082             }
3083         },
3084         { &hf_catapult_dct2000_sctpprim_dst_addr_v6,
3085             { "Destination Address",
3086               "dct2000.sctpprim.dstv6", FT_IPv6, BASE_NONE, NULL, 0x0,
3087               "SCTPPrim IPv6 Destination Address", HFILL
3088             }
3089         },
3090         { &hf_catapult_dct2000_sctpprim_addr_v4,
3091             { "Address",
3092               "dct2000.sctpprim.addr", FT_IPv4, BASE_NONE, NULL, 0x0,
3093               "SCTPPrim IPv4 Address", HFILL
3094             }
3095         },
3096         { &hf_catapult_dct2000_sctpprim_addr_v6,
3097             { "Address",
3098               "dct2000.sctpprim.addrv6", FT_IPv6, BASE_NONE, NULL, 0x0,
3099               "SCTPPrim IPv6 Address", HFILL
3100             }
3101         },
3102         { &hf_catapult_dct2000_sctpprim_dst_port,
3103             { "UDP Destination Port",
3104               "dct2000.sctprim.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
3105               "SCTPPrim Destination Port", HFILL
3106             }
3107         },
3108
3109         { &hf_catapult_dct2000_tty,
3110             { "tty contents",
3111               "dct2000.tty", FT_NONE, BASE_NONE, NULL, 0x0,
3112               NULL, HFILL
3113             }
3114         },
3115         { &hf_catapult_dct2000_tty_line,
3116             { "tty line",
3117               "dct2000.tty-line", FT_STRING, BASE_NONE, NULL, 0x0,
3118               NULL, HFILL
3119             }
3120         },
3121
3122         { &hf_catapult_dct2000_lte_ueid,
3123             { "UE Id",
3124               "dct2000.lte.ueid", FT_UINT16, BASE_DEC, NULL, 0x0,
3125               "User Equipment Identifier", HFILL
3126             }
3127         },
3128         { &hf_catapult_dct2000_lte_srbid,
3129             { "srbid",
3130               "dct2000.lte.srbid", FT_UINT8, BASE_DEC, NULL, 0x0,
3131               "Signalling Radio Bearer Identifier", HFILL
3132             }
3133         },
3134         { &hf_catapult_dct2000_lte_drbid,
3135             { "drbid",
3136               "dct2000.lte.drbid", FT_UINT8, BASE_DEC, NULL, 0x0,
3137               "Data Radio Bearer Identifier", HFILL
3138             }
3139         },
3140         { &hf_catapult_dct2000_lte_cellid,
3141             { "Cell-Id",
3142               "dct2000.lte.cellid", FT_UINT16, BASE_DEC, NULL, 0x0,
3143               "Cell Identifier", HFILL
3144             }
3145         },
3146         { &hf_catapult_dct2000_lte_bcch_transport,
3147             { "BCCH Transport",
3148               "dct2000.lte.bcch-transport", FT_UINT16, BASE_DEC, VALS(bcch_transport_vals), 0x0,
3149               "BCCH Transport Channel", HFILL
3150             }
3151         },
3152         { &hf_catapult_dct2000_lte_rlc_op,
3153             { "RLC Op",
3154               "dct2000.lte.rlc-op", FT_UINT8, BASE_DEC, VALS(rlc_op_vals), 0x0,
3155               "RLC top-level op", HFILL
3156             }
3157         },
3158         { &hf_catapult_dct2000_lte_rlc_channel_type,
3159             { "RLC Logical Channel Type",
3160               "dct2000.lte.rlc-logchan-type", FT_UINT8, BASE_DEC, VALS(rlc_logical_channel_vals), 0x0,
3161               NULL, HFILL
3162             }
3163         },
3164         { &hf_catapult_dct2000_lte_rlc_mui,
3165             { "MUI",
3166               "dct2000.lte.rlc-mui", FT_UINT16, BASE_DEC, NULL, 0x0,
3167               "RLC MUI", HFILL
3168             }
3169         },
3170         { &hf_catapult_dct2000_lte_rlc_cnf,
3171             { "CNF",
3172               "dct2000.lte.rlc-cnf", FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0,
3173               "RLC CNF", HFILL
3174             }
3175         },
3176         { &hf_catapult_dct2000_lte_rlc_discard_req,
3177             { "Discard Req",
3178               "dct2000.lte.rlc-discard-req", FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0,
3179               "RLC Discard Req", HFILL
3180             }
3181         },
3182
3183         { &hf_catapult_dct2000_lte_ccpri_opcode,
3184             { "CCPRI opcode",
3185               "dct2000.lte.ccpri.opcode", FT_UINT8, BASE_DEC, VALS(ccpri_opcode_vals), 0x0,
3186               NULL, HFILL
3187             }
3188         },
3189         { &hf_catapult_dct2000_lte_ccpri_status,
3190             { "Status",
3191               "dct2000.lte.ccpri.status", FT_UINT8, BASE_DEC, VALS(ccpri_status_vals), 0x0,
3192               NULL, HFILL
3193             }
3194         },
3195         { &hf_catapult_dct2000_lte_ccpri_channel,
3196             { "Channel",
3197               "dct2000.lte.ccpri.channel", FT_UINT8, BASE_DEC, NULL, 0x0,
3198               NULL, HFILL
3199             }
3200         },
3201
3202         { &hf_catapult_dct2000_lte_monitor_cpu_user,
3203             { "User CPU",
3204               "dct2000.lte.monitor.cpu.user", FT_UINT32, BASE_DEC, NULL, 0x0,
3205               NULL, HFILL
3206             }
3207         },
3208         { &hf_catapult_dct2000_lte_monitor_cpu_sys,
3209             { "Sys CPU",
3210               "dct2000.lte.monitor.cpu.sys", FT_UINT32, BASE_DEC, NULL, 0x0,
3211               NULL, HFILL
3212             }
3213         },
3214         { &hf_catapult_dct2000_lte_monitor_cpu_load,
3215             { "Load CPU",
3216               "dct2000.lte.monitor.cpu.load", FT_UINT32, BASE_DEC, NULL, 0x0,
3217               NULL, HFILL
3218             }
3219         },
3220         { &hf_catapult_dct2000_lte_monitor_lte_scs_cpu_user,
3221             { "lte-scs User CPU",
3222               "dct2000.lte.monitor.lte-scs.cpu.user", FT_UINT32, BASE_DEC, NULL, 0x0,
3223               NULL, HFILL
3224             }
3225         },
3226         { &hf_catapult_dct2000_lte_monitor_lte_scs_cpu_sys,
3227             { "lte-scs Sys CPU",
3228               "dct2000.lte.monitor.lte-scs.cpu.sys", FT_UINT32, BASE_DEC, NULL, 0x0,
3229               NULL, HFILL
3230             }
3231         },
3232
3233         { &hf_catapult_dct2000_lte_nas_rrc_opcode,
3234             { "NAS RRC Opcode",
3235               "dct2000.lte.nas-rrc.opcode", FT_UINT8, BASE_DEC, VALS(lte_nas_rrc_opcode_vals), 0x0,
3236               NULL, HFILL
3237             }
3238         },
3239         { &hf_catapult_dct2000_lte_nas_rrc_establish_cause,
3240             { "Establish Cause",
3241               "dct2000.lte.nas-rrc.establish-cause", FT_UINT8, BASE_DEC, NULL, 0x0,
3242               NULL, HFILL
3243             }
3244         },
3245         { &hf_catapult_dct2000_lte_nas_rrc_priority,
3246             { "Priority",
3247               "dct2000.lte.nas-rrc.priority", FT_UINT8, BASE_DEC, NULL, 0x0,
3248               NULL, HFILL
3249             }
3250         },
3251         { &hf_catapult_dct2000_lte_nas_rrc_release_cause,
3252             { "Priority",
3253               "dct2000.lte.nas-rrc.priority", FT_UINT8, BASE_DEC, NULL, 0x0,
3254               NULL, HFILL
3255             }
3256         },
3257
3258
3259         { &hf_catapult_dct2000_ueid,
3260             { "UE Id",
3261               "dct2000.ueid", FT_UINT32, BASE_DEC, NULL, 0x0,
3262               "User Equipment Identifier", HFILL
3263             }
3264         },
3265         { &hf_catapult_dct2000_rbid,
3266             { "Channel",
3267               "dct2000.rbid", FT_UINT8, BASE_DEC, VALS(rlc_rbid_vals), 0x0,
3268               "Channel (rbid)", HFILL
3269             }
3270         },
3271         { &hf_catapult_dct2000_ccch_id,
3272             { "CCCH Id",
3273               "dct2000.ccch-id", FT_UINT8, BASE_DEC, NULL, 0x0,
3274               "CCCH Identifier", HFILL
3275             }
3276         },
3277         { &hf_catapult_dct2000_no_crc_error,
3278             { "No CRC Error",
3279               "dct2000.no-crc-error", FT_NONE, BASE_NONE, NULL, 0x0,
3280               NULL, HFILL
3281             }
3282         },
3283         { &hf_catapult_dct2000_crc_error,
3284             { "CRC Error",
3285               "dct2000.crc-error", FT_NONE, BASE_NONE, NULL, 0x0,
3286               NULL, HFILL
3287             }
3288         },
3289         { &hf_catapult_dct2000_clear_tx_buffer,
3290             { "Clear Tx Buffer",
3291               "dct2000.clear-tx-buffer", FT_NONE, BASE_NONE, NULL, 0x0,
3292               NULL, HFILL
3293             }
3294         },
3295         { &hf_catapult_dct2000_buffer_occupancy,
3296             { "Buffer Occupancy",
3297               "dct2000.buffer-occupancy", FT_UINT8, BASE_DEC, NULL, 0x0,
3298               NULL, HFILL
3299             }
3300         },
3301         { &hf_catapult_dct2000_pdu_size,
3302             { "PDU Size",
3303               "dct2000.pdu-size", FT_UINT16, BASE_DEC, NULL, 0x0,
3304               NULL, HFILL
3305             }
3306         },
3307         { &hf_catapult_dct2000_ueid_type,
3308             { "UEId Type",
3309               "dct2000.ueid-type", FT_UINT8, BASE_DEC, VALS(ueid_type_vals), 0x0,
3310               NULL, HFILL
3311             }
3312         },
3313         { &hf_catapult_dct2000_tx_priority,
3314             { "Tx Priority",
3315               "dct2000.tx-priority", FT_UINT8, BASE_DEC, VALS(tx_priority_vals), 0x0,
3316               NULL, HFILL
3317             }
3318         },
3319         { &hf_catapult_dct2000_last_in_seg_set,
3320             { "Last in seg set",
3321               "dct2000.last-in-seg-set", FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0,
3322               NULL, HFILL
3323             }
3324         },
3325         { &hf_catapult_dct2000_rx_timing_deviation,
3326             { "Tx Timing Deviation",
3327               "dct2000.rx-timing-deviation", FT_UINT32, BASE_DEC, NULL, 0x0,
3328               NULL, HFILL
3329             }
3330         },
3331         { &hf_catapult_dct2000_transport_channel_type,
3332             { "Transport Channel Type",
3333               "dct2000.transport_channel_type", FT_UINT8, BASE_DEC, VALS(transport_channel_type_vals), 0x0,
3334               NULL, HFILL
3335             }
3336         },
3337         { &hf_catapult_dct2000_no_padding_bits,
3338             { "Number of padding bits",
3339               "dct2000.number-of-padding-bits", FT_UINT8, BASE_DEC, NULL, 0x0,
3340               NULL, HFILL
3341             }
3342         },
3343
3344     };
3345
3346     static gint *ett[] =
3347     {
3348         &ett_catapult_dct2000,
3349         &ett_catapult_dct2000_ipprim,
3350         &ett_catapult_dct2000_sctpprim,
3351         &ett_catapult_dct2000_tty
3352     };
3353
3354     module_t *catapult_dct2000_module;
3355
3356     /* Register protocol. */
3357     proto_catapult_dct2000 = proto_register_protocol("Catapult DCT2000 packet",
3358                                                      "DCT2000",
3359                                                      "dct2000");
3360     proto_register_field_array(proto_catapult_dct2000, hf, array_length(hf));
3361     proto_register_subtree_array(ett, array_length(ett));
3362
3363     /* Allow dissector to find be found by name. */
3364     register_dissector("dct2000", dissect_catapult_dct2000, proto_catapult_dct2000);
3365
3366     /* Preferences */
3367     catapult_dct2000_module = prefs_register_protocol(proto_catapult_dct2000, NULL);
3368
3369     /* This preference no longer supported (introduces linkage dependency between
3370        dissectors and wiretap) */
3371     prefs_register_obsolete_preference(catapult_dct2000_module, "board_ports_only");
3372
3373     /* Determines whether for not-handled protocols we should try to parse it if:
3374        - it looks like its embedded in an ipprim message, AND
3375        - the DCT2000 protocol name can be matched to a Wireshark dissector name */
3376     prefs_register_bool_preference(catapult_dct2000_module, "ipprim_heuristic",
3377                                    "Use IP Primitive heuristic",
3378                                    "If a payload looks like its embedded in an "
3379                                    "IP primitive message, and there is a Wireshark "
3380                                    "dissector matching the DCT2000 protocol name, "
3381                                    "try parsing the payload using that dissector",
3382                                    &catapult_dct2000_try_ipprim_heuristic);
3383
3384     /* Determines whether for not-handled protocols we should try to parse it if:
3385        - it looks like its embedded in an sctpprim message, AND
3386        - the DCT2000 protocol name can be matched to a Wireshark dissector name */
3387     prefs_register_bool_preference(catapult_dct2000_module, "sctpprim_heuristic",
3388                                    "Use SCTP Primitive heuristic",
3389                                    "If a payload looks like its embedded in an "
3390                                    "SCTP primitive message, and there is a Wireshark "
3391                                    "dissector matching the DCT2000 protocol name, "
3392                                    "try parsing the payload using that dissector",
3393                                    &catapult_dct2000_try_sctpprim_heuristic);
3394
3395     /* Determines whether LTE RRC messages should be dissected */
3396     prefs_register_bool_preference(catapult_dct2000_module, "decode_lte_rrc",
3397                                    "Attempt to decode LTE RRC frames",
3398                                    "When set, attempt to decode LTE RRC frames. "
3399                                    "Note that this won't affect other protocols "
3400                                    "that also call the LTE RRC dissector",
3401                                    &catapult_dct2000_dissect_lte_rrc);
3402
3403     /* Determines whether LTE S1AP messages should be dissected */
3404     prefs_register_bool_preference(catapult_dct2000_module, "decode_lte_s1ap",
3405                                    "Attempt to decode LTE S1AP frames",
3406                                    "When set, attempt to decode LTE S1AP frames. "
3407                                    "Note that this won't affect other protocols "
3408                                    "that also call the LTE S1AP dissector",
3409                                    &catapult_dct2000_dissect_lte_s1ap);
3410
3411     /* Determines whether out-of-band messages should dissected */
3412     prefs_register_bool_preference(catapult_dct2000_module, "decode_mac_lte_oob_messages",
3413                                    "Look for out-of-band LTE MAC events messages in comments",
3414                                    "When set, look for formatted messages indicating "
3415                                    "specific events.  This may be quite slow, so should "
3416                                    "be disabled if LTE MAC is not being analysed",
3417                                    &catapult_dct2000_dissect_mac_lte_oob_messages);
3418 }
3419