HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-catapult-dct2000.c
blob9c4730c70b3857dbf51b5061e429922f353046d3
1 /* packet-catapult-dct2000.c
2 * Routines for Catapult DCT2000 packet stub header disassembly
4 * $Id$
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "config.h"
27 #include <glib.h>
29 #include <stdio.h>
30 #include <ctype.h>
32 #include <epan/packet.h>
33 #include <epan/conversation.h>
34 #include <epan/expert.h>
35 #include <epan/wmem/wmem.h>
36 #include <epan/ipproto.h>
37 #include <epan/prefs.h>
38 #include <epan/strutil.h>
39 #include <epan/addr_resolv.h>
41 #include <wiretap/catapult_dct2000.h>
42 #include "packet-umts_fp.h"
43 #include "packet-rlc.h"
45 #include "packet-mac-lte.h"
46 #include "packet-rlc-lte.h"
47 #include "packet-pdcp-lte.h"
49 /* Protocol and registered fields. */
50 static int proto_catapult_dct2000 = -1;
52 static int hf_catapult_dct2000_context = -1;
53 static int hf_catapult_dct2000_port_number = -1;
54 static int hf_catapult_dct2000_timestamp = -1;
55 static int hf_catapult_dct2000_protocol = -1;
56 static int hf_catapult_dct2000_variant = -1;
57 static int hf_catapult_dct2000_outhdr = -1;
58 static int hf_catapult_dct2000_direction = -1;
59 static int hf_catapult_dct2000_encap = -1;
60 static int hf_catapult_dct2000_unparsed_data = -1;
61 static int hf_catapult_dct2000_comment = -1;
62 static int hf_catapult_dct2000_sprint = -1;
63 static int hf_catapult_dct2000_error_comment = -1;
64 static int hf_catapult_dct2000_tty = -1;
65 static int hf_catapult_dct2000_tty_line = -1;
66 static int hf_catapult_dct2000_dissected_length = -1;
68 static int hf_catapult_dct2000_ipprim_addresses = -1;
69 static int hf_catapult_dct2000_ipprim_src_addr_v4 = -1;
70 static int hf_catapult_dct2000_ipprim_src_addr_v6 = -1;
71 static int hf_catapult_dct2000_ipprim_dst_addr_v4 = -1;
72 static int hf_catapult_dct2000_ipprim_dst_addr_v6 = -1;
73 static int hf_catapult_dct2000_ipprim_addr_v4 = -1;
74 static int hf_catapult_dct2000_ipprim_addr_v6 = -1;
75 static int hf_catapult_dct2000_ipprim_udp_src_port = -1;
76 static int hf_catapult_dct2000_ipprim_udp_dst_port = -1;
77 static int hf_catapult_dct2000_ipprim_udp_port = -1;
78 static int hf_catapult_dct2000_ipprim_tcp_src_port = -1;
79 static int hf_catapult_dct2000_ipprim_tcp_dst_port = -1;
80 static int hf_catapult_dct2000_ipprim_tcp_port = -1;
81 static int hf_catapult_dct2000_ipprim_conn_id = -1;
83 static int hf_catapult_dct2000_sctpprim_addresses = -1;
84 static int hf_catapult_dct2000_sctpprim_dst_addr_v4 = -1;
85 static int hf_catapult_dct2000_sctpprim_dst_addr_v6 = -1;
86 static int hf_catapult_dct2000_sctpprim_addr_v4 = -1;
87 static int hf_catapult_dct2000_sctpprim_addr_v6 = -1;
88 static int hf_catapult_dct2000_sctpprim_dst_port = -1;
90 static int hf_catapult_dct2000_lte_ueid = -1;
91 static int hf_catapult_dct2000_lte_srbid = -1;
92 static int hf_catapult_dct2000_lte_drbid = -1;
93 static int hf_catapult_dct2000_lte_cellid = -1;
94 static int hf_catapult_dct2000_lte_bcch_transport = -1;
95 static int hf_catapult_dct2000_lte_rlc_op = -1;
96 static int hf_catapult_dct2000_lte_rlc_channel_type = -1;
97 static int hf_catapult_dct2000_lte_rlc_mui = -1;
98 static int hf_catapult_dct2000_lte_rlc_cnf = -1;
99 static int hf_catapult_dct2000_lte_rlc_discard_req = -1;
101 static int hf_catapult_dct2000_lte_ccpri_opcode = -1;
102 static int hf_catapult_dct2000_lte_ccpri_status = -1;
103 static int hf_catapult_dct2000_lte_ccpri_channel = -1;
105 static int hf_catapult_dct2000_lte_nas_rrc_opcode = -1;
106 static int hf_catapult_dct2000_lte_nas_rrc_establish_cause = -1;
107 static int hf_catapult_dct2000_lte_nas_rrc_priority = -1;
108 static int hf_catapult_dct2000_lte_nas_rrc_release_cause = -1;
111 /* UMTS RLC fields */
112 static int hf_catapult_dct2000_ueid = -1;
113 static int hf_catapult_dct2000_rbid = -1;
114 static int hf_catapult_dct2000_ccch_id = -1;
115 static int hf_catapult_dct2000_no_crc_error = -1;
116 static int hf_catapult_dct2000_crc_error = -1;
117 static int hf_catapult_dct2000_clear_tx_buffer = -1;
118 static int hf_catapult_dct2000_buffer_occupancy = -1;
119 static int hf_catapult_dct2000_pdu_size = -1;
120 static int hf_catapult_dct2000_ueid_type = -1;
121 static int hf_catapult_dct2000_tx_priority = -1;
122 static int hf_catapult_dct2000_last_in_seg_set = -1;
123 static int hf_catapult_dct2000_rx_timing_deviation = -1;
124 static int hf_catapult_dct2000_transport_channel_type = -1;
125 static int hf_catapult_dct2000_no_padding_bits = -1;
127 /* Variables used for preferences */
128 static gboolean catapult_dct2000_try_ipprim_heuristic = TRUE;
129 static gboolean catapult_dct2000_try_sctpprim_heuristic = TRUE;
130 static gboolean catapult_dct2000_dissect_lte_rrc = TRUE;
131 static gboolean catapult_dct2000_dissect_lte_s1ap = TRUE;
132 static gboolean catapult_dct2000_dissect_mac_lte_oob_messages = TRUE;
134 /* Protocol subtree. */
135 static int ett_catapult_dct2000 = -1;
136 static int ett_catapult_dct2000_ipprim = -1;
137 static int ett_catapult_dct2000_sctpprim = -1;
138 static int ett_catapult_dct2000_tty = -1;
140 static expert_field ei_catapult_dct2000_lte_ccpri_status_error = EI_INIT;
141 static expert_field ei_catapult_dct2000_error_comment_expert = EI_INIT;
143 static const value_string direction_vals[] = {
144 { 0, "Sent" },
145 { 1, "Received" },
146 { 0, NULL },
149 static const value_string encap_vals[] = {
150 { WTAP_ENCAP_RAW_IP, "Raw IP" },
151 { WTAP_ENCAP_ETHERNET, "Ethernet" },
152 { WTAP_ENCAP_ISDN, "LAPD" },
153 { WTAP_ENCAP_ATM_PDUS_UNTRUNCATED, "ATM (PDUs untruncated)" },
154 { WTAP_ENCAP_PPP, "PPP" },
155 { DCT2000_ENCAP_SSCOP, "SSCOP" },
156 { WTAP_ENCAP_FRELAY, "Frame Relay" },
157 { WTAP_ENCAP_MTP2, "MTP2" },
158 { DCT2000_ENCAP_NBAP, "NBAP" },
159 { DCT2000_ENCAP_UNHANDLED, "No Direct Encapsulation" },
160 { 0, NULL },
163 static const value_string bcch_transport_vals[] = {
164 { BCH_TRANSPORT, "BCH" },
165 { DLSCH_TRANSPORT, "DLSCH" },
166 { 0, NULL },
170 #define RLC_MGMT_ASSIGN 0x41
171 #define RLC_AM_DATA_REQ 0x60
172 #define RLC_AM_DATA_IND 0x61
173 #define RLC_AM_DATA_CONF 0x62
174 #define RLC_UM_DATA_REQ 0x70
175 #define RLC_UM_DATA_IND 0x71
176 #define RLC_UM_DATA_CONF 0x74
177 #define RLC_TR_DATA_REQ 0x80
178 #define RLC_TR_DATA_IND 0x81
179 #define RLC_TR_DATA_CONF 0x83
181 static const value_string rlc_op_vals[] = {
182 { RLC_AM_DATA_REQ, "[UL] [AM]" },
183 { RLC_AM_DATA_IND, "[DL] [AM]" },
184 { RLC_UM_DATA_REQ, "[UL] [UM]"},
185 { RLC_UM_DATA_IND, "[DL] [UM]"},
186 { RLC_TR_DATA_REQ, "[UL] [TM]"},
187 { RLC_TR_DATA_IND, "[DL] [TM]"},
188 { 0, NULL }
192 static const value_string rlc_logical_channel_vals[] = {
193 { Channel_DCCH, "DCCH"},
194 { Channel_BCCH, "BCCH"},
195 { Channel_CCCH, "CCCH"},
196 { Channel_PCCH, "PCCH"},
197 { 0, NULL}
201 #define CCPRI_REQ 1
202 #define CCPRI_IND 2
204 static const value_string ccpri_opcode_vals[] = {
205 { CCPRI_REQ, "REQUEST"},
206 { CCPRI_IND, "INDICATION"},
207 { 0, NULL}
210 static const value_string ccpri_status_vals[] = {
211 { 0, "OK"},
212 { 1, "ERROR"},
213 { 0, NULL}
216 static const value_string rlc_rbid_vals[] = {
217 { 1, "DCH1"},
218 { 2, "DCH2"},
219 { 3, "DCH3"},
220 { 4, "DCH4"},
221 { 5, "DCH5"},
222 { 6, "DCH6"},
223 { 7, "DCH7"},
224 { 8, "DCH8"},
225 { 9, "DCH9"},
226 { 10, "DCH10"},
227 { 11, "DCH11"},
228 { 12, "DCH12"},
229 { 13, "DCH13"},
230 { 14, "DCH14"},
231 { 15, "DCH15"},
232 { 17, "BCCH"},
233 { 18, "CCCH"},
234 { 19, "PCCH"},
235 { 20, "SHCCH"},
236 { 21, "CTCH"},
237 { 23, "MCCH"},
238 { 24, "MSCH"},
239 { 25, "MTCH"},
240 { 0, NULL}
243 static const value_string ueid_type_vals[] = {
244 { 0, "URNTI"},
245 { 1, "CRNTI"},
246 { 0, NULL}
249 static const value_string tx_priority_vals[] = {
250 { 0, "Normal"},
251 { 1, "High"},
252 { 0, NULL}
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}
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
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}
283 #define MAX_OUTHDR_VALUES 32
285 static guint outhdr_values[MAX_OUTHDR_VALUES];
286 static guint outhdr_values_found = 0;
288 extern int proto_fp;
289 extern int proto_rlc;
291 extern int proto_rlc_lte;
292 extern int proto_pdcp_lte;
294 static dissector_handle_t mac_lte_handle;
295 static dissector_handle_t rlc_lte_handle;
296 static dissector_handle_t pdcp_lte_handle;
298 void proto_register_catapult_dct2000(void);
300 static dissector_handle_t look_for_dissector(const char *protocol_name);
301 static void parse_outhdr_string(const guchar *outhdr_string, gint outhdr_length);
303 static void attach_fp_info(packet_info *pinfo, gboolean received,
304 const char *protocol_name, int variant);
305 static void attach_rlc_info(packet_info *pinfo, guint32 urnti, guint8 rbid,
306 gboolean is_sent);
308 static void attach_mac_lte_info(packet_info *pinfo);
309 static void attach_rlc_lte_info(packet_info *pinfo);
310 static void attach_pdcp_lte_info(packet_info *pinfo);
314 /* Return the number of bytes used to encode the length field
315 (we're not interested in the length value itself) */
316 static int skipASNLength(guint8 value)
318 if ((value & 0x80) == 0)
320 return 1;
322 else
324 return ((value & 0x03) == 1) ? 2 : 3;
329 /* Look for the protocol data within an ipprim packet.
330 Only set *data_offset if data field found. */
331 static gboolean find_ipprim_data_offset(tvbuff_t *tvb, int *data_offset, guint8 direction,
332 guint32 *source_addr_offset, guint8 *source_addr_length,
333 guint32 *dest_addr_offset, guint8 *dest_addr_length,
334 guint32 *source_port_offset, guint32 *dest_port_offset,
335 port_type *type_of_port,
336 guint16 *conn_id_offset)
338 guint8 length;
339 int offset = *data_offset;
341 /* Get the ipprim command code. */
342 guint8 tag = tvb_get_guint8(tvb, offset++);
344 /* Only accept UDP or TCP data request or indication */
345 switch (tag) {
346 case 0x23: /* UDP data request */
347 case 0x24: /* UDP data indication */
348 *type_of_port = PT_UDP;
349 break;
350 case 0x45: /* TCP data request */
351 case 0x46: /* TCP data indication */
352 *type_of_port = PT_TCP;
353 break;
354 default:
355 return FALSE;
358 /* Skip any other TLC fields before reach payload */
359 while (tvb_length_remaining(tvb, offset) > 2) {
360 /* Look at next tag */
361 tag = tvb_get_guint8(tvb, offset++);
363 /* Is this the data payload we're expecting? */
364 if (((tag == 0x34) && (*type_of_port == PT_UDP)) ||
365 ((tag == 0x48) && (*type_of_port == PT_TCP))) {
367 *data_offset = offset;
368 return TRUE;
370 else {
371 /* Read length in next byte */
372 length = tvb_get_guint8(tvb, offset++);
374 if (tag == 0x31 && length >=4) {
375 /* Remote IP address */
376 if (direction == 0) {
377 /* Sent *to* remote, so dest */
378 *dest_addr_offset = offset;
379 *dest_addr_length = (length/4) * 4;
381 else {
382 *source_addr_offset = offset;
383 *source_addr_length = (length/4) * 4;
386 /* Remote port follows (if present) */
387 if ((length % 4) == 2) {
388 if (direction == 0) {
389 *dest_port_offset = offset + *dest_addr_length;
391 else {
392 *source_port_offset = offset + *source_addr_length;
396 else
397 if (tag == 0x32) {
398 if (length == 4 || length == 16) {
399 /* Local IP address */
400 if (direction == 0) {
401 /* Sent *from* local, so source */
402 *source_addr_offset = offset;
403 *source_addr_length = length;
405 else {
406 *dest_addr_offset = offset;
407 *dest_addr_length = length;
411 else
412 if (tag == 0x33 && length == 2) {
413 /* Get local port */
414 if (direction == 0) {
415 /* Sent from local, so source */
416 *source_port_offset = offset;
418 else {
419 *dest_port_offset = offset;
422 else
423 if (tag == 0x36 && length == 2) {
424 /* Get conn_id */
425 *conn_id_offset = offset;
428 /* Skip the length of the indicated value */
429 offset += length;
433 /* No data found... */
434 return FALSE;
439 /* Look for the protocol data within an sctpprim (variant 1 or 2...) packet.
440 Only set *data_offset if data field found. */
441 static gboolean find_sctpprim_variant1_data_offset(tvbuff_t *tvb, int *data_offset,
442 guint32 *dest_addr_offset,
443 guint16 *dest_addr_length,
444 guint32 *dest_port_offset)
446 int offset = *data_offset;
448 /* Get the sctpprim command code. */
449 guint8 first_tag = tvb_get_guint8(tvb, offset++);
450 guint8 tag;
451 guint8 first_length_byte;
453 /* Only accept interested in data requests or indications */
454 switch (first_tag) {
455 case 0x04: /* data request */
456 case 0x62: /* data indication */
457 break;
458 default:
459 return FALSE;
462 first_length_byte = tvb_get_guint8(tvb, offset);
463 offset += skipASNLength(first_length_byte);
465 /* Skip any other fields before reach payload */
466 while (tvb_length_remaining(tvb, offset) > 2) {
467 /* Look at next tag */
468 tag = tvb_get_guint8(tvb, offset++);
470 /* Is this the data payload we're expecting? */
471 if (tag == 0x19) {
472 *data_offset = offset;
473 return TRUE;
475 else {
476 /* Skip length field */
477 offset++;
478 switch (tag) {
479 case 0x0a: /* destPort */
480 *dest_port_offset = offset;
481 offset += 2;
482 break;
484 case 0x01: /* sctpInstanceNum */
485 case 0x1e: /* strseqnum */
486 case 0x0d: /* streamnum */
487 offset += 2;
488 continue;
490 case 0x09: /* ipv4Address */
491 *dest_addr_offset = offset;
492 *dest_addr_length = 4;
493 offset += 4;
494 break;
496 case 0x1d:
497 case 0x0c: /* payloadType */
498 offset += 4;
499 continue;
501 default:
502 /* Fail if not a known header field */
503 return FALSE;
508 /* No data found... */
509 return FALSE;
512 /* Look for the protocol data within an sctpprim (variant 3) packet.
513 Only set *data_offset if data field found. */
514 static gboolean find_sctpprim_variant3_data_offset(tvbuff_t *tvb, int *data_offset,
515 guint32 *dest_addr_offset,
516 guint16 *dest_addr_length,
517 guint32 *dest_port_offset)
519 guint16 tag = 0;
520 guint16 length = 0;
521 int offset = *data_offset;
523 /* Get the sctpprim (2 byte) command code. */
524 guint16 top_tag = tvb_get_ntohs(tvb, offset);
525 offset += 2;
527 /* Only interested in data requests or indications */
528 switch (top_tag) {
529 case 0x0400: /* SendDataReq */
530 case 0x6200: /* DataInd */
531 break;
533 default:
534 return FALSE;
537 /* Overall length field is next 2 bytes */
538 offset += 2;
540 /* Rx/Tx ops have different formats */
542 /*****************/
543 /* DataInd */
544 if (top_tag == 0x6200) {
545 /* Next 2 bytes are associate ID */
546 offset += 2;
548 /* Next 2 bytes are destination port */
549 *dest_port_offset = offset;
550 offset += 2;
552 /* Destination address should follow - check tag */
553 tag = tvb_get_ntohs(tvb, offset);
554 if (tag != 0x0900) {
555 return FALSE;
557 else {
558 /* Skip tag */
559 offset += 2;
561 /* Length field */
562 length = tvb_get_ntohs(tvb, offset) / 2;
563 if ((length != 4) && (length != 16))
565 return FALSE;
567 offset += 2;
569 /* Address data is here */
570 *dest_addr_offset = offset;
571 *dest_addr_length = length;
573 offset += length;
576 /* Not interested in remaining (fixed) fields */
577 if (tvb_reported_length_remaining(tvb, offset) > (4 + 2 + 2 + 4)) {
578 offset += (4 + 2 + 2 + 4);
580 else {
581 return FALSE;
584 /* Data should now be here */
585 tag = tvb_get_ntohs(tvb, offset);
586 offset += 2;
587 if (tag == 0x1900) {
588 /* 2-byte length field */
589 offset += 2;
591 /* Data is here!!! */
592 *data_offset = offset;
593 return TRUE;
595 else {
596 return FALSE;
600 /***************/
601 /* SendDataReq */
602 else if (top_tag == 0x0400) {
603 /* AssociateId should follow - check tag */
604 tag = tvb_get_ntohs(tvb, offset);
605 if (tag != 0x2400) {
606 return FALSE;
608 else {
609 /* Skip tag */
610 offset += 2;
612 /* Skip 2-byte value */
613 offset += 2;
616 /* Get tag */
617 tag = tvb_get_ntohs(tvb, offset);
618 offset += 2;
620 /* Some optional params */
621 while ((tag != 0x0c00) && (tvb_length_remaining(tvb, offset) > 4)) {
622 switch (tag) {
623 case 0x0900: /* Dest address */
624 /* Length field */
625 length = tvb_get_ntohs(tvb, offset) / 2;
626 if ((length != 4) && (length != 16)) {
627 return FALSE;
629 offset += 2;
631 /* Address data is here */
632 *dest_addr_offset = offset;
633 *dest_addr_length = length;
635 offset += length;
636 break;
638 case 0x0a00: /* Dest port number */
639 *dest_port_offset = offset;
640 offset += 2;
641 break;
643 case 0x0d00: /* StreamNum */
644 *dest_port_offset = offset;
645 offset += 2;
646 break;
649 default:
650 return FALSE;
653 /* Get the next tag */
654 tag = tvb_get_ntohs(tvb, offset);
655 offset += 2;
659 /* Mandatory payload type */
660 if (tag != 0x0c00) {
661 return FALSE;
663 length = tvb_get_ntohs(tvb, offset) / 2;
664 offset += 2;
665 offset += length;
668 /* Optional options */
669 tag = tvb_get_ntohs(tvb, offset);
670 offset += 2;
671 if (tag == 0x0b00) {
672 length = tvb_get_ntohs(tvb, offset) / 2;
673 offset += 2;
675 offset += length;
677 /* Get next tag */
678 tag = tvb_get_ntohs(tvb, offset);
679 offset += 2;
683 /* Data should now be here!! */
684 if (tag == 0x1900) {
685 /* 2-byte length field */
686 offset += 2;
688 /* Data is here!!! */
689 *data_offset = offset;
690 return TRUE;
692 else {
693 return FALSE;
697 return FALSE;
701 /* Dissect a UMTS RLC frame by:
702 - parsing the primitive header
703 - passing those values + outhdeader to dissector
704 - calling the UMTS RLC dissector */
705 static void dissect_rlc_umts(tvbuff_t *tvb, gint offset,
706 packet_info *pinfo, proto_tree *tree,
707 gboolean is_sent)
709 guint8 tag;
710 gboolean ueid_set = FALSE, rbid_set=FALSE;
711 guint32 ueid = 0;
712 guint8 rbid = 0;
713 guint8 length;
714 tvbuff_t *rlc_tvb;
715 dissector_handle_t rlc_umts_handle = 0;
717 /* Top-level opcode */
718 tag = tvb_get_guint8(tvb, offset++);
719 switch (tag) {
720 case 0xc0: /* mac data request */
721 case 0xc1: /* mac data indication */
722 break;
724 default:
725 /* No data to dissect */
726 return;
729 /* Keep going until reach data tag or end of frame */
730 while ((tag != 0x41) && tvb_length_remaining(tvb, offset)) { /* i.e. Data */
731 tag = tvb_get_guint8(tvb, offset++);
732 switch (tag) {
733 case 0x72: /* UE Id */
734 ueid = tvb_get_ntohl(tvb, offset);
735 proto_tree_add_item(tree, hf_catapult_dct2000_ueid, tvb, offset, 4, ENC_BIG_ENDIAN);
736 offset += 4;
737 ueid_set = TRUE;
738 break;
739 case 0xa2: /* RBID */
740 offset++; /* skip length */
741 rbid = tvb_get_guint8(tvb, offset);
742 proto_tree_add_item(tree, hf_catapult_dct2000_rbid, tvb, offset, 1, ENC_BIG_ENDIAN);
743 offset++;
744 rbid_set = TRUE;
745 break;
746 case 0x22: /* CCCH-id setting rbid to CCCH! */
747 offset++; /* skip length */
748 proto_tree_add_item(tree, hf_catapult_dct2000_ccch_id, tvb, offset, 1, ENC_BIG_ENDIAN);
749 offset++;
750 rbid = 18;
751 break;
752 case 0xc4: /* No CRC error */
753 proto_tree_add_item(tree, hf_catapult_dct2000_no_crc_error, tvb, offset-1, 1, ENC_NA);
754 break;
755 case 0xc5: /* CRC error */
756 proto_tree_add_item(tree, hf_catapult_dct2000_crc_error, tvb, offset-1, 1, ENC_NA);
757 break;
758 case 0xf7: /* Clear Tx Buffer */
759 proto_tree_add_item(tree, hf_catapult_dct2000_clear_tx_buffer, tvb, offset-1, 1, ENC_NA);
760 break;
762 case 0x41: /* Data !!! */
763 offset += skipASNLength(tvb_get_guint8(tvb, offset));
764 break;
766 default:
767 /* For other fields, just skip length and following data */
768 length = tvb_get_guint8(tvb, offset++);
769 switch (tag) {
770 case 0x42: /* Buffer Occupancy */
771 proto_tree_add_item(tree, hf_catapult_dct2000_buffer_occupancy, tvb, offset, length, ENC_BIG_ENDIAN);
772 break;
773 case 0x49: /* PDU Size */
774 proto_tree_add_item(tree, hf_catapult_dct2000_pdu_size, tvb, offset, 2, ENC_LITTLE_ENDIAN);
775 break;
776 case 0x47: /* UEId type */
777 proto_tree_add_item(tree, hf_catapult_dct2000_ueid_type, tvb, offset, 1, ENC_BIG_ENDIAN);
778 break;
779 case 0x4e: /* Tx Priority */
780 proto_tree_add_item(tree, hf_catapult_dct2000_tx_priority, tvb, offset, 1, ENC_BIG_ENDIAN);
781 break;
782 case 0x4c: /* Last in seg set */
783 proto_tree_add_item(tree, hf_catapult_dct2000_last_in_seg_set, tvb, offset, 1, ENC_BIG_ENDIAN);
784 break;
785 case 0x43: /* Rx timing deviation */
786 proto_tree_add_item(tree, hf_catapult_dct2000_rx_timing_deviation, tvb, offset, 1, ENC_BIG_ENDIAN);
787 break;
788 case 0x46: /* Transport channel type */
789 proto_tree_add_item(tree, hf_catapult_dct2000_transport_channel_type, tvb, offset, 1, ENC_BIG_ENDIAN);
790 break;
791 case 0xc2: /* Number of padding bits */
792 proto_tree_add_item(tree, hf_catapult_dct2000_no_padding_bits, tvb, offset, 1, ENC_BIG_ENDIAN);
793 break;
795 default:
796 break;
800 offset += length;
804 /* Have we got enough info to call dissector */
805 if ((tag == 0x41) && ueid_set && rbid_set) {
806 attach_rlc_info(pinfo, ueid, rbid, is_sent);
808 /* Set appropriate RLC dissector handle */
809 switch (rbid) {
810 case 1: case 2: case 3: case 4: case 5:
811 case 6: case 7: case 8: case 9: case 10:
812 case 11: case 12: case 13: case 14: case 15:
813 /* DCH channels. */
814 /* TODO: can't really tell if these are control or transport...
815 maybe control with preferences (UAT?) between "rlc.ps_dtch" and "rlc.dcch" ? */
816 rlc_umts_handle = find_dissector("rlc.dch_unknown");
817 break;
818 case 18:
819 rlc_umts_handle = find_dissector("rlc.ccch");
820 break;
821 case 21:
822 rlc_umts_handle = find_dissector("rlc.ctch");
823 break;
825 default:
826 /* Give up here */
827 return;
830 /* Call UMTS RLC dissector */
831 if (rlc_umts_handle != 0) {
832 rlc_tvb = tvb_new_subset_remaining(tvb, offset);
833 call_dissector_only(rlc_umts_handle, rlc_tvb, pinfo, tree, NULL);
840 /* Dissect an RRC LTE frame by first parsing the header entries then passing
841 the data to the RRC dissector, according to direction and channel type.
842 TODO: factor out common code between this function and dissect_pdcp_lte() */
843 static void dissect_rrc_lte(tvbuff_t *tvb, gint offset,
844 packet_info *pinfo, proto_tree *tree)
846 guint8 tag;
847 dissector_handle_t protocol_handle = 0;
848 gboolean isUplink = FALSE;
849 LogicalChannelType logicalChannelType;
850 guint16 cell_id;
851 guint8 bcch_transport = 0;
852 tvbuff_t *rrc_tvb;
854 /* Top-level opcode */
855 tag = tvb_get_guint8(tvb, offset++);
856 switch (tag) {
857 case 0x00: /* Data_Req_UE */
858 case 0x04: /* Data_Ind_eNodeB */
859 isUplink = TRUE;
860 break;
862 case 0x02: /* Data_Req_eNodeB */
863 case 0x03: /* Data_Ind_UE */
864 isUplink = FALSE;
865 break;
867 default:
868 /* Unexpected opcode tag! */
869 return;
872 /* Skip length */
873 offset += skipASNLength(tvb_get_guint8(tvb, offset));
875 /* Get next tag */
876 tag = tvb_get_guint8(tvb, offset++);
877 switch (tag) {
878 case 0x12: /* UE_Id_LCId */
880 /* Dedicated channel info */
882 /* Length will fit in one byte here */
883 offset++;
885 logicalChannelType = Channel_DCCH;
887 /* UEId */
888 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid, tvb, offset, 2, ENC_BIG_ENDIAN);
889 offset += 2;
891 /* Get tag of channel type */
892 tag = tvb_get_guint8(tvb, offset++);
894 switch (tag) {
895 case 0:
896 offset++;
897 col_append_fstr(pinfo->cinfo, COL_INFO, " SRB:%u",
898 tvb_get_guint8(tvb, offset));
899 proto_tree_add_item(tree, hf_catapult_dct2000_lte_srbid,
900 tvb, offset, 1, ENC_BIG_ENDIAN);
901 offset++;
902 break;
903 case 1:
904 offset++;
905 col_append_fstr(pinfo->cinfo, COL_INFO, " DRB:%u",
906 tvb_get_guint8(tvb, offset));
907 proto_tree_add_item(tree, hf_catapult_dct2000_lte_drbid,
908 tvb, offset, 1, ENC_BIG_ENDIAN);
909 offset++;
910 break;
912 default:
913 /* Unexpected channel type */
914 return;
916 break;
918 case 0x1a: /* Cell_LCId */
920 /* Common channel info */
922 /* Skip length */
923 offset++;
925 /* Cell-id */
926 proto_tree_add_item(tree, hf_catapult_dct2000_lte_cellid,
927 tvb, offset, 2, ENC_BIG_ENDIAN);
928 cell_id = tvb_get_ntohs(tvb, offset);
929 offset += 2;
931 /* Logical channel type */
932 proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_channel_type,
933 tvb, offset, 1, ENC_BIG_ENDIAN);
934 logicalChannelType = (LogicalChannelType)tvb_get_guint8(tvb, offset);
935 offset++;
937 /* Won't be seen if RRC decoder is called... */
938 col_append_fstr(pinfo->cinfo, COL_INFO, " cell-id=%u %s",
939 cell_id,
940 val_to_str_const(logicalChannelType, rlc_logical_channel_vals,
941 "UNKNOWN-CHANNEL"));
944 switch (logicalChannelType) {
945 case Channel_BCCH:
946 /* Skip length */
947 offset++;
949 /* Transport channel type */
950 bcch_transport = tvb_get_guint8(tvb, offset);
951 proto_tree_add_item(tree, hf_catapult_dct2000_lte_bcch_transport,
952 tvb, offset, 1, ENC_BIG_ENDIAN);
953 offset++;
954 break;
956 case Channel_CCCH:
957 /* Skip length */
958 offset++;
960 /* UEId */
961 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
962 tvb, offset, 2, ENC_BIG_ENDIAN);
963 offset += 2;
964 break;
966 default:
967 break;
969 break;
971 default:
972 /* Unexpected tag */
973 return;
976 /* Data tag should follow */
977 tag = tvb_get_guint8(tvb, offset++);
978 if (tag != 0xaa) {
979 return;
982 /* Skip length */
983 offset += skipASNLength(tvb_get_guint8(tvb, offset));
985 /* Look up dissector handle corresponding to direction and channel type */
986 if (isUplink) {
988 /* Uplink channel types */
989 switch (logicalChannelType) {
990 case Channel_DCCH:
991 protocol_handle = find_dissector("lte_rrc.ul_dcch");
992 break;
993 case Channel_CCCH:
994 protocol_handle = find_dissector("lte_rrc.ul_ccch");
995 break;
997 default:
998 /* Unknown Uplink channel type */
999 break;
1001 } else {
1003 /* Downlink channel types */
1004 switch (logicalChannelType) {
1005 case Channel_DCCH:
1006 protocol_handle = find_dissector("lte_rrc.dl_dcch");
1007 break;
1008 case Channel_CCCH:
1009 protocol_handle = find_dissector("lte_rrc.dl_ccch");
1010 break;
1011 case Channel_PCCH:
1012 protocol_handle = find_dissector("lte_rrc.pcch");
1013 break;
1014 case Channel_BCCH:
1015 if (bcch_transport == 1) {
1016 protocol_handle = find_dissector("lte_rrc.bcch_bch");
1018 else {
1019 protocol_handle = find_dissector("lte_rrc.bcch_dl_sch");
1021 break;
1023 default:
1024 /* Unknown Downlink channel type */
1025 break;
1029 /* Send to RRC dissector, if got here, have sub-dissector and some data left */
1030 if ((protocol_handle != NULL) && (tvb_length_remaining(tvb, offset) > 0)) {
1031 rrc_tvb = tvb_new_subset_remaining(tvb, offset);
1032 call_dissector_only(protocol_handle, rrc_tvb, pinfo, tree, NULL);
1037 /* Dissect an CCPRI LTE frame by first parsing the header entries then passing
1038 the data to the CPRI C&M dissector */
1039 static void dissect_ccpri_lte(tvbuff_t *tvb, gint offset,
1040 packet_info *pinfo, proto_tree *tree)
1042 guint8 opcode;
1043 guint8 tag;
1044 tvbuff_t *ccpri_tvb;
1045 dissector_handle_t protocol_handle = 0;
1046 guint16 length;
1048 /* Top-level opcode */
1049 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ccpri_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
1050 opcode = tvb_get_guint8(tvb, offset++);
1052 /* Skip 2-byte length field */
1053 offset += 2;
1055 /* Cell-id */
1056 proto_tree_add_item(tree, hf_catapult_dct2000_lte_cellid,
1057 tvb, offset, 2, ENC_BIG_ENDIAN);
1058 offset += 2;
1060 /* Status (ind only) */
1061 if (opcode == 2) {
1062 proto_item *ti;
1063 guint8 status = tvb_get_guint8(tvb, offset);
1064 ti = proto_tree_add_item(tree, hf_catapult_dct2000_lte_ccpri_status,
1065 tvb, offset, 1, ENC_BIG_ENDIAN);
1066 offset++;
1068 if (status != 0) {
1069 expert_add_info(pinfo, ti, &ei_catapult_dct2000_lte_ccpri_status_error);
1074 /* Channel ID */
1075 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ccpri_channel,
1076 tvb, offset, 1, ENC_BIG_ENDIAN);
1077 offset++;
1079 /* Data tag must follow */
1080 tag = tvb_get_guint8(tvb, offset++);
1081 if (tag != 2) {
1082 return;
1085 /* Skip length */
1086 length = tvb_get_ntohs(tvb, offset);
1087 offset += 2;
1089 /* Send remainder to lapb dissector (lapb needs patch with preference
1090 set to call cpri C&M dissector instead of X.25) */
1091 protocol_handle = find_dissector("lapb");
1092 if ((protocol_handle != NULL) && (tvb_length_remaining(tvb, offset) > 0)) {
1093 ccpri_tvb = tvb_new_subset(tvb, offset, length, length);
1094 call_dissector_only(protocol_handle, ccpri_tvb, pinfo, tree, NULL);
1101 /* Dissect a PDCP LTE frame by first parsing the RLCPrim header then passing
1102 the data to the PDCP LTE dissector */
1103 static void dissect_pdcp_lte(tvbuff_t *tvb, gint offset,
1104 packet_info *pinfo, proto_tree *tree)
1106 guint8 opcode;
1107 guint8 tag;
1108 struct pdcp_lte_info *p_pdcp_lte_info = NULL;
1109 tvbuff_t *pdcp_lte_tvb;
1110 guint16 ueid;
1111 guint8 channelId;
1113 /* Look this up so can update channel info */
1114 p_pdcp_lte_info = (struct pdcp_lte_info *)p_get_proto_data(pinfo->fd, proto_pdcp_lte, 0);
1115 if (p_pdcp_lte_info == NULL) {
1116 /* This really should be set...can't dissect anything without it */
1117 return;
1120 /* Top-level opcode */
1121 opcode = tvb_get_guint8(tvb, offset);
1122 if (tree) {
1123 proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_op, tvb, offset, 1, ENC_BIG_ENDIAN);
1125 offset++;
1127 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(opcode, rlc_op_vals, "Unknown"));
1129 /* Assume UE side, so REQ is UL, IND is DL */
1130 switch (opcode) {
1131 case RLC_AM_DATA_REQ:
1132 case RLC_UM_DATA_REQ:
1133 case RLC_TR_DATA_REQ:
1134 p_pdcp_lte_info->direction = DIRECTION_UPLINK;
1135 break;
1137 default:
1138 p_pdcp_lte_info->direction = DIRECTION_DOWNLINK;
1141 /* Parse header */
1142 switch (opcode) {
1143 case RLC_AM_DATA_REQ:
1144 case RLC_AM_DATA_IND:
1145 case RLC_UM_DATA_REQ:
1146 case RLC_UM_DATA_IND:
1147 case RLC_TR_DATA_REQ:
1148 case RLC_TR_DATA_IND:
1150 /* Get next tag */
1151 tag = tvb_get_guint8(tvb, offset++);
1152 switch (tag) {
1153 case 0x10: /* UE_Id_LCId */
1155 /* Dedicated channel info */
1157 /* Length will fit in one byte here */
1158 offset++;
1160 p_pdcp_lte_info->channelType = Channel_DCCH;
1162 /* UEId */
1163 ueid = tvb_get_ntohs(tvb, offset);
1164 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid, tvb, offset, 2, ENC_BIG_ENDIAN);
1165 col_append_fstr(pinfo->cinfo, COL_INFO,
1166 " UEId=%u", ueid);
1167 p_pdcp_lte_info->ueid = ueid;
1168 offset += 2;
1170 /* Get tag of channel type */
1171 tag = tvb_get_guint8(tvb, offset++);
1173 switch (tag) {
1174 case 0:
1175 offset++;
1176 channelId = tvb_get_guint8(tvb, offset);
1177 col_append_fstr(pinfo->cinfo, COL_INFO, " SRB:%u",
1178 channelId);
1179 proto_tree_add_item(tree, hf_catapult_dct2000_lte_srbid,
1180 tvb, offset++, 1, ENC_BIG_ENDIAN);
1181 p_pdcp_lte_info->channelId = channelId;
1182 break;
1183 case 1:
1184 offset++;
1185 channelId = tvb_get_guint8(tvb, offset);
1186 col_append_fstr(pinfo->cinfo, COL_INFO, " DRB:%u",
1187 channelId);
1188 proto_tree_add_item(tree, hf_catapult_dct2000_lte_drbid,
1189 tvb, offset++, 1, ENC_BIG_ENDIAN);
1190 p_pdcp_lte_info->channelId = channelId;
1191 break;
1193 default:
1194 /* Unexpected channel type */
1195 return;
1197 break;
1199 case 0x1a: /* Cell_LCId */
1201 /* Common channel info */
1203 /* Skip length */
1204 offset++;
1206 /* Cell-id */
1207 proto_tree_add_item(tree, hf_catapult_dct2000_lte_cellid,
1208 tvb, offset, 2, ENC_BIG_ENDIAN);
1209 offset += 2;
1211 /* Logical channel type */
1212 proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_channel_type,
1213 tvb, offset, 1, ENC_BIG_ENDIAN);
1214 p_pdcp_lte_info->channelType = (LogicalChannelType)tvb_get_guint8(tvb, offset++);
1215 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
1216 val_to_str_const(p_pdcp_lte_info->channelType, rlc_logical_channel_vals,
1217 "UNKNOWN-CHANNEL"));
1219 switch (p_pdcp_lte_info->channelType) {
1220 case Channel_BCCH:
1221 /* Skip length */
1222 offset++;
1224 /* Transport channel type */
1225 p_pdcp_lte_info->BCCHTransport = (BCCHTransportType)tvb_get_guint8(tvb, offset);
1226 proto_tree_add_item(tree, hf_catapult_dct2000_lte_bcch_transport,
1227 tvb, offset, 1, ENC_BIG_ENDIAN);
1228 offset++;
1229 break;
1231 case Channel_CCCH:
1232 /* Skip length */
1233 offset++;
1235 /* UEId */
1236 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
1237 tvb, offset, 2, ENC_BIG_ENDIAN);
1238 ueid = tvb_get_ntohs(tvb, offset);
1239 offset += 2;
1241 col_append_fstr(pinfo->cinfo, COL_INFO, " UEId=%u", ueid);
1242 break;
1244 default:
1245 break;
1247 break;
1249 default:
1250 /* Unexpected tag */
1251 return;
1254 /* Other optional fields may follow */
1255 tag = tvb_get_guint8(tvb, offset++);
1256 while ((tag != 0x41) && (tvb_length_remaining(tvb, offset) > 2)) {
1258 if (tag == 0x35) {
1259 /* This is MUI */
1260 offset++;
1261 proto_tree_add_item(tree, hf_catapult_dct2000_lte_rlc_mui,
1262 tvb, offset, 2, ENC_BIG_ENDIAN);
1263 offset += 2;
1265 /* CNF follows MUI in AM */
1266 if ((opcode == RLC_AM_DATA_REQ) || (opcode == RLC_AM_DATA_IND)) {
1267 proto_tree_add_boolean(tree, hf_catapult_dct2000_lte_rlc_cnf,
1268 tvb, offset, 1, tvb_get_guint8(tvb, offset));
1269 offset++;
1272 else if (tag == 0x45) {
1273 /* Discard Req */
1274 offset++;
1275 proto_tree_add_boolean(tree, hf_catapult_dct2000_lte_rlc_discard_req,
1276 tvb, offset, 1, tvb_get_guint8(tvb, offset));
1277 offset++;
1280 tag = tvb_get_guint8(tvb, offset++);
1284 /********************************/
1285 /* Should be at data tag now */
1287 /* Call PDCP LTE dissector */
1288 pdcp_lte_tvb = tvb_new_subset_remaining(tvb, offset);
1289 call_dissector_only(pdcp_lte_handle, pdcp_lte_tvb, pinfo, tree, NULL);
1291 break;
1293 default:
1294 return;
1302 /* Look up dissector by protocol name. Fix up known name mis-matches.
1303 This includes exact matches and prefixes (e.g. "diameter_rx" -> "diameter") */
1304 static dissector_handle_t look_for_dissector(const char *protocol_name)
1306 /* Use known aliases and protocol name prefixes */
1307 if (strcmp(protocol_name, "tbcp") == 0) {
1308 return find_dissector("rtcp");
1310 else
1311 if (strncmp(protocol_name, "diameter", strlen("diameter")) == 0) {
1312 return find_dissector("diameter");
1314 else
1315 if ((strcmp(protocol_name, "xcap_caps") == 0) ||
1316 (strcmp(protocol_name, "soap") == 0) ||
1317 (strcmp(protocol_name, "mm1") == 0) ||
1318 (strcmp(protocol_name, "mm3") == 0) ||
1319 (strcmp(protocol_name, "mm7") == 0)) {
1321 return find_dissector("http");
1323 else
1324 if ((strcmp(protocol_name, "fp") == 0) ||
1325 (strncmp(protocol_name, "fp_r", 4) == 0) ||
1326 (strcmp(protocol_name, "fpiur_r5") == 0)) {
1328 return find_dissector("fp");
1330 else
1331 if ((strcmp(protocol_name, "iuup_rtp_r5") == 0) ||
1332 (strcmp(protocol_name, "iuup_rtp_r6") == 0)) {
1334 return find_dissector("rtp");
1336 else
1337 if (strcmp(protocol_name, "sipt") == 0) {
1338 return find_dissector("sip");
1340 else
1341 if (strncmp(protocol_name, "nbap_sctp", strlen("nbap_sctp")) == 0) {
1342 return find_dissector("nbap");
1344 else
1345 if (strncmp(protocol_name, "gtp", strlen("gtp")) == 0) {
1346 return find_dissector("gtp");
1348 else
1349 if (strcmp(protocol_name, "dhcpv4") == 0) {
1350 return find_dissector("bootp");
1352 else
1353 if (strcmp(protocol_name, "wimax") == 0) {
1354 return find_dissector("wimaxasncp");
1356 else
1357 if (strncmp(protocol_name, "sabp", strlen("sabp")) == 0) {
1358 return find_dissector("sabp");
1360 else
1361 if (strcmp(protocol_name, "wtp") == 0) {
1362 return find_dissector("wtp-udp");
1364 else
1365 /* Only match with s1ap if preference turned on */
1366 if (catapult_dct2000_dissect_lte_s1ap &&
1367 strncmp(protocol_name, "s1ap", strlen("s1ap")) == 0) {
1369 return find_dissector("s1ap");
1371 else
1372 /* Always try lookup for now */
1373 if ((strncmp(protocol_name, "x2ap_r8_lte", strlen("x2ap_r8_lte")) == 0) ||
1374 (strncmp(protocol_name, "x2ap_r9_lte", strlen("x2ap_r9_lte")) == 0)) {
1376 return find_dissector("x2ap");
1379 else
1380 if ((strcmp(protocol_name, "gtpv2_r8_lte") == 0) ||
1381 (strcmp(protocol_name, "gtpv2_r9_lte") == 0)) {
1382 return find_dissector("gtpv2");
1386 /* Try for an exact match */
1387 else {
1388 return find_dissector(protocol_name);
1393 /* Populate outhdr_values array with numbers found in outhdr_string */
1394 static void parse_outhdr_string(const guchar *outhdr_string, gint outhdr_string_len)
1396 int n = 0;
1398 /* Populate values array */
1399 for (outhdr_values_found=0; outhdr_values_found < MAX_OUTHDR_VALUES; ) {
1401 guint digit_array[MAX_OUTHDR_VALUES];
1402 guint number_digits = 0;
1404 guint number = 0;
1405 guint multiplier = 1;
1406 guint d;
1408 /* Find digits */
1409 for ( ; n < outhdr_string_len; n++) {
1410 if (!isdigit(outhdr_string[n])) {
1411 break;
1413 else {
1414 digit_array[number_digits++] = outhdr_string[n] - '0';
1418 if (number_digits == 0) {
1419 /* No more numbers left */
1420 break;
1423 /* Convert digits into value (much faster than format_text() + atoi()) */
1424 for (d=number_digits; d > 0; d--) {
1425 number += ((digit_array[d-1]) * multiplier);
1426 multiplier *= 10;
1428 outhdr_values[outhdr_values_found++] = number;
1430 /* Skip comma */
1431 n++;
1437 /* Fill in an FP packet info struct and attach it to the packet for the FP
1438 dissector to use */
1439 static void attach_fp_info(packet_info *pinfo, gboolean received, const char *protocol_name, int variant)
1441 int i=0;
1442 int chan;
1443 int tf_start, num_chans_start;
1444 gint node_type;
1445 int calculated_variant;
1447 /* Only need to set info once per session. */
1448 struct fp_info *p_fp_info = (struct fp_info *)p_get_proto_data(pinfo->fd, proto_fp, 0);
1449 if (p_fp_info != NULL) {
1450 return;
1453 /* Allocate struct */
1454 p_fp_info = wmem_new0(wmem_file_scope(), struct fp_info);
1456 /* Check that the number of outhdr values looks sensible */
1457 if (((strcmp(protocol_name, "fpiur_r5") == 0) && (outhdr_values_found != 2)) ||
1458 (outhdr_values_found < 5)) {
1460 return;
1463 /* 3gpp release (99, 4, 5, 6, 7) */
1464 if (strcmp(protocol_name, "fp") == 0) {
1465 p_fp_info->release = 99;
1467 else if (strcmp(protocol_name, "fp_r4") == 0) {
1468 p_fp_info->release = 4;
1470 else if (strcmp(protocol_name, "fp_r5") == 0) {
1471 p_fp_info->release = 5;
1473 else if (strcmp(protocol_name, "fp_r6") == 0) {
1474 p_fp_info->release = 6;
1476 else if (strcmp(protocol_name, "fp_r7") == 0) {
1477 p_fp_info->release = 7;
1479 else if (strcmp(protocol_name, "fp_r8") == 0) {
1480 p_fp_info->release = 8;
1482 else if (strcmp(protocol_name, "fpiur_r5") == 0) {
1483 p_fp_info->release = 5;
1485 else {
1486 /* Really shouldn't get here */
1487 DISSECTOR_ASSERT_NOT_REACHED();
1488 return;
1491 /* Release date is derived from variant number */
1492 /* Only R6 sub-versions currently influence format within a release */
1493 switch (p_fp_info->release) {
1494 case 6:
1495 if (variant < 256) {
1496 calculated_variant = variant;
1498 else {
1499 calculated_variant = variant / 256;
1502 switch (calculated_variant) {
1503 case 1:
1504 p_fp_info->release_year = 2005;
1505 p_fp_info->release_month = 6;
1506 break;
1507 case 2:
1508 p_fp_info->release_year = 2005;
1509 p_fp_info->release_month = 9;
1510 break;
1511 case 3:
1512 default:
1513 p_fp_info->release_year = 2006;
1514 p_fp_info->release_month = 3;
1515 break;
1517 break;
1518 case 7:
1519 p_fp_info->release_year = 2008;
1520 p_fp_info->release_month = 3;
1521 break;
1523 case 8:
1524 p_fp_info->release_year = 2010;
1525 p_fp_info->release_month = 6;
1526 break;
1529 default:
1530 p_fp_info->release_year = 0;
1531 p_fp_info->release_month = 0;
1535 /* Channel type */
1536 p_fp_info->channel = outhdr_values[i++];
1537 /* Sad hack until this value is filled in properly */
1538 if (p_fp_info->channel == 0) {
1539 p_fp_info->channel = CHANNEL_DCH;
1542 /* Derive direction from node type/side */
1543 node_type = outhdr_values[i++];
1544 p_fp_info->is_uplink = (( received && (node_type == 2)) ||
1545 (!received && (node_type == 1)));
1547 /* Division type introduced for R7 */
1548 if ((p_fp_info->release == 7) ||
1549 (p_fp_info->release == 8)) {
1550 p_fp_info->division = (enum division_type)outhdr_values[i++];
1553 /* HS-DSCH config */
1554 if (p_fp_info->channel == CHANNEL_HSDSCH) {
1555 if ((p_fp_info->release == 7) ||
1556 (p_fp_info->release == 8)) {
1557 /* Entity (MAC-hs or MAC-ehs) used */
1558 if (outhdr_values[i++]) {
1559 p_fp_info->hsdsch_entity = ehs;
1562 else {
1563 /* This is the pre-R7 default */
1564 p_fp_info->hsdsch_entity = hs;
1569 /* IUR only uses the above... */
1570 if (strcmp(protocol_name, "fpiur_r5") == 0) {
1571 /* Store info in packet */
1572 p_fp_info->iface_type = IuR_Interface;
1573 p_add_proto_data(pinfo->fd, proto_fp, 0, p_fp_info);
1574 return;
1577 /* DCH CRC present... */
1578 p_fp_info->dch_crc_present = outhdr_values[i++];
1580 /* ... but don't trust for edch */
1581 if (p_fp_info->channel == CHANNEL_EDCH) {
1582 p_fp_info->dch_crc_present = 2; /* unknown */
1585 /* How many paging indications (if PCH data) */
1586 p_fp_info->paging_indications = outhdr_values[i++];
1588 /* Number of channels (for coordinated channels) */
1589 p_fp_info->num_chans = outhdr_values[i++];
1591 /* EDCH-Common is always T2 */
1592 if (p_fp_info->channel == CHANNEL_EDCH_COMMON) {
1593 p_fp_info->edch_type = 1;
1596 if (p_fp_info->channel != CHANNEL_EDCH) {
1597 /* TF size for each channel */
1598 tf_start = i;
1599 for (chan=0; chan < p_fp_info->num_chans; chan++) {
1600 p_fp_info->chan_tf_size[chan] = outhdr_values[tf_start+chan];
1603 /* Number of TBs for each channel */
1604 num_chans_start = tf_start + p_fp_info->num_chans;
1605 for (chan=0; chan < p_fp_info->num_chans; chan++) {
1606 p_fp_info->chan_num_tbs[chan] = outhdr_values[num_chans_start+chan];
1609 /* EDCH info */
1610 else {
1611 int n;
1613 p_fp_info->no_ddi_entries = outhdr_values[i++];
1615 /* DDI values */
1616 for (n=0; n < p_fp_info->no_ddi_entries; n++) {
1617 p_fp_info->edch_ddi[n] = outhdr_values[i++];
1620 /* Corresponding MAC-d sizes */
1621 for (n=0; n < p_fp_info->no_ddi_entries; n++) {
1622 p_fp_info->edch_macd_pdu_size[n] = outhdr_values[i++];
1625 if (strcmp(protocol_name, "fp_r8") == 0) {
1626 p_fp_info->edch_type = outhdr_values[i];
1628 else {
1629 p_fp_info->edch_type = 0;
1633 /* Interface must be IuB */
1634 p_fp_info->iface_type = IuB_Interface;
1636 /* Store info in packet */
1637 p_add_proto_data(pinfo->fd, proto_fp, 0, p_fp_info);
1641 /* Fill in an RLC packet info struct and attach it to the packet for the RLC
1642 dissector to use */
1643 static void attach_rlc_info(packet_info *pinfo, guint32 urnti, guint8 rbid, gboolean is_sent)
1645 /* Only need to set info once per session. */
1646 struct fp_info *p_fp_info;
1647 struct rlc_info *p_rlc_info = (struct rlc_info *)p_get_proto_data(pinfo->fd, proto_rlc, 0);
1649 if (p_rlc_info != NULL) {
1650 return;
1653 /* Check that the number of outhdr values looks correct */
1654 if (outhdr_values_found != 2) {
1655 return;
1658 /* Allocate structs */
1659 p_rlc_info = wmem_new(wmem_file_scope(), struct rlc_info);
1660 p_fp_info = wmem_new(wmem_file_scope(), struct fp_info);
1662 /* Fill in struct fields for first (only) PDU in this frame */
1664 /* Urnti. Just use UEId */
1665 p_rlc_info->urnti[0] = urnti;
1667 /* ciphered (off by default) */
1668 p_rlc_info->ciphered[0] = FALSE;
1670 /* deciphered (off by default) */
1671 p_rlc_info->deciphered[0] = FALSE;
1673 /* Mode. */
1674 switch (outhdr_values[1]) {
1675 case 1:
1676 p_rlc_info->mode[0] = RLC_TM;
1677 break;
1678 case 2:
1679 p_rlc_info->mode[0] = RLC_UM;
1680 break;
1681 case 3:
1682 p_rlc_info->mode[0] = RLC_AM;
1683 break;
1684 case 4:
1685 p_rlc_info->mode[0] = RLC_UM;
1686 p_rlc_info->ciphered[0] = TRUE;
1687 break;
1688 case 5:
1689 p_rlc_info->mode[0] = RLC_AM;
1690 p_rlc_info->ciphered[0] = TRUE;
1691 break;
1692 default:
1693 return;
1696 /* rbid. TODO: does this need conversion? */
1697 p_rlc_info->rbid[0] = rbid;
1699 /* li_size */
1700 p_rlc_info->li_size[0] = (enum rlc_li_size)outhdr_values[0];
1702 /* Store info in packet */
1703 p_add_proto_data(pinfo->fd, proto_rlc, 0, p_rlc_info);
1705 /* Also store minimal FP info consulted by RLC dissector
1706 TODO: Don't really know direction, but use S/R flag to make
1707 logs in same context consistent. Will be correct for NodeB logs,
1708 but RLC dissector seems to not use anyway... */
1709 p_fp_info->is_uplink = is_sent;
1710 p_fp_info->cur_tb = 0; /* Always the first/only one */
1711 p_add_proto_data(pinfo->fd, proto_fp, 0, p_fp_info);
1715 /* Fill in a MAC LTE packet info struct and attach it to the packet for that
1716 dissector to use */
1717 static void attach_mac_lte_info(packet_info *pinfo)
1719 struct mac_lte_info *p_mac_lte_info;
1720 unsigned int i = 0;
1722 /* Only need to set info once per session. */
1723 p_mac_lte_info = get_mac_lte_proto_data(pinfo);
1724 if (p_mac_lte_info != NULL) {
1725 return;
1728 /* Allocate & zero struct */
1729 p_mac_lte_info = wmem_new0(wmem_file_scope(), struct mac_lte_info);
1731 /* Populate the struct from outhdr values */
1732 p_mac_lte_info->crcStatusValid = crc_fail; /* not set yet */
1734 p_mac_lte_info->radioType = outhdr_values[i++] + 1;
1735 p_mac_lte_info->rntiType = outhdr_values[i++];
1736 p_mac_lte_info->direction = outhdr_values[i++];
1737 /* Set these extra PHY present flags to FALSE by default */
1738 if (p_mac_lte_info->direction == DIRECTION_UPLINK) {
1739 p_mac_lte_info->detailed_phy_info.ul_info.present = FALSE;
1741 else {
1742 p_mac_lte_info->detailed_phy_info.dl_info.present = FALSE;
1745 p_mac_lte_info->subframeNumber = outhdr_values[i++];
1746 p_mac_lte_info->isPredefinedData = outhdr_values[i++];
1747 p_mac_lte_info->rnti = outhdr_values[i++];
1748 p_mac_lte_info->ueid = outhdr_values[i++];
1749 p_mac_lte_info->length = outhdr_values[i++];
1750 if (outhdr_values_found > 8) {
1751 p_mac_lte_info->reTxCount = outhdr_values[i++];
1753 if (outhdr_values_found == 10) {
1754 /* CRC only valid for Downlink */
1755 if (p_mac_lte_info->direction == DIRECTION_DOWNLINK) {
1756 p_mac_lte_info->crcStatusValid = crc_success;
1757 p_mac_lte_info->detailed_phy_info.dl_info.crc_status = (mac_lte_crc_status)outhdr_values[i++];
1759 else {
1760 i++;
1764 p_mac_lte_info->dl_retx = dl_retx_unknown;
1766 if (outhdr_values_found > 10) {
1767 /* Extra PHY parameters */
1768 if (p_mac_lte_info->direction == DIRECTION_DOWNLINK) {
1769 p_mac_lte_info->detailed_phy_info.dl_info.present = outhdr_values[i++];
1770 p_mac_lte_info->detailed_phy_info.dl_info.dci_format = outhdr_values[i++];
1771 p_mac_lte_info->detailed_phy_info.dl_info.resource_allocation_type = outhdr_values[i++];
1772 p_mac_lte_info->detailed_phy_info.dl_info.aggregation_level = outhdr_values[i++];
1773 p_mac_lte_info->detailed_phy_info.dl_info.mcs_index = outhdr_values[i++];
1774 p_mac_lte_info->detailed_phy_info.dl_info.redundancy_version_index = outhdr_values[i++];
1775 if (outhdr_values[i++]) {
1776 p_mac_lte_info->dl_retx = dl_retx_yes;
1778 else {
1779 p_mac_lte_info->dl_retx = dl_retx_no;
1781 p_mac_lte_info->detailed_phy_info.dl_info.resource_block_length = outhdr_values[i++];
1782 p_mac_lte_info->crcStatusValid = crc_success;
1783 p_mac_lte_info->detailed_phy_info.dl_info.crc_status = (mac_lte_crc_status)outhdr_values[i++];
1784 if (outhdr_values_found > 18) {
1785 p_mac_lte_info->detailed_phy_info.dl_info.harq_id = outhdr_values[i++];
1786 p_mac_lte_info->detailed_phy_info.dl_info.ndi = outhdr_values[i++];
1788 if (outhdr_values_found > 20) {
1789 p_mac_lte_info->detailed_phy_info.dl_info.transport_block = outhdr_values[i++];
1792 else {
1793 /* Uplink */
1794 p_mac_lte_info->detailed_phy_info.ul_info.present = outhdr_values[i++];
1795 p_mac_lte_info->detailed_phy_info.ul_info.modulation_type = outhdr_values[i++];
1796 p_mac_lte_info->detailed_phy_info.ul_info.tbs_index = outhdr_values[i++];
1797 p_mac_lte_info->detailed_phy_info.ul_info.resource_block_length = outhdr_values[i++];
1798 p_mac_lte_info->detailed_phy_info.ul_info.resource_block_start = outhdr_values[i++];
1799 /* Skip retx flag */
1800 i++;
1802 if (outhdr_values_found == 16) {
1803 p_mac_lte_info->subframeNumberOfGrantPresent = TRUE;
1804 p_mac_lte_info->subframeNumberOfGrant = outhdr_values[i++];
1806 if (outhdr_values_found > 16) {
1807 p_mac_lte_info->detailed_phy_info.ul_info.harq_id = outhdr_values[i++];
1808 p_mac_lte_info->detailed_phy_info.ul_info.ndi = outhdr_values[i++];
1810 p_mac_lte_info->subframeNumberOfGrantPresent = TRUE;
1811 p_mac_lte_info->subframeNumberOfGrant = outhdr_values[i++];
1816 /* System frame number */
1817 if (i < outhdr_values_found) {
1818 p_mac_lte_info->sysframeNumber = outhdr_values[i++];
1821 if ((p_mac_lte_info->direction == DIRECTION_UPLINK) &&
1822 (i < outhdr_values_found)) {
1824 p_mac_lte_info->isPHICHNACK = outhdr_values[i];
1827 if (p_mac_lte_info->direction == DIRECTION_UPLINK) {
1828 /* R10 parameter not set yet */
1829 p_mac_lte_info->isExtendedBSRSizes = FALSE;
1832 /* Store info in packet */
1833 set_mac_lte_proto_data(pinfo, p_mac_lte_info);
1837 /* Fill in a RLC LTE packet info struct and attach it to the packet for that
1838 dissector to use */
1839 static void attach_rlc_lte_info(packet_info *pinfo)
1841 struct rlc_lte_info *p_rlc_lte_info;
1842 unsigned int i = 0;
1844 /* Only need to set info once per session. */
1845 p_rlc_lte_info = (rlc_lte_info *)p_get_proto_data(pinfo->fd, proto_rlc_lte, 0);
1846 if (p_rlc_lte_info != NULL) {
1847 return;
1850 /* Allocate & zero struct */
1851 p_rlc_lte_info = wmem_new0(wmem_file_scope(), rlc_lte_info);
1853 p_rlc_lte_info->rlcMode = outhdr_values[i++];
1854 p_rlc_lte_info->direction = outhdr_values[i++];
1855 p_rlc_lte_info->priority = outhdr_values[i++];
1856 p_rlc_lte_info->UMSequenceNumberLength = outhdr_values[i++];
1857 p_rlc_lte_info->channelId = outhdr_values[i++];
1858 p_rlc_lte_info->channelType = outhdr_values[i++];
1859 p_rlc_lte_info->ueid = outhdr_values[i++];
1860 p_rlc_lte_info->pduLength = outhdr_values[i];
1862 /* Store info in packet */
1863 p_add_proto_data(pinfo->fd, proto_rlc_lte, 0, p_rlc_lte_info);
1866 /* Fill in a PDCP LTE packet info struct and attach it to the packet for the PDCP LTE
1867 dissector to use */
1868 static void attach_pdcp_lte_info(packet_info *pinfo)
1870 struct pdcp_lte_info *p_pdcp_lte_info;
1871 unsigned int i = 0;
1873 /* Only need to set info once per session. */
1874 p_pdcp_lte_info = (pdcp_lte_info *)p_get_proto_data(pinfo->fd, proto_pdcp_lte, 0);
1875 if (p_pdcp_lte_info != NULL) {
1876 return;
1879 /* Allocate & zero struct */
1880 p_pdcp_lte_info = wmem_new0(wmem_file_scope(), pdcp_lte_info);
1882 p_pdcp_lte_info->no_header_pdu = outhdr_values[i++];
1883 p_pdcp_lte_info->plane = (enum pdcp_plane)outhdr_values[i++];
1884 if (p_pdcp_lte_info->plane != USER_PLANE) {
1885 p_pdcp_lte_info->plane = SIGNALING_PLANE;
1887 p_pdcp_lte_info->seqnum_length = outhdr_values[i++];
1889 p_pdcp_lte_info->rohc.rohc_compression = outhdr_values[i++];
1890 p_pdcp_lte_info->rohc.rohc_ip_version = outhdr_values[i++];
1891 p_pdcp_lte_info->rohc.cid_inclusion_info = outhdr_values[i++];
1892 p_pdcp_lte_info->rohc.large_cid_present = outhdr_values[i++];
1893 p_pdcp_lte_info->rohc.mode = (enum rohc_mode)outhdr_values[i++];
1894 p_pdcp_lte_info->rohc.rnd = outhdr_values[i++];
1895 p_pdcp_lte_info->rohc.udp_checksum_present = outhdr_values[i++];
1896 p_pdcp_lte_info->rohc.profile = outhdr_values[i];
1898 /* Remaining 2 (fixed) fields are ah_length and gre_checksum */
1900 /* Store info in packet */
1901 p_add_proto_data(pinfo->fd, proto_pdcp_lte, 0, p_pdcp_lte_info);
1905 /* Attempt to show tty (raw character messages) as text lines. */
1906 static void dissect_tty_lines(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
1908 gint next_offset;
1909 proto_tree *tty_tree;
1910 proto_item *ti;
1911 int lines = 0;
1913 /* Create tty tree. */
1914 ti = proto_tree_add_item(tree, hf_catapult_dct2000_tty, tvb, offset, -1, ENC_NA);
1915 tty_tree = proto_item_add_subtree(ti, ett_catapult_dct2000_tty);
1917 /* Show the tty lines one at a time. */
1918 while (tvb_reported_length_remaining(tvb, offset) > 0) {
1919 /* Find the end of the line. */
1920 int linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset);
1922 /* Extract & add the string. */
1923 char *string = (char*)tvb_get_string(wmem_packet_scope(), tvb, offset, linelen);
1924 if (isascii(string[0])) {
1925 /* If looks printable treat as string... */
1926 proto_tree_add_string_format(tty_tree, hf_catapult_dct2000_tty_line,
1927 tvb, offset,
1928 linelen, string,
1929 "%s", string);
1931 else {
1932 /* Otherwise show as $hex */
1933 int n, idx;
1934 char *hex_string;
1935 int tty_string_length = tvb_length_remaining(tvb, offset);
1936 int hex_string_length = 1+(2*tty_string_length)+1;
1937 hex_string = (char *)wmem_alloc(wmem_packet_scope(), hex_string_length);
1939 idx = g_snprintf(hex_string, hex_string_length, "$");
1941 /* Write hex out to new string */
1942 for (n=0; n < tty_string_length; n++) {
1943 idx += g_snprintf(hex_string+idx, 3, "%02x",
1944 tvb_get_guint8(tvb, offset+n));
1946 string = hex_string;
1948 lines++;
1950 /* Show first line in info column */
1951 if (lines == 1) {
1952 col_append_fstr(pinfo->cinfo, COL_INFO, "tty (%s", string);
1953 proto_item_append_text(ti, " (%s)", string);
1956 /* Move onto next line. */
1957 offset = next_offset;
1960 /* Close off summary of tty message in info column */
1961 if (lines != 0) {
1962 col_append_str(pinfo->cinfo, COL_INFO, (lines > 1) ? "...)" : ")");
1967 /* Scan the log comment looking for notable out-of-band MAC events that should
1968 be sent to the MAC dissector */
1969 static void check_for_oob_mac_lte_events(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
1970 const char *string)
1972 guint number_of_ues;
1973 guint ueids[MAX_SRs];
1974 guint rntis[MAX_SRs];
1975 guint rapid;
1976 guint rach_attempt_number;
1977 guint temp;
1978 mac_lte_oob_event oob_event;
1979 struct mac_lte_info *p_mac_lte_info;
1980 tvbuff_t *mac_lte_tvb = NULL;
1981 guint16 n;
1983 /* Look for strings matching expected formats */
1984 if (sscanf(string, ">> RACH Preamble Request[UE = %u] [RAPID = %u] [Attempt = %u]",
1985 &ueids[0], &rapid, &rach_attempt_number) == 3) {
1986 oob_event = ltemac_send_preamble;
1988 else
1989 if (sscanf(string, ">> Schedule Requests (%u) [UE=%u][RNTI=%u]",
1990 &number_of_ues, &ueids[0], &rntis[0]) == 3) {
1991 const char *current_position;
1993 /* Newer, multi-UE format */
1994 oob_event = ltemac_send_sr;
1996 /* Parse other ueid/rnti pairs */
1997 number_of_ues = MIN(number_of_ues, MAX_SRs);
1998 if (number_of_ues > 1) {
1999 current_position = string;
2001 for (n=1; n < number_of_ues; n++) {
2003 /* Find the start of the next entry */
2004 current_position = strstr(current_position, "] ");
2005 if (current_position != NULL) {
2006 current_position += 2;
2008 else {
2009 /* This is an error - shouldn't happen */
2010 return;
2013 /* Read this entry */
2014 if (sscanf(current_position, "[UE=%u][RNTI=%u]", &ueids[n], &rntis[n]) != 2) {
2015 /* Assuming that if we can't read this one there is no point trying others */
2016 number_of_ues = n;
2017 break;
2022 else
2023 /* Support both old and new formats of SR failure */
2024 if ((sscanf(string, ">> INFO (inst %u) MAC: [UE = %u] SR failed (CRNTI=%u)",
2025 &temp, &ueids[0], &rntis[0]) == 3) ||
2026 (sscanf(string, ">> INFO MAC: SR failed for UE %u (CRNTI=%u",
2027 &ueids[0], &rntis[0]) == 2))
2029 oob_event = ltemac_sr_failure;
2031 else {
2032 /* No events found */
2033 return;
2036 /* We have an event */
2037 /* Only need to set info once per session. */
2038 p_mac_lte_info = get_mac_lte_proto_data(pinfo);
2039 if (p_mac_lte_info == NULL) {
2041 /* Allocate & zero struct */
2042 p_mac_lte_info = wmem_new0(wmem_file_scope(), mac_lte_info);
2044 /* This indicates to MAC dissector that it has an oob event */
2045 p_mac_lte_info->length = 0;
2047 switch (oob_event) {
2048 case ltemac_send_preamble:
2049 p_mac_lte_info->ueid = ueids[0];
2050 p_mac_lte_info->rapid = rapid;
2051 p_mac_lte_info->rach_attempt_number = rach_attempt_number;
2052 p_mac_lte_info->direction = DIRECTION_UPLINK;
2053 break;
2054 case ltemac_send_sr:
2055 for (n=0; n < number_of_ues; n++) {
2056 p_mac_lte_info->oob_ueid[n] = ueids[n];
2057 p_mac_lte_info->oob_rnti[n] = rntis[n];
2059 p_mac_lte_info->number_of_srs = number_of_ues;
2060 p_mac_lte_info->direction = DIRECTION_UPLINK;
2061 break;
2062 case ltemac_sr_failure:
2063 p_mac_lte_info->rnti = rntis[0];
2064 p_mac_lte_info->ueid = ueids[0];
2065 p_mac_lte_info->direction = DIRECTION_DOWNLINK;
2066 break;
2069 p_mac_lte_info->radioType = FDD_RADIO; /* TODO: will be the same as rest of log... */
2070 p_mac_lte_info->oob_event = oob_event;
2072 /* Store info in packet */
2073 set_mac_lte_proto_data(pinfo, p_mac_lte_info);
2076 /* Call MAC dissector */
2077 mac_lte_tvb = tvb_new_subset(tvb, 0, 0, 0);
2078 call_dissector_only(mac_lte_handle, mac_lte_tvb, pinfo, tree, NULL);
2082 /*****************************************/
2083 /* Main dissection function. */
2084 /*****************************************/
2085 static void
2086 dissect_catapult_dct2000(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2088 proto_tree *dct2000_tree = NULL;
2089 proto_item *ti = NULL;
2090 gint offset = 0;
2091 gint context_length;
2092 const char *context_name;
2093 guint8 port_number;
2094 gint protocol_length;
2095 gint timestamp_length;
2096 const char *timestamp_string;
2097 gint variant_length;
2098 const char *variant_string;
2099 gint outhdr_length;
2100 const char *outhdr_string;
2101 guint8 direction;
2102 tvbuff_t *next_tvb;
2103 int encap;
2104 dissector_handle_t protocol_handle = 0;
2105 dissector_handle_t heur_protocol_handle = 0;
2106 int sub_dissector_result = 0;
2107 const char *protocol_name;
2108 gboolean is_comment, is_sprint = FALSE;
2110 /* Set Protocol */
2111 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCT2000");
2113 /* Clear Info */
2114 col_clear(pinfo->cinfo, COL_INFO);
2116 /* Create root (protocol) tree. */
2117 if (tree) {
2118 ti = proto_tree_add_item(tree, proto_catapult_dct2000, tvb, offset, -1, ENC_NA);
2119 dct2000_tree = proto_item_add_subtree(ti, ett_catapult_dct2000);
2122 /*********************************************************************/
2123 /* Note that these are the fields of the stub header as written out */
2124 /* by the wiretap module */
2126 /* Context Name */
2127 context_name = tvb_get_const_stringz(tvb, offset, &context_length);
2128 if (dct2000_tree) {
2129 proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_context, tvb,
2130 offset, context_length, ENC_ASCII|ENC_NA);
2132 offset += context_length;
2134 /* Context port number */
2135 port_number = tvb_get_guint8(tvb, offset);
2136 if (dct2000_tree) {
2137 proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_port_number, tvb,
2138 offset, 1, ENC_BIG_ENDIAN);
2140 offset++;
2142 /* Timestamp in file */
2143 timestamp_string = tvb_get_const_stringz(tvb, offset, &timestamp_length);
2144 if (dct2000_tree) {
2145 /* TODO: this is *very* slow, but float version adds trailing digits when
2146 displayed as a custom column... */
2147 proto_tree_add_double(dct2000_tree, hf_catapult_dct2000_timestamp, tvb,
2148 offset, timestamp_length,
2149 atof(timestamp_string));
2151 offset += timestamp_length;
2154 /* DCT2000 protocol name */
2155 protocol_name = tvb_get_const_stringz(tvb, offset, &protocol_length);
2156 if (dct2000_tree) {
2157 proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_protocol, tvb,
2158 offset, protocol_length, ENC_ASCII|ENC_NA);
2160 is_comment = (strcmp(protocol_name, "comment") == 0);
2161 if (!is_comment) {
2162 is_sprint = (strcmp(protocol_name, "sprint") == 0);
2164 offset += protocol_length;
2167 /* Protocol Variant */
2168 variant_string = tvb_get_const_stringz(tvb, offset, &variant_length);
2169 if (!is_comment && !is_sprint) {
2170 proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_variant, tvb,
2171 offset, variant_length, ENC_ASCII|ENC_NA);
2173 offset += variant_length;
2175 /* Outhdr (shown as string) */
2176 outhdr_string = tvb_get_const_stringz(tvb, offset, &outhdr_length);
2177 if (!is_comment && !is_sprint && (outhdr_length > 1)) {
2178 proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_outhdr, tvb,
2179 offset, outhdr_length, ENC_ASCII|ENC_NA);
2181 offset += outhdr_length;
2184 /* Direction */
2185 direction = tvb_get_guint8(tvb, offset);
2186 if (dct2000_tree) {
2187 proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_direction, tvb,
2188 offset, 1, ENC_BIG_ENDIAN);
2190 offset++;
2192 /* Read frame encapsulation set by wiretap */
2193 if (!is_comment && !is_sprint) {
2194 proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_encap, tvb, offset, 1, ENC_BIG_ENDIAN);
2196 encap = tvb_get_guint8(tvb, offset);
2197 offset++;
2199 /* Add useful details to protocol tree label */
2200 proto_item_append_text(ti, " context=%s.%u t=%s %c prot=%s (v=%s)",
2201 context_name,
2202 port_number,
2203 timestamp_string,
2204 (direction == 0) ? 'S' : 'R',
2205 protocol_name,
2206 variant_string);
2210 /* FP protocols need info from outhdr attached */
2211 if ((strcmp(protocol_name, "fp") == 0) ||
2212 (strncmp(protocol_name, "fp_r", 4) == 0) ||
2213 (strcmp(protocol_name, "fpiur_r5") == 0)) {
2215 parse_outhdr_string(outhdr_string, outhdr_length);
2216 attach_fp_info(pinfo, direction, protocol_name, atoi(variant_string));
2219 /* RLC protocols need info from outhdr attached */
2220 else if ((strcmp(protocol_name, "rlc") == 0) ||
2221 (strcmp(protocol_name, "rlc_r4") == 0) ||
2222 (strcmp(protocol_name, "rlc_r5") == 0) ||
2223 (strcmp(protocol_name, "rlc_r6") == 0) ||
2224 (strcmp(protocol_name, "rlc_r7") == 0) ||
2225 (strcmp(protocol_name, "rlc_r8") == 0) ||
2226 (strcmp(protocol_name, "rlc_r9") == 0)) {
2228 parse_outhdr_string(outhdr_string, outhdr_length);
2229 /* Can't attach info yet. Need combination of outheader values
2230 and fields parsed from primitive header... */
2233 /* LTE MAC needs info attached */
2234 else if ((strcmp(protocol_name, "mac_r8_lte") == 0) ||
2235 (strcmp(protocol_name, "mac_r9_lte") == 0) ||
2236 (strcmp(protocol_name, "mac_r10_lte") == 0)) {
2237 parse_outhdr_string(outhdr_string, outhdr_length);
2238 attach_mac_lte_info(pinfo);
2241 /* LTE RLC needs info attached */
2242 else if ((strcmp(protocol_name, "rlc_r8_lte") == 0) ||
2243 (strcmp(protocol_name, "rlc_r9_lte") == 0) ||
2244 (strcmp(protocol_name, "rlc_r10_lte") == 0)) {
2245 parse_outhdr_string(outhdr_string, outhdr_length);
2246 attach_rlc_lte_info(pinfo);
2249 /* LTE PDCP needs info attached */
2250 else if ((strcmp(protocol_name, "pdcp_r8_lte") == 0) ||
2251 (strcmp(protocol_name, "pdcp_r9_lte") == 0) ||
2252 (strcmp(protocol_name, "pdcp_r10_lte") == 0)) {
2253 parse_outhdr_string(outhdr_string, outhdr_length);
2254 attach_pdcp_lte_info(pinfo);
2258 else if ((strcmp(protocol_name, "nas_rrc_r8_lte") == 0) ||
2259 (strcmp(protocol_name, "nas_rrc_r9_lte") == 0) ||
2260 (strcmp(protocol_name, "nas_rrc_r10_lte") == 0)) {
2261 gboolean nas_body_found = TRUE;
2262 guint8 opcode = tvb_get_guint8(tvb, offset);
2263 proto_tree_add_item(tree, hf_catapult_dct2000_lte_nas_rrc_opcode,
2264 tvb, offset++, 1, ENC_BIG_ENDIAN);
2266 offset++; /* Skip overall length */
2268 switch (opcode) {
2269 case LTE_NAS_RRC_DATA_IND:
2270 case LTE_NAS_RRC_DATA_REQ:
2271 /* UEId */
2272 offset++; /* tag */
2273 offset += 2; /* 2 wasted bytes of UEId*/
2274 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
2275 tvb, offset, 2, ENC_BIG_ENDIAN);
2276 offset += 2;
2277 break;
2278 case LTE_NAS_RRC_ESTABLISH_REQ:
2279 /* UEId */
2280 offset++; /* tag */
2281 offset += 2; /* 2 wasted bytes of UEId*/
2282 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
2283 tvb, offset, 2, ENC_BIG_ENDIAN);
2284 offset += 2;
2286 /* Establish cause. TODO: value_string */
2287 offset += 2; /* tag + length */
2288 proto_tree_add_item(tree, hf_catapult_dct2000_lte_nas_rrc_establish_cause,
2289 tvb, offset++, 1, ENC_BIG_ENDIAN);
2291 /* Priority. TODO: Vals are low | high */
2292 offset += 2; /* tag + length */
2293 proto_tree_add_item(tree, hf_catapult_dct2000_lte_nas_rrc_priority,
2294 tvb, offset++, 1, ENC_BIG_ENDIAN);
2295 break;
2296 case LTE_NAS_RRC_RELEASE_IND:
2297 /* UEId */
2298 offset++; /* tag */
2299 offset += 2; /* 2 wasted bytes of UEId*/
2300 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ueid,
2301 tvb, offset, 2, ENC_BIG_ENDIAN);
2302 offset += 2;
2304 /* Release cause. TODO: value_string */
2305 offset += 2; /* tag + length */
2306 proto_tree_add_item(tree, hf_catapult_dct2000_lte_nas_rrc_release_cause,
2307 tvb, offset++, 1, ENC_BIG_ENDIAN);
2308 break;
2310 default:
2311 nas_body_found = FALSE;
2312 break;
2315 /* Look up dissector if if looks right */
2316 if (nas_body_found) {
2317 offset += 2; /* L3 tag + len */
2318 protocol_handle = find_dissector("nas-eps");
2322 /* Note that the first item of pinfo->pseudo_header->dct2000 will contain
2323 the pseudo-header needed (in some cases) by the Wireshark dissector that
2324 this packet data will be handed off to. */
2327 /***********************************************************************/
2328 /* Now hand off to the dissector of intended packet encapsulation type */
2330 /* Get protocol handle, and set p2p_dir where necessary.
2331 (packet-frame.c won't copy it from pseudo-header because it doesn't
2332 know about Catapult DCT2000 encap type...)
2334 switch (encap) {
2335 case WTAP_ENCAP_RAW_IP:
2336 protocol_handle = find_dissector("ip");
2337 #if 0
2338 /* TODO: this doesn't work yet.
2339 pseudo_header isn't copied from wtap to pinfo... */
2340 if ((pinfo->pseudo_header != NULL) &&
2341 (pinfo->pseudo_header->dct2000.inner_pseudo_header.pdcp.ueid != 0)) {
2343 proto_item *ti;
2345 /* Add PDCP thread info as generated fields */
2346 ti = proto_tree_add_uint(dct2000_tree, hf_catapult_dct2000_lte_ueid, tvb, 0, 0,
2347 pinfo->pseudo_header->dct2000.inner_pseudo_header.pdcp.ueid);
2348 PROTO_ITEM_SET_GENERATED(ti);
2349 ti = proto_tree_add_uint(dct2000_tree, hf_catapult_dct2000_lte_drbid, tvb, 0, 0,
2350 pinfo->pseudo_header->dct2000.inner_pseudo_header.pdcp.drbid);
2351 PROTO_ITEM_SET_GENERATED(ti);
2353 #endif
2354 break;
2355 case WTAP_ENCAP_ETHERNET:
2356 protocol_handle = find_dissector("eth_withoutfcs");
2357 break;
2358 case WTAP_ENCAP_ISDN:
2359 protocol_handle = find_dissector("lapd");
2360 pinfo->p2p_dir = pinfo->pseudo_header->isdn.uton;
2361 break;
2362 case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED:
2363 protocol_handle = find_dissector("atm_untruncated");
2364 break;
2365 case WTAP_ENCAP_PPP:
2366 protocol_handle = find_dissector("ppp_hdlc");
2367 pinfo->p2p_dir = pinfo->pseudo_header->p2p.sent;
2368 break;
2369 case DCT2000_ENCAP_SSCOP:
2370 protocol_handle = find_dissector("sscop");
2371 break;
2372 case WTAP_ENCAP_FRELAY:
2373 protocol_handle = find_dissector("fr");
2374 break;
2375 case DCT2000_ENCAP_MTP2:
2376 protocol_handle = find_dissector("mtp2");
2377 break;
2378 case DCT2000_ENCAP_NBAP:
2379 protocol_handle = find_dissector("nbap");
2380 break;
2382 case DCT2000_ENCAP_UNHANDLED:
2383 /**********************************************************/
2384 /* The wiretap module wasn't able to set an encapsulation */
2385 /* type, but it may still be possible to dissect the data */
2386 /* if we know about the protocol or if we can recognise */
2387 /* and parse or skip a primitive header */
2388 /**********************************************************/
2390 /* Show context.port in src or dest column as appropriate */
2391 if (direction == 0) {
2392 col_add_fstr(pinfo->cinfo, COL_DEF_SRC,
2393 "%s.%u",
2394 context_name,
2395 port_number);
2397 else
2398 if (direction == 1) {
2399 col_add_fstr(pinfo->cinfo, COL_DEF_DST,
2400 "%s.%u",
2401 context_name,
2402 port_number);
2406 /**************************************************************************/
2407 /* These protocols have no encapsulation type, just look them up directly */
2409 if ((strcmp(protocol_name, "rlc") == 0) ||
2410 (strcmp(protocol_name, "rlc_r4") == 0) ||
2411 (strcmp(protocol_name, "rlc_r5") == 0) ||
2412 (strcmp(protocol_name, "rlc_r6") == 0) ||
2413 (strcmp(protocol_name, "rlc_r7") == 0) ||
2414 (strcmp(protocol_name, "rlc_r8") == 0) ||
2415 (strcmp(protocol_name, "rlc_r9") == 0)) {
2417 dissect_rlc_umts(tvb, offset, pinfo, tree, direction);
2418 return;
2421 else
2422 if ((strcmp(protocol_name, "mac_r8_lte") == 0) ||
2423 (strcmp(protocol_name, "mac_r9_lte") == 0) ||
2424 (strcmp(protocol_name, "mac_r10_lte") == 0)) {
2425 protocol_handle = mac_lte_handle;
2428 else
2429 if ((strcmp(protocol_name, "rlc_r8_lte") == 0) ||
2430 (strcmp(protocol_name, "rlc_r9_lte") == 0) ||
2431 (strcmp(protocol_name, "rlc_r10_lte") == 0)) {
2432 protocol_handle = rlc_lte_handle;
2435 else
2436 if ((strcmp(protocol_name, "pdcp_r8_lte") == 0) ||
2437 (strcmp(protocol_name, "pdcp_r9_lte") == 0) ||
2438 (strcmp(protocol_name, "pdcp_r10_lte") == 0)) {
2439 /* Dissect proprietary header, then pass remainder to PDCP */
2440 dissect_pdcp_lte(tvb, offset, pinfo, tree);
2441 return;
2445 /* Work with generic XML protocol. */
2446 else
2447 if (strcmp(protocol_name, "xml") == 0) {
2448 protocol_handle = find_dissector("xml");
2452 /* Attempt to show tty messages as raw text */
2453 else
2454 if (strcmp(protocol_name, "tty") == 0) {
2455 dissect_tty_lines(tvb, pinfo, dct2000_tree, offset);
2456 return;
2459 else
2460 if (strcmp(protocol_name, "sipprim") == 0) {
2461 protocol_handle = find_dissector("sipprim");
2464 else
2465 if (strcmp(protocol_name, "comment") == 0) {
2466 /* Extract & add the string. */
2467 proto_item *string_ti;
2468 char *string = (char*)tvb_get_string(wmem_packet_scope(), tvb, offset, tvb_length_remaining(tvb, offset));
2470 /* Show comment string */
2471 string_ti = proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_comment, tvb,
2472 offset, -1, ENC_ASCII|ENC_NA);
2473 col_append_fstr(pinfo->cinfo, COL_INFO, "%s", string);
2475 if (catapult_dct2000_dissect_mac_lte_oob_messages) {
2476 /* Look into string for out-of-band MAC events, such as SRReq, SRInd */
2477 check_for_oob_mac_lte_events(pinfo, tvb, tree, string);
2480 /* Look for and flag generic error messages */
2481 if (strncmp(string, ">> ERR", 6) == 0) {
2482 proto_item *error_ti = proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_error_comment, tvb,
2483 offset, -1, ENC_NA);
2484 PROTO_ITEM_SET_GENERATED(error_ti);
2485 expert_add_info_format(pinfo, string_ti, &ei_catapult_dct2000_error_comment_expert,
2486 "%s", string);
2489 return;
2492 else
2493 if (strcmp(protocol_name, "sprint") == 0) {
2494 /* Extract & add the string. */
2495 char *string = (char*)tvb_get_string(wmem_packet_scope(), tvb, offset, tvb_length_remaining(tvb, offset));
2497 /* Show sprint string */
2498 proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_sprint, tvb,
2499 offset, -1, ENC_ASCII|ENC_NA);
2500 col_append_fstr(pinfo->cinfo, COL_INFO, "%s", string);
2502 return;
2506 else
2507 if (catapult_dct2000_dissect_lte_rrc &&
2508 ((strcmp(protocol_name, "rrc_r8_lte") == 0) ||
2509 (strcmp(protocol_name, "rrcpdcpprim_r8_lte") == 0) ||
2510 (strcmp(protocol_name, "rrc_r9_lte") == 0) ||
2511 (strcmp(protocol_name, "rrcpdcpprim_r9_lte") == 0) ||
2512 (strcmp(protocol_name, "rrc_r10_lte") == 0))) {
2514 /* Dissect proprietary header, then pass remainder
2515 to RRC (depending upon direction and channel type) */
2516 dissect_rrc_lte(tvb, offset, pinfo, tree);
2517 return;
2520 else
2521 if ((strcmp(protocol_name, "ccpri_r8_lte") == 0) ||
2522 (strcmp(protocol_name, "ccpri_r9_lte") == 0)) {
2524 /* Dissect proprietary header, then pass remainder to lapb */
2525 dissect_ccpri_lte(tvb, offset, pinfo, tree);
2526 return;
2529 /* Many DCT2000 protocols have at least one IPPrim variant. If the
2530 protocol name can be matched to a dissector, try to find the
2531 UDP/TCP data inside and dissect it.
2534 if (!protocol_handle && catapult_dct2000_try_ipprim_heuristic) {
2535 guint32 source_addr_offset = 0, dest_addr_offset = 0;
2536 guint8 source_addr_length = 0, dest_addr_length = 0;
2537 guint32 source_port_offset = 0, dest_port_offset = 0;
2538 port_type type_of_port = PT_NONE;
2539 guint16 conn_id_offset = 0;
2540 int offset_before_ipprim_header = offset;
2542 /* Will give up if couldn't match protocol anyway... */
2543 heur_protocol_handle = look_for_dissector(protocol_name);
2544 if ((heur_protocol_handle != 0) &&
2545 find_ipprim_data_offset(tvb, &offset, direction,
2546 &source_addr_offset, &source_addr_length,
2547 &dest_addr_offset, &dest_addr_length,
2548 &source_port_offset, &dest_port_offset,
2549 &type_of_port,
2550 &conn_id_offset)) {
2552 proto_tree *ipprim_tree;
2553 proto_item *ipprim_ti;
2554 struct e_in6_addr sourcev6, destv6;
2556 /* Fetch IPv6 addresses */
2557 if (source_addr_length != 4) {
2558 tvb_get_ipv6(tvb, source_addr_offset, &sourcev6);
2560 if (dest_addr_length != 4) {
2561 tvb_get_ipv6(tvb, dest_addr_offset, &destv6);
2565 /* Will use this dissector then. */
2566 protocol_handle = heur_protocol_handle;
2568 /* Add address parameters to tree */
2569 /* Unfortunately can't automatically create a conversation filter for this...
2570 I *could* create a fake IP header from these details, but then it would be tricky
2571 to get the FP dissector called as it has no well-known ports or heuristics... */
2572 ipprim_ti = proto_tree_add_string_format(dct2000_tree, hf_catapult_dct2000_ipprim_addresses,
2573 tvb, offset_before_ipprim_header, 0,
2574 "", "IPPrim transport (%s): %s:%u -> %s:%u",
2575 (type_of_port == PT_UDP) ? "UDP" : "TCP",
2576 (source_addr_offset) ?
2577 ((source_addr_length == 4) ?
2578 get_hostname(tvb_get_ipv4(tvb, source_addr_offset)) :
2579 get_hostname6(&sourcev6)
2581 "0.0.0.0",
2582 (source_port_offset) ?
2583 tvb_get_ntohs(tvb, source_port_offset) :
2585 (dest_addr_offset) ?
2586 ((source_addr_length == 4) ?
2587 get_hostname(tvb_get_ipv4(tvb, dest_addr_offset)) :
2588 get_hostname6(&destv6)
2590 "0.0.0.0",
2591 (dest_port_offset) ?
2592 tvb_get_ntohs(tvb, dest_port_offset) :
2594 if ((type_of_port == PT_TCP) && (conn_id_offset != 0)) {
2595 proto_item_append_text(ipprim_ti, " (conn_id=%u)", tvb_get_ntohs(tvb, conn_id_offset));
2598 /* Add these IPPRIM fields inside an IPPRIM subtree */
2599 ipprim_tree = proto_item_add_subtree(ipprim_ti, ett_catapult_dct2000_ipprim);
2601 /* Try to add right stuff to pinfo so conversation stuff works... */
2602 pinfo->ptype = type_of_port;
2603 switch (type_of_port) {
2604 case PT_UDP:
2605 pinfo->ipproto = IP_PROTO_UDP;
2606 break;
2607 case PT_TCP:
2608 pinfo->ipproto = IP_PROTO_TCP;
2609 break;
2610 default:
2611 pinfo->ipproto = IP_PROTO_NONE;
2614 /* Add addresses & ports into ipprim tree.
2615 Also set address info in pinfo for conversations... */
2616 if (source_addr_offset != 0) {
2617 proto_item *addr_ti;
2619 TVB_SET_ADDRESS(&pinfo->net_src,
2620 (source_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2621 tvb, source_addr_offset, source_addr_length);
2622 TVB_SET_ADDRESS(&pinfo->src,
2623 (source_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2624 tvb, source_addr_offset, source_addr_length);
2626 proto_tree_add_item(ipprim_tree,
2627 (source_addr_length == 4) ?
2628 hf_catapult_dct2000_ipprim_src_addr_v4 :
2629 hf_catapult_dct2000_ipprim_src_addr_v6,
2630 tvb, source_addr_offset, source_addr_length,
2631 (source_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2633 /* Add hidden item for "side-less" addr */
2634 addr_ti = proto_tree_add_item(ipprim_tree,
2635 (source_addr_length == 4) ?
2636 hf_catapult_dct2000_ipprim_addr_v4 :
2637 hf_catapult_dct2000_ipprim_addr_v6,
2638 tvb, source_addr_offset, source_addr_length,
2639 (source_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2640 PROTO_ITEM_SET_HIDDEN(addr_ti);
2642 if (source_port_offset != 0) {
2643 proto_item *port_ti;
2645 pinfo->srcport = tvb_get_ntohs(tvb, source_port_offset);
2647 proto_tree_add_item(ipprim_tree,
2648 (type_of_port == PT_UDP) ?
2649 hf_catapult_dct2000_ipprim_udp_src_port :
2650 hf_catapult_dct2000_ipprim_tcp_src_port,
2651 tvb, source_port_offset, 2, ENC_BIG_ENDIAN);
2652 port_ti = proto_tree_add_item(ipprim_tree,
2653 (type_of_port == PT_UDP) ?
2654 hf_catapult_dct2000_ipprim_udp_port :
2655 hf_catapult_dct2000_ipprim_tcp_port,
2656 tvb, source_port_offset, 2, ENC_BIG_ENDIAN);
2657 PROTO_ITEM_SET_HIDDEN(port_ti);
2659 if (dest_addr_offset != 0) {
2660 proto_item *addr_ti;
2662 TVB_SET_ADDRESS(&pinfo->net_dst,
2663 (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2664 tvb, dest_addr_offset, dest_addr_length);
2665 TVB_SET_ADDRESS(&pinfo->dst,
2666 (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2667 tvb, dest_addr_offset, dest_addr_length);
2668 proto_tree_add_item(ipprim_tree,
2669 (dest_addr_length == 4) ?
2670 hf_catapult_dct2000_ipprim_dst_addr_v4 :
2671 hf_catapult_dct2000_ipprim_dst_addr_v6,
2672 tvb, dest_addr_offset, dest_addr_length,
2673 (dest_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2675 /* Add hidden item for "side-less" addr */
2676 addr_ti = proto_tree_add_item(ipprim_tree,
2677 (dest_addr_length == 4) ?
2678 hf_catapult_dct2000_ipprim_addr_v4 :
2679 hf_catapult_dct2000_ipprim_addr_v6,
2680 tvb, dest_addr_offset, dest_addr_length,
2681 (dest_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2682 PROTO_ITEM_SET_HIDDEN(addr_ti);
2684 if (dest_port_offset != 0) {
2685 proto_item *port_ti;
2687 pinfo->destport = tvb_get_ntohs(tvb, dest_port_offset);
2689 proto_tree_add_item(ipprim_tree,
2690 (type_of_port == PT_UDP) ?
2691 hf_catapult_dct2000_ipprim_udp_dst_port :
2692 hf_catapult_dct2000_ipprim_tcp_dst_port,
2693 tvb, dest_port_offset, 2, ENC_BIG_ENDIAN);
2694 port_ti = proto_tree_add_item(ipprim_tree,
2695 (type_of_port == PT_UDP) ?
2696 hf_catapult_dct2000_ipprim_udp_port :
2697 hf_catapult_dct2000_ipprim_tcp_port,
2698 tvb, dest_port_offset, 2, ENC_BIG_ENDIAN);
2699 PROTO_ITEM_SET_HIDDEN(port_ti);
2701 if (conn_id_offset != 0) {
2702 proto_tree_add_item(ipprim_tree,
2703 hf_catapult_dct2000_ipprim_conn_id,
2704 tvb, conn_id_offset, 2, ENC_BIG_ENDIAN);
2708 /* Set source and dest columns now (will be overwriiten if
2709 src and dst IP addresses set) */
2710 if (source_addr_offset) {
2711 col_append_fstr(pinfo->cinfo, COL_DEF_SRC,
2712 "(%s:%u)",
2713 get_hostname(tvb_get_ipv4(tvb, source_addr_offset)),
2714 tvb_get_ntohs(tvb, source_port_offset));
2716 if (dest_addr_offset) {
2717 col_append_fstr(pinfo->cinfo, COL_DEF_DST,
2718 "(%s:%u)",
2719 get_hostname(tvb_get_ipv4(tvb, dest_addr_offset)),
2720 tvb_get_ntohs(tvb, dest_port_offset));
2723 /* Set length for IPPrim tree */
2724 proto_item_set_len(ipprim_tree, offset - offset_before_ipprim_header);
2729 /* Try SCTP Prim heuristic if configured to */
2730 if (!protocol_handle && catapult_dct2000_try_sctpprim_heuristic) {
2731 guint32 dest_addr_offset = 0;
2732 guint16 dest_addr_length = 0;
2733 guint32 dest_port_offset = 0;
2734 int offset_before_sctpprim_header = offset;
2736 heur_protocol_handle = look_for_dissector(protocol_name);
2737 if ((heur_protocol_handle != 0) &&
2738 (find_sctpprim_variant1_data_offset(tvb, &offset,
2739 &dest_addr_offset,
2740 &dest_addr_length,
2741 &dest_port_offset) ||
2742 find_sctpprim_variant3_data_offset(tvb, &offset,
2743 &dest_addr_offset,
2744 &dest_addr_length,
2745 &dest_port_offset))) {
2747 proto_tree *sctpprim_tree;
2748 proto_item *ti_local;
2750 /* Will use this dissector then. */
2751 protocol_handle = heur_protocol_handle;
2753 ti_local = proto_tree_add_string_format(dct2000_tree, hf_catapult_dct2000_sctpprim_addresses,
2754 tvb, offset_before_sctpprim_header, 0,
2755 "", "SCTPPrim transport: -> %s:%u",
2756 (dest_addr_offset) ?
2757 ((dest_addr_length == 4) ?
2758 get_hostname(tvb_get_ipv4(tvb, dest_addr_offset)) :
2759 "<ipv6-address>"
2761 "0.0.0.0",
2762 (dest_port_offset) ?
2763 tvb_get_ntohs(tvb, dest_port_offset) :
2766 /* Add these SCTPPRIM fields inside an SCTPPRIM subtree */
2767 sctpprim_tree = proto_item_add_subtree(ti_local, ett_catapult_dct2000_sctpprim);
2769 pinfo->ipproto = IP_PROTO_SCTP;
2771 /* Destination address */
2772 if (dest_addr_offset != 0) {
2773 proto_item *addr_ti;
2775 TVB_SET_ADDRESS(&pinfo->net_dst,
2776 (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2777 tvb, dest_addr_offset, dest_addr_length);
2778 TVB_SET_ADDRESS(&pinfo->dst,
2779 (dest_addr_length == 4) ? AT_IPv4 : AT_IPv6,
2780 tvb, dest_addr_offset, dest_addr_length);
2781 proto_tree_add_item(sctpprim_tree,
2782 (dest_addr_length == 4) ?
2783 hf_catapult_dct2000_sctpprim_dst_addr_v4 :
2784 hf_catapult_dct2000_sctpprim_dst_addr_v6,
2785 tvb, dest_addr_offset, dest_addr_length,
2786 (dest_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2788 /* Add hidden item for "side-less" addr */
2789 addr_ti = proto_tree_add_item(sctpprim_tree,
2790 (dest_addr_length == 4) ?
2791 hf_catapult_dct2000_sctpprim_addr_v4 :
2792 hf_catapult_dct2000_sctpprim_addr_v6,
2793 tvb, dest_addr_offset, dest_addr_length,
2794 (dest_addr_length == 4) ? ENC_BIG_ENDIAN : ENC_NA);
2795 PROTO_ITEM_SET_HIDDEN(addr_ti);
2798 if (dest_port_offset != 0) {
2799 pinfo->destport = tvb_get_ntohs(tvb, dest_port_offset);
2801 proto_tree_add_item(sctpprim_tree,
2802 hf_catapult_dct2000_sctpprim_dst_port,
2803 tvb, dest_port_offset, 2, ENC_BIG_ENDIAN);
2806 /* Set length for SCTPPrim tree */
2807 proto_item_set_len(sctpprim_tree, offset - offset_before_sctpprim_header);
2811 /* Last chance: is there a (private) registered protocol of the form
2812 "dct2000.protocol" ? */
2813 if (protocol_handle == 0) {
2814 /* TODO: only look inside preference? */
2815 char dotted_protocol_name[64+128];
2816 g_snprintf(dotted_protocol_name, 64+128, "dct2000.%s", protocol_name);
2817 protocol_handle = find_dissector(dotted_protocol_name);
2820 break;
2822 default:
2823 /* !! If get here, there is a mismatch between
2824 this dissector and the wiretap module catapult_dct2000.c !!
2826 DISSECTOR_ASSERT_NOT_REACHED();
2827 return;
2830 /* Set selection length of dct2000 tree */
2831 proto_item_set_len(dct2000_tree, offset);
2833 /* Try appropriate dissector, if one has been selected */
2834 if (protocol_handle != 0) {
2835 /* Dissect the remainder of the frame using chosen protocol handle */
2836 next_tvb = tvb_new_subset_remaining(tvb, offset);
2837 sub_dissector_result = call_dissector_only(protocol_handle, next_tvb, pinfo, tree, NULL);
2841 if (protocol_handle == 0 || sub_dissector_result == 0) {
2842 /* Could get here because:
2843 - encap is DCT2000_ENCAP_UNHANDLED and we still didn't handle it, OR
2844 - desired protocol is unavailable (probably disabled), OR
2845 - protocol rejected our data
2846 Show remaining bytes as unparsed data */
2847 proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_unparsed_data,
2848 tvb, offset, -1, ENC_NA);
2850 col_add_fstr(pinfo->cinfo, COL_INFO,
2851 "Not dissected (context=%s.%u t=%s %c prot=%s (v=%s))",
2852 context_name,
2853 port_number,
2854 timestamp_string,
2855 (direction == 0) ? 'S' : 'R',
2856 protocol_name,
2857 variant_string);
2859 else {
2860 /* Show number of dissected bytes */
2861 if (dct2000_tree) {
2862 proto_item *ti_local = proto_tree_add_uint(dct2000_tree,
2863 hf_catapult_dct2000_dissected_length,
2864 tvb, 0, 0, tvb_reported_length(tvb)-offset);
2865 PROTO_ITEM_SET_GENERATED(ti_local);
2872 /******************************************************************************/
2873 /* Associate this protocol with the Catapult DCT2000 file encapsulation type. */
2874 /******************************************************************************/
2875 void proto_reg_handoff_catapult_dct2000(void)
2877 dissector_handle_t catapult_dct2000_handle = find_dissector("dct2000");
2879 dissector_add_uint("wtap_encap", WTAP_ENCAP_CATAPULT_DCT2000, catapult_dct2000_handle);
2881 mac_lte_handle = find_dissector("mac-lte");
2882 rlc_lte_handle = find_dissector("rlc-lte");
2883 pdcp_lte_handle = find_dissector("pdcp-lte");
2886 /****************************************/
2887 /* Register the protocol */
2888 /****************************************/
2889 void proto_register_catapult_dct2000(void)
2891 static hf_register_info hf[] =
2893 { &hf_catapult_dct2000_context,
2894 { "Context",
2895 "dct2000.context", FT_STRING, BASE_NONE, NULL, 0x0,
2896 "Context name", HFILL
2899 { &hf_catapult_dct2000_port_number,
2900 { "Context Port number",
2901 "dct2000.context_port", FT_UINT8, BASE_DEC, NULL, 0x0,
2902 NULL, HFILL
2905 { &hf_catapult_dct2000_timestamp,
2906 { "Timestamp",
2907 "dct2000.timestamp", FT_DOUBLE, BASE_NONE, NULL, 0x0,
2908 "File timestamp", HFILL
2911 { &hf_catapult_dct2000_protocol,
2912 { "DCT2000 protocol",
2913 "dct2000.protocol", FT_STRING, BASE_NONE, NULL, 0x0,
2914 "Original (DCT2000) protocol name", HFILL
2917 { &hf_catapult_dct2000_variant,
2918 { "Protocol variant",
2919 "dct2000.variant", FT_STRING, BASE_NONE, NULL, 0x0,
2920 "DCT2000 protocol variant", HFILL
2923 { &hf_catapult_dct2000_outhdr,
2924 { "Out-header",
2925 "dct2000.outhdr", FT_STRING, BASE_NONE, NULL, 0x0,
2926 "DCT2000 protocol outhdr", HFILL
2929 { &hf_catapult_dct2000_direction,
2930 { "Direction",
2931 "dct2000.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
2932 "Frame direction (Sent or Received)", HFILL
2935 { &hf_catapult_dct2000_encap,
2936 { "Wireshark encapsulation",
2937 "dct2000.encapsulation", FT_UINT8, BASE_DEC, VALS(encap_vals), 0x0,
2938 "Wireshark frame encapsulation used", HFILL
2941 { &hf_catapult_dct2000_unparsed_data,
2942 { "Unparsed protocol data",
2943 "dct2000.unparsed_data", FT_BYTES, BASE_NONE, NULL, 0x0,
2944 "Unparsed DCT2000 protocol data", HFILL
2947 { &hf_catapult_dct2000_comment,
2948 { "Comment",
2949 "dct2000.comment", FT_STRING, BASE_NONE, NULL, 0x0,
2950 NULL, HFILL
2953 { &hf_catapult_dct2000_sprint,
2954 { "Sprint text",
2955 "dct2000.sprint", FT_STRING, BASE_NONE, NULL, 0x0,
2956 NULL, HFILL
2959 { &hf_catapult_dct2000_error_comment,
2960 { "Error comment",
2961 "dct2000.error-comment", FT_NONE, BASE_NONE, NULL, 0x0,
2962 NULL, HFILL
2965 { &hf_catapult_dct2000_dissected_length,
2966 { "Dissected length",
2967 "dct2000.dissected-length", FT_UINT16, BASE_DEC, NULL, 0x0,
2968 "Number of bytes dissected by subdissector(s)", HFILL
2972 { &hf_catapult_dct2000_ipprim_addresses,
2973 { "IPPrim Addresses",
2974 "dct2000.ipprim", FT_STRING, BASE_NONE, NULL, 0x0,
2975 NULL, HFILL
2978 { &hf_catapult_dct2000_ipprim_src_addr_v4,
2979 { "Source Address",
2980 "dct2000.ipprim.src", FT_IPv4, BASE_NONE, NULL, 0x0,
2981 "IPPrim IPv4 Source Address", HFILL
2984 { &hf_catapult_dct2000_ipprim_src_addr_v6,
2985 { "Source Address",
2986 "dct2000.ipprim.srcv6", FT_IPv6, BASE_NONE, NULL, 0x0,
2987 "IPPrim IPv6 Source Address", HFILL
2990 { &hf_catapult_dct2000_ipprim_dst_addr_v4,
2991 { "Destination Address",
2992 "dct2000.ipprim.dst", FT_IPv4, BASE_NONE, NULL, 0x0,
2993 "IPPrim IPv4 Destination Address", HFILL
2996 { &hf_catapult_dct2000_ipprim_dst_addr_v6,
2997 { "Destination Address",
2998 "dct2000.ipprim.dstv6", FT_IPv6, BASE_NONE, NULL, 0x0,
2999 "IPPrim IPv6 Destination Address", HFILL
3002 { &hf_catapult_dct2000_ipprim_addr_v4,
3003 { "Address",
3004 "dct2000.ipprim.addr", FT_IPv4, BASE_NONE, NULL, 0x0,
3005 "IPPrim IPv4 Address", HFILL
3008 { &hf_catapult_dct2000_ipprim_addr_v6,
3009 { "Address",
3010 "dct2000.ipprim.addrv6", FT_IPv6, BASE_NONE, NULL, 0x0,
3011 "IPPrim IPv6 Address", HFILL
3014 { &hf_catapult_dct2000_ipprim_udp_src_port,
3015 { "UDP Source Port",
3016 "dct2000.ipprim.udp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
3017 "IPPrim UDP Source Port", HFILL
3020 { &hf_catapult_dct2000_ipprim_udp_dst_port,
3021 { "UDP Destination Port",
3022 "dct2000.ipprim.udp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
3023 "IPPrim UDP Destination Port", HFILL
3026 { &hf_catapult_dct2000_ipprim_udp_port,
3027 { "UDP Port",
3028 "dct2000.ipprim.udp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
3029 "IPPrim UDP Port", HFILL
3032 { &hf_catapult_dct2000_ipprim_tcp_src_port,
3033 { "TCP Source Port",
3034 "dct2000.ipprim.tcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
3035 "IPPrim TCP Source Port", HFILL
3038 { &hf_catapult_dct2000_ipprim_tcp_dst_port,
3039 { "TCP Destination Port",
3040 "dct2000.ipprim.tcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
3041 "IPPrim TCP Destination Port", HFILL
3044 { &hf_catapult_dct2000_ipprim_tcp_port,
3045 { "TCP Port",
3046 "dct2000.ipprim.tcp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
3047 "IPPrim TCP Port", HFILL
3050 { &hf_catapult_dct2000_ipprim_conn_id,
3051 { "Conn Id",
3052 "dct2000.ipprim.conn-id", FT_UINT16, BASE_DEC, NULL, 0x0,
3053 "IPPrim TCP Connection ID", HFILL
3057 { &hf_catapult_dct2000_sctpprim_addresses,
3058 { "SCTPPrim Addresses",
3059 "dct2000.sctpprim", FT_STRING, BASE_NONE, NULL, 0x0,
3060 NULL, HFILL
3063 { &hf_catapult_dct2000_sctpprim_dst_addr_v4,
3064 { "Destination Address",
3065 "dct2000.sctpprim.dst", FT_IPv4, BASE_NONE, NULL, 0x0,
3066 "SCTPPrim IPv4 Destination Address", HFILL
3069 { &hf_catapult_dct2000_sctpprim_dst_addr_v6,
3070 { "Destination Address",
3071 "dct2000.sctpprim.dstv6", FT_IPv6, BASE_NONE, NULL, 0x0,
3072 "SCTPPrim IPv6 Destination Address", HFILL
3075 { &hf_catapult_dct2000_sctpprim_addr_v4,
3076 { "Address",
3077 "dct2000.sctpprim.addr", FT_IPv4, BASE_NONE, NULL, 0x0,
3078 "SCTPPrim IPv4 Address", HFILL
3081 { &hf_catapult_dct2000_sctpprim_addr_v6,
3082 { "Address",
3083 "dct2000.sctpprim.addrv6", FT_IPv6, BASE_NONE, NULL, 0x0,
3084 "SCTPPrim IPv6 Address", HFILL
3087 { &hf_catapult_dct2000_sctpprim_dst_port,
3088 { "UDP Destination Port",
3089 "dct2000.sctprim.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
3090 "SCTPPrim Destination Port", HFILL
3094 { &hf_catapult_dct2000_tty,
3095 { "tty contents",
3096 "dct2000.tty", FT_NONE, BASE_NONE, NULL, 0x0,
3097 NULL, HFILL
3100 { &hf_catapult_dct2000_tty_line,
3101 { "tty line",
3102 "dct2000.tty-line", FT_STRING, BASE_NONE, NULL, 0x0,
3103 NULL, HFILL
3107 { &hf_catapult_dct2000_lte_ueid,
3108 { "UE Id",
3109 "dct2000.lte.ueid", FT_UINT16, BASE_DEC, NULL, 0x0,
3110 "User Equipment Identifier", HFILL
3113 { &hf_catapult_dct2000_lte_srbid,
3114 { "srbid",
3115 "dct2000.lte.srbid", FT_UINT8, BASE_DEC, NULL, 0x0,
3116 "Signalling Radio Bearer Identifier", HFILL
3119 { &hf_catapult_dct2000_lte_drbid,
3120 { "drbid",
3121 "dct2000.lte.drbid", FT_UINT8, BASE_DEC, NULL, 0x0,
3122 "Data Radio Bearer Identifier", HFILL
3125 { &hf_catapult_dct2000_lte_cellid,
3126 { "Cell-Id",
3127 "dct2000.lte.cellid", FT_UINT16, BASE_DEC, NULL, 0x0,
3128 "Cell Identifier", HFILL
3131 { &hf_catapult_dct2000_lte_bcch_transport,
3132 { "BCCH Transport",
3133 "dct2000.lte.bcch-transport", FT_UINT16, BASE_DEC, VALS(bcch_transport_vals), 0x0,
3134 "BCCH Transport Channel", HFILL
3137 { &hf_catapult_dct2000_lte_rlc_op,
3138 { "RLC Op",
3139 "dct2000.lte.rlc-op", FT_UINT8, BASE_DEC, VALS(rlc_op_vals), 0x0,
3140 "RLC top-level op", HFILL
3143 { &hf_catapult_dct2000_lte_rlc_channel_type,
3144 { "RLC Logical Channel Type",
3145 "dct2000.lte.rlc-logchan-type", FT_UINT8, BASE_DEC, VALS(rlc_logical_channel_vals), 0x0,
3146 NULL, HFILL
3149 { &hf_catapult_dct2000_lte_rlc_mui,
3150 { "MUI",
3151 "dct2000.lte.rlc-mui", FT_UINT16, BASE_DEC, NULL, 0x0,
3152 "RLC MUI", HFILL
3155 { &hf_catapult_dct2000_lte_rlc_cnf,
3156 { "CNF",
3157 "dct2000.lte.rlc-cnf", FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0,
3158 "RLC CNF", HFILL
3161 { &hf_catapult_dct2000_lte_rlc_discard_req,
3162 { "Discard Req",
3163 "dct2000.lte.rlc-discard-req", FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0,
3164 "RLC Discard Req", HFILL
3168 { &hf_catapult_dct2000_lte_ccpri_opcode,
3169 { "CCPRI opcode",
3170 "dct2000.lte.ccpri.opcode", FT_UINT8, BASE_DEC, VALS(ccpri_opcode_vals), 0x0,
3171 NULL, HFILL
3174 { &hf_catapult_dct2000_lte_ccpri_status,
3175 { "Status",
3176 "dct2000.lte.ccpri.status", FT_UINT8, BASE_DEC, VALS(ccpri_status_vals), 0x0,
3177 NULL, HFILL
3180 { &hf_catapult_dct2000_lte_ccpri_channel,
3181 { "Channel",
3182 "dct2000.lte.ccpri.channel", FT_UINT8, BASE_DEC, NULL, 0x0,
3183 NULL, HFILL
3187 { &hf_catapult_dct2000_lte_nas_rrc_opcode,
3188 { "NAS RRC Opcode",
3189 "dct2000.lte.nas-rrc.opcode", FT_UINT8, BASE_DEC, VALS(lte_nas_rrc_opcode_vals), 0x0,
3190 NULL, HFILL
3193 { &hf_catapult_dct2000_lte_nas_rrc_establish_cause,
3194 { "Establish Cause",
3195 "dct2000.lte.nas-rrc.establish-cause", FT_UINT8, BASE_DEC, NULL, 0x0,
3196 NULL, HFILL
3199 { &hf_catapult_dct2000_lte_nas_rrc_priority,
3200 { "Priority",
3201 "dct2000.lte.nas-rrc.priority", FT_UINT8, BASE_DEC, NULL, 0x0,
3202 NULL, HFILL
3205 { &hf_catapult_dct2000_lte_nas_rrc_release_cause,
3206 { "Priority",
3207 "dct2000.lte.nas-rrc.priority", FT_UINT8, BASE_DEC, NULL, 0x0,
3208 NULL, HFILL
3213 { &hf_catapult_dct2000_ueid,
3214 { "UE Id",
3215 "dct2000.ueid", FT_UINT32, BASE_DEC, NULL, 0x0,
3216 "User Equipment Identifier", HFILL
3219 { &hf_catapult_dct2000_rbid,
3220 { "Channel",
3221 "dct2000.rbid", FT_UINT8, BASE_DEC, VALS(rlc_rbid_vals), 0x0,
3222 "Channel (rbid)", HFILL
3225 { &hf_catapult_dct2000_ccch_id,
3226 { "CCCH Id",
3227 "dct2000.ccch-id", FT_UINT8, BASE_DEC, NULL, 0x0,
3228 "CCCH Identifier", HFILL
3231 { &hf_catapult_dct2000_no_crc_error,
3232 { "No CRC Error",
3233 "dct2000.no-crc-error", FT_NONE, BASE_NONE, NULL, 0x0,
3234 NULL, HFILL
3237 { &hf_catapult_dct2000_crc_error,
3238 { "CRC Error",
3239 "dct2000.crc-error", FT_NONE, BASE_NONE, NULL, 0x0,
3240 NULL, HFILL
3243 { &hf_catapult_dct2000_clear_tx_buffer,
3244 { "Clear Tx Buffer",
3245 "dct2000.clear-tx-buffer", FT_NONE, BASE_NONE, NULL, 0x0,
3246 NULL, HFILL
3249 { &hf_catapult_dct2000_buffer_occupancy,
3250 { "Buffer Occupancy",
3251 "dct2000.buffer-occupancy", FT_UINT8, BASE_DEC, NULL, 0x0,
3252 NULL, HFILL
3255 { &hf_catapult_dct2000_pdu_size,
3256 { "PDU Size",
3257 "dct2000.pdu-size", FT_UINT16, BASE_DEC, NULL, 0x0,
3258 NULL, HFILL
3261 { &hf_catapult_dct2000_ueid_type,
3262 { "UEId Type",
3263 "dct2000.ueid-type", FT_UINT8, BASE_DEC, VALS(ueid_type_vals), 0x0,
3264 NULL, HFILL
3267 { &hf_catapult_dct2000_tx_priority,
3268 { "Tx Priority",
3269 "dct2000.tx-priority", FT_UINT8, BASE_DEC, VALS(tx_priority_vals), 0x0,
3270 NULL, HFILL
3273 { &hf_catapult_dct2000_last_in_seg_set,
3274 { "Last in seg set",
3275 "dct2000.last-in-seg-set", FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0,
3276 NULL, HFILL
3279 { &hf_catapult_dct2000_rx_timing_deviation,
3280 { "Tx Timing Deviation",
3281 "dct2000.rx-timing-deviation", FT_UINT32, BASE_DEC, NULL, 0x0,
3282 NULL, HFILL
3285 { &hf_catapult_dct2000_transport_channel_type,
3286 { "Transport Channel Type",
3287 "dct2000.transport_channel_type", FT_UINT8, BASE_DEC, VALS(transport_channel_type_vals), 0x0,
3288 NULL, HFILL
3291 { &hf_catapult_dct2000_no_padding_bits,
3292 { "Number of padding bits",
3293 "dct2000.number-of-padding-bits", FT_UINT8, BASE_DEC, NULL, 0x0,
3294 NULL, HFILL
3300 static gint *ett[] =
3302 &ett_catapult_dct2000,
3303 &ett_catapult_dct2000_ipprim,
3304 &ett_catapult_dct2000_sctpprim,
3305 &ett_catapult_dct2000_tty
3308 static ei_register_info ei[] = {
3309 { &ei_catapult_dct2000_lte_ccpri_status_error, { "dct2000.lte.ccpri.status.error", PI_SEQUENCE, PI_ERROR, "CCPRI Indication has error status", EXPFILL }},
3310 { &ei_catapult_dct2000_error_comment_expert, { "dct2000.error-comment.expert", PI_SEQUENCE, PI_ERROR, "Formatted expert comment", EXPFILL }},
3313 module_t *catapult_dct2000_module;
3314 expert_module_t* expert_catapult_dct2000;
3316 /* Register protocol. */
3317 proto_catapult_dct2000 = proto_register_protocol("Catapult DCT2000 packet",
3318 "DCT2000",
3319 "dct2000");
3320 proto_register_field_array(proto_catapult_dct2000, hf, array_length(hf));
3321 proto_register_subtree_array(ett, array_length(ett));
3322 expert_catapult_dct2000 = expert_register_protocol(proto_catapult_dct2000);
3323 expert_register_field_array(expert_catapult_dct2000, ei, array_length(ei));
3325 /* Allow dissector to find be found by name. */
3326 register_dissector("dct2000", dissect_catapult_dct2000, proto_catapult_dct2000);
3328 /* Preferences */
3329 catapult_dct2000_module = prefs_register_protocol(proto_catapult_dct2000, NULL);
3331 /* This preference no longer supported (introduces linkage dependency between
3332 dissectors and wiretap) */
3333 prefs_register_obsolete_preference(catapult_dct2000_module, "board_ports_only");
3335 /* Determines whether for not-handled protocols we should try to parse it if:
3336 - it looks like it's embedded in an ipprim message, AND
3337 - the DCT2000 protocol name can be matched to a Wireshark dissector name */
3338 prefs_register_bool_preference(catapult_dct2000_module, "ipprim_heuristic",
3339 "Use IP Primitive heuristic",
3340 "If a payload looks like it's embedded in an "
3341 "IP primitive message, and there is a Wireshark "
3342 "dissector matching the DCT2000 protocol name, "
3343 "try parsing the payload using that dissector",
3344 &catapult_dct2000_try_ipprim_heuristic);
3346 /* Determines whether for not-handled protocols we should try to parse it if:
3347 - it looks like it's embedded in an sctpprim message, AND
3348 - the DCT2000 protocol name can be matched to a Wireshark dissector name */
3349 prefs_register_bool_preference(catapult_dct2000_module, "sctpprim_heuristic",
3350 "Use SCTP Primitive heuristic",
3351 "If a payload looks like it's embedded in an "
3352 "SCTP primitive message, and there is a Wireshark "
3353 "dissector matching the DCT2000 protocol name, "
3354 "try parsing the payload using that dissector",
3355 &catapult_dct2000_try_sctpprim_heuristic);
3357 /* Determines whether LTE RRC messages should be dissected */
3358 prefs_register_bool_preference(catapult_dct2000_module, "decode_lte_rrc",
3359 "Attempt to decode LTE RRC frames",
3360 "When set, attempt to decode LTE RRC frames. "
3361 "Note that this won't affect other protocols "
3362 "that also call the LTE RRC dissector",
3363 &catapult_dct2000_dissect_lte_rrc);
3365 /* Determines whether LTE S1AP messages should be dissected */
3366 prefs_register_bool_preference(catapult_dct2000_module, "decode_lte_s1ap",
3367 "Attempt to decode LTE S1AP frames",
3368 "When set, attempt to decode LTE S1AP frames. "
3369 "Note that this won't affect other protocols "
3370 "that also call the LTE S1AP dissector",
3371 &catapult_dct2000_dissect_lte_s1ap);
3373 /* Determines whether out-of-band messages should dissected */
3374 prefs_register_bool_preference(catapult_dct2000_module, "decode_mac_lte_oob_messages",
3375 "Look for out-of-band LTE MAC events messages in comments",
3376 "When set, look for formatted messages indicating "
3377 "specific events. This may be quite slow, so should "
3378 "be disabled if LTE MAC is not being analysed",
3379 &catapult_dct2000_dissect_mac_lte_oob_messages);