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