1 /* packet-catapult-dct2000.c
2 * Routines for Catapult DCT2000 packet stub header disassembly
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include <stdio.h> /* for sscanf() */
15 #include <epan/packet.h>
16 #include <epan/expert.h>
17 #include <epan/prefs.h>
18 #include <epan/addr_resolv.h>
19 #include <epan/proto_data.h>
22 #include <wsutil/strtoi.h>
24 #include <wiretap/catapult_dct2000.h>
25 #include "packet-umts_fp.h"
26 #include "packet-umts_rlc.h"
28 #include "packet-mac-lte.h"
29 #include "packet-rlc-lte.h"
30 #include "packet-pdcp-lte.h"
32 #include "packet-mac-nr.h"
33 #include "packet-pdcp-nr.h"
35 void proto_reg_handoff_catapult_dct2000(void);
36 void proto_register_catapult_dct2000(void);
38 /* Protocol and registered fields. */
39 static int proto_catapult_dct2000
;
41 static int hf_catapult_dct2000_context
;
42 static int hf_catapult_dct2000_port_number
;
43 static int hf_catapult_dct2000_timestamp
;
44 static int hf_catapult_dct2000_protocol
;
45 static int hf_catapult_dct2000_variant
;
46 static int hf_catapult_dct2000_outhdr
;
47 static int hf_catapult_dct2000_direction
;
48 static int hf_catapult_dct2000_encap
;
49 static int hf_catapult_dct2000_unparsed_data
;
50 static int hf_catapult_dct2000_comment
;
51 static int hf_catapult_dct2000_sprint
;
52 static int hf_catapult_dct2000_error_comment
;
53 static int hf_catapult_dct2000_tty
;
54 static int hf_catapult_dct2000_tty_line
;
55 static int hf_catapult_dct2000_dissected_length
;
57 static int hf_catapult_dct2000_ipprim_addresses
;
58 static int hf_catapult_dct2000_ipprim_src_addr_v4
;
59 static int hf_catapult_dct2000_ipprim_src_addr_v6
;
60 static int hf_catapult_dct2000_ipprim_dst_addr_v4
;
61 static int hf_catapult_dct2000_ipprim_dst_addr_v6
;
62 static int hf_catapult_dct2000_ipprim_addr_v4
;
63 static int hf_catapult_dct2000_ipprim_addr_v6
;
64 static int hf_catapult_dct2000_ipprim_udp_src_port
;
65 static int hf_catapult_dct2000_ipprim_udp_dst_port
;
66 static int hf_catapult_dct2000_ipprim_udp_port
;
67 static int hf_catapult_dct2000_ipprim_tcp_src_port
;
68 static int hf_catapult_dct2000_ipprim_tcp_dst_port
;
69 static int hf_catapult_dct2000_ipprim_tcp_port
;
70 static int hf_catapult_dct2000_ipprim_conn_id
;
72 static int hf_catapult_dct2000_sctpprim_addresses
;
73 static int hf_catapult_dct2000_sctpprim_dst_addr_v4
;
74 static int hf_catapult_dct2000_sctpprim_dst_addr_v6
;
75 static int hf_catapult_dct2000_sctpprim_addr_v4
;
76 static int hf_catapult_dct2000_sctpprim_addr_v6
;
77 static int hf_catapult_dct2000_sctpprim_dst_port
;
79 static int hf_catapult_dct2000_ueid
;
80 static int hf_catapult_dct2000_srbid
;
81 static int hf_catapult_dct2000_drbid
;
82 static int hf_catapult_dct2000_cellid
;
83 static int hf_catapult_dct2000_bcch_transport
;
84 static int hf_catapult_dct2000_rlc_op
;
85 static int hf_catapult_dct2000_rlc_channel_type
;
86 static int hf_catapult_dct2000_rlc_mui
;
87 static int hf_catapult_dct2000_rlc_cnf
;
88 static int hf_catapult_dct2000_rlc_discard_req
;
89 static int hf_catapult_dct2000_carrier_type
;
90 static int hf_catapult_dct2000_cell_group
;
91 static int hf_catapult_dct2000_carrier_id
;
93 static int hf_catapult_dct2000_security_mode_params
;
94 static int hf_catapult_dct2000_uplink_sec_mode
;
95 static int hf_catapult_dct2000_downlink_sec_mode
;
96 static int hf_catapult_dct2000_ciphering_algorithm
;
97 static int hf_catapult_dct2000_ciphering_key
;
98 static int hf_catapult_dct2000_integrity_algorithm
;
99 static int hf_catapult_dct2000_integrity_key
;
101 static int hf_catapult_dct2000_lte_ccpri_opcode
;
102 static int hf_catapult_dct2000_lte_ccpri_status
;
103 static int hf_catapult_dct2000_lte_ccpri_channel
;
105 static int hf_catapult_dct2000_lte_nas_rrc_opcode
;
106 static int hf_catapult_dct2000_lte_nas_rrc_establish_cause
;
107 static int hf_catapult_dct2000_lte_nas_rrc_priority
;
108 static int hf_catapult_dct2000_lte_nas_rrc_release_cause
;
110 static int hf_catapult_dct2000_nr_nas_s1ap_opcode
;
112 /* UMTS RLC fields */
113 static int hf_catapult_dct2000_rbid
;
114 static int hf_catapult_dct2000_ccch_id
;
115 static int hf_catapult_dct2000_no_crc_error
;
116 static int hf_catapult_dct2000_crc_error
;
117 static int hf_catapult_dct2000_clear_tx_buffer
;
118 static int hf_catapult_dct2000_buffer_occupancy
;
119 static int hf_catapult_dct2000_pdu_size
;
120 static int hf_catapult_dct2000_ueid_type
;
121 static int hf_catapult_dct2000_tx_priority
;
122 static int hf_catapult_dct2000_last_in_seg_set
;
123 static int hf_catapult_dct2000_rx_timing_deviation
;
124 static int hf_catapult_dct2000_transport_channel_type
;
125 static int hf_catapult_dct2000_no_padding_bits
;
127 static int hf_catapult_dct2000_rawtraffic_interface
;
128 static int hf_catapult_dct2000_rawtraffic_direction
;
129 static int hf_catapult_dct2000_rawtraffic_pdu
;
132 /* Variables used for preferences */
133 static bool catapult_dct2000_try_ipprim_heuristic
= true;
134 static bool catapult_dct2000_try_sctpprim_heuristic
= true;
135 static bool catapult_dct2000_dissect_lte_rrc
= true;
136 static bool catapult_dct2000_dissect_mac_lte_oob_messages
= true;
137 static bool catapult_dct2000_dissect_old_protocol_names
;
138 static bool catapult_dct2000_use_protocol_name_as_dissector_name
;
140 /* Protocol subtree. */
141 static int ett_catapult_dct2000
;
142 static int ett_catapult_dct2000_ipprim
;
143 static int ett_catapult_dct2000_sctpprim
;
144 static int ett_catapult_dct2000_tty
;
145 static int ett_catapult_dct2000_security_mode_params
;
147 static expert_field ei_catapult_dct2000_lte_ccpri_status_error
;
148 static expert_field ei_catapult_dct2000_error_comment_expert
;
149 static expert_field ei_catapult_dct2000_string_invalid
;
151 static const value_string direction_vals
[] = {
157 static const value_string encap_vals
[] = {
158 { WTAP_ENCAP_RAW_IP
, "Raw IP" },
159 { WTAP_ENCAP_ETHERNET
, "Ethernet" },
160 { WTAP_ENCAP_ISDN
, "LAPD" },
161 { WTAP_ENCAP_ATM_PDUS_UNTRUNCATED
, "ATM (PDUs untruncated)" },
162 { WTAP_ENCAP_PPP
, "PPP" },
163 { DCT2000_ENCAP_SSCOP
, "SSCOP" },
164 { WTAP_ENCAP_FRELAY
, "Frame Relay" },
165 { WTAP_ENCAP_MTP2
, "MTP2" },
166 { DCT2000_ENCAP_NBAP
, "NBAP" },
167 { DCT2000_ENCAP_UNHANDLED
, "No Direct Encapsulation" },
171 static const value_string bcch_transport_vals
[] = {
172 { BCH_TRANSPORT
, "BCH" },
173 { DLSCH_TRANSPORT
, "DLSCH" },
178 #define RLC_MGMT_ASSIGN 0x41
179 #define RLC_AM_DATA_REQ 0x60
180 #define RLC_AM_DATA_IND 0x61
181 #define RLC_AM_DATA_CONF 0x62
182 #define RLC_UM_DATA_REQ 0x70
183 #define RLC_UM_DATA_IND 0x71
184 #define RLC_UM_DATA_CONF 0x74
185 #define RLC_TR_DATA_REQ 0x80
186 #define RLC_TR_DATA_IND 0x81
187 #define RLC_TR_DATA_CONF 0x83
189 static const value_string rlc_op_vals
[] = {
190 { RLC_AM_DATA_REQ
, "[UL] [AM]" },
191 { RLC_AM_DATA_IND
, "[DL] [AM]" },
192 { RLC_UM_DATA_REQ
, "[UL] [UM]"},
193 { RLC_UM_DATA_IND
, "[DL] [UM]"},
194 { RLC_TR_DATA_REQ
, "[UL] [TM]"},
195 { RLC_TR_DATA_IND
, "[DL] [TM]"},
200 static const value_string rlc_logical_channel_vals
[] = {
201 { Channel_DCCH
, "DCCH"},
202 { Channel_BCCH
, "BCCH"},
203 { Channel_CCCH
, "CCCH"},
204 { Channel_PCCH
, "PCCH"},
212 static const value_string ccpri_opcode_vals
[] = {
213 { CCPRI_REQ
, "REQUEST"},
214 { CCPRI_IND
, "INDICATION"},
218 static const value_string rlc_rbid_vals
[] = {
244 static value_string_ext rlc_rbid_vals_ext
= VALUE_STRING_EXT_INIT(rlc_rbid_vals
);
246 static const value_string ueid_type_vals
[] = {
252 static const value_string transport_channel_type_vals
[] = {
265 #define LTE_NAS_RRC_DATA_IND 0x02
266 #define LTE_NAS_RRC_DATA_REQ 0x03
267 #define LTE_NAS_RRC_ESTABLISH_REQ 0x06
268 #define LTE_NAS_RRC_RELEASE_IND 0x08
270 static const value_string lte_nas_rrc_opcode_vals
[] = {
271 { LTE_NAS_RRC_DATA_IND
, "Data-Ind"},
272 { LTE_NAS_RRC_DATA_REQ
, "Data-Req"},
273 { LTE_NAS_RRC_ESTABLISH_REQ
, "Establish-Req"},
274 { LTE_NAS_RRC_RELEASE_IND
, "Release-Ind"},
279 #define NAS_S1AP_DATA_REQ 0x00
280 #define NAS_S1AP_DATA_IND 0x01
282 static const value_string nas_s1ap_opcode_vals
[] = {
283 { NAS_S1AP_DATA_REQ
, "Data-Req"},
284 { NAS_S1AP_DATA_IND
, "Data-Ind"},
289 /* Distinguish between similar 4G or 5G protocols */
295 static const value_string carrier_type_vals
[] = {
304 static const value_string security_mode_vals
[] = {
306 { 1, "Integrity only"},
307 { 2, "Ciphering and Integrity"},
311 static const value_string ciphering_algorithm_vals
[] = {
319 static const value_string integrity_algorithm_vals
[] = {
328 #define MAX_OUTHDR_VALUES 32
331 extern int proto_umts_rlc
;
333 extern int proto_rlc_lte
;
334 extern int proto_pdcp_lte
;
337 static dissector_handle_t mac_lte_handle
;
338 static dissector_handle_t rlc_lte_handle
;
339 static dissector_handle_t pdcp_lte_handle
;
340 static dissector_handle_t catapult_dct2000_handle
;
341 static dissector_handle_t nrup_handle
;
343 static dissector_handle_t mac_nr_handle
;
345 static dissector_handle_t eth_handle
;
347 static dissector_handle_t
look_for_dissector(const char *protocol_name
);
348 static unsigned parse_outhdr_string(const unsigned char *outhdr_string
, int outhdr_length
, unsigned *outhdr_values
);
350 static void attach_fp_info(packet_info
*pinfo
, bool received
,
351 const char *protocol_name
, int variant
,
352 unsigned *outhdr_values
, unsigned outhdr_values_found
);
353 static void attach_rlc_info(packet_info
*pinfo
, uint32_t urnti
, uint8_t rbid
,
354 bool is_sent
, unsigned *outhdr_values
,
355 unsigned outhdr_values_found
);
357 static void attach_mac_lte_info(packet_info
*pinfo
, unsigned *outhdr_values
,
358 unsigned outhdr_values_found
);
359 static void attach_rlc_lte_info(packet_info
*pinfo
, unsigned *outhdr_values
,
360 unsigned outhdr_values_found
);
361 static void attach_pdcp_lte_info(packet_info
*pinfo
, unsigned *outhdr_values
,
362 unsigned outhdr_values_found
);
365 /* Return the number of bytes used to encode the length field
366 (we're not interested in the length value itself) */
367 static int skipASNLength(uint8_t value
)
369 if ((value
& 0x80) == 0)
375 return ((value
& 0x03) == 1) ? 2 : 3;
380 /* Look for the protocol data within an ipprim packet.
381 Only set *data_offset if data field found. */
382 static bool find_ipprim_data_offset(tvbuff_t
*tvb
, int *data_offset
, uint8_t direction
,
383 uint32_t *source_addr_offset
, uint8_t *source_addr_length
,
384 uint32_t *dest_addr_offset
, uint8_t *dest_addr_length
,
385 uint32_t *source_port_offset
, uint32_t *dest_port_offset
,
386 port_type
*type_of_port
,
387 uint16_t *conn_id_offset
)
390 int offset
= *data_offset
;
392 /* Get the ipprim command code. */
393 uint8_t tag
= tvb_get_uint8(tvb
, offset
++);
395 /* Only accept UDP or TCP data request or indication */
397 case 0x23: /* UDP data request */
398 case 0x24: /* UDP data indication */
399 *type_of_port
= PT_UDP
;
401 case 0x45: /* TCP data request */
402 case 0x46: /* TCP data indication */
403 *type_of_port
= PT_TCP
;
409 /* Skip any other TLC fields before reach payload */
410 while (tvb_reported_length_remaining(tvb
, offset
) > 2) {
411 /* Look at next tag */
412 tag
= tvb_get_uint8(tvb
, offset
++);
414 /* Is this the data payload we're expecting? */
415 if (((tag
== 0x34) && (*type_of_port
== PT_UDP
)) ||
416 ((tag
== 0x48) && (*type_of_port
== PT_TCP
))) {
418 *data_offset
= offset
;
422 /* Read length in next byte */
423 length
= tvb_get_uint8(tvb
, offset
++);
425 if (tag
== 0x31 && length
>=4) {
426 /* Remote IP address */
427 if (direction
== 0) {
428 /* Sent *to* remote, so dest */
429 *dest_addr_offset
= offset
;
430 *dest_addr_length
= (length
/4) * 4;
433 *source_addr_offset
= offset
;
434 *source_addr_length
= (length
/4) * 4;
437 /* Remote port follows (if present) */
438 if ((length
% 4) == 2) {
439 if (direction
== 0) {
440 *dest_port_offset
= offset
+ *dest_addr_length
;
443 *source_port_offset
= offset
+ *source_addr_length
;
449 if (length
== 4 || length
== 16) {
450 /* Local IP address */
451 if (direction
== 0) {
452 /* Sent *from* local, so source */
453 *source_addr_offset
= offset
;
454 *source_addr_length
= length
;
457 *dest_addr_offset
= offset
;
458 *dest_addr_length
= length
;
463 if (tag
== 0x33 && length
== 2) {
465 if (direction
== 0) {
466 /* Sent from local, so source */
467 *source_port_offset
= offset
;
470 *dest_port_offset
= offset
;
474 if (tag
== 0x36 && length
== 2) {
476 *conn_id_offset
= offset
;
479 /* Skip the length of the indicated value */
484 /* No data found... */
490 /* Look for the protocol data within an sctpprim (variant 1 or 2...) packet.
491 Only set *data_offset if data field found. */
492 static bool find_sctpprim_variant1_data_offset(tvbuff_t
*tvb
, int *data_offset
,
493 uint32_t *dest_addr_offset
,
494 uint16_t *dest_addr_length
,
495 uint32_t *dest_port_offset
)
497 int offset
= *data_offset
;
499 /* Get the sctpprim command code. */
500 uint8_t first_tag
= tvb_get_uint8(tvb
, offset
++);
502 uint8_t first_length_byte
;
504 /* Only accept interested in data requests or indications */
506 case 0x04: /* data request */
507 case 0x62: /* data indication */
513 first_length_byte
= tvb_get_uint8(tvb
, offset
);
514 offset
+= skipASNLength(first_length_byte
);
516 /* Skip any other fields before reach payload */
517 while (tvb_reported_length_remaining(tvb
, offset
) > 2) {
518 /* Look at next tag */
519 tag
= tvb_get_uint8(tvb
, offset
++);
521 /* Is this the data payload we're expecting? */
523 *data_offset
= offset
;
527 /* Skip length field */
530 case 0x0a: /* destPort */
531 *dest_port_offset
= offset
;
535 case 0x01: /* sctpInstanceNum */
536 case 0x1e: /* strseqnum */
537 case 0x0d: /* streamnum */
541 case 0x09: /* ipv4Address */
542 *dest_addr_offset
= offset
;
543 *dest_addr_length
= 4;
548 case 0x0c: /* payloadType */
553 /* Fail if not a known header field */
559 /* No data found... */
563 /* Look for the protocol data within an sctpprim (variant 3) packet.
564 Return value indicates whether this header found.
565 Only set *data_offset if data field found. */
566 static bool find_sctpprim_variant3_data_offset(tvbuff_t
*tvb
, int *data_offset
,
567 uint32_t *dest_addr_offset
,
568 uint16_t *dest_addr_length
,
569 uint32_t *dest_port_offset
)
573 int offset
= *data_offset
;
575 /* Get the sctpprim (2 byte) command code. */
576 uint16_t top_tag
= tvb_get_ntohs(tvb
, offset
);
579 /* Only interested in data requests or indications */
580 if ((top_tag
!= 0x0400) && /* SendDataReq */
581 (top_tag
!= 0x6200)) { /* DataInd */
585 /* Overall length field is next 2 bytes */
588 /* Rx/Tx ops have different formats */
592 if (top_tag
== 0x6200) {
593 /* Next 2 bytes are associate ID */
596 /* Next 2 bytes are destination port */
597 *dest_port_offset
= offset
;
600 /* Destination address should follow - check tag */
601 tag
= tvb_get_ntohs(tvb
, offset
);
610 length
= tvb_get_ntohs(tvb
, offset
) / 2;
611 if ((length
!= 4) && (length
!= 16))
617 /* Address data is here */
618 *dest_addr_offset
= offset
;
619 *dest_addr_length
= length
;
624 /* Not interested in remaining (fixed) fields */
625 if (tvb_reported_length_remaining(tvb
, offset
) > (4 + 2 + 2 + 4)) {
626 offset
+= (4 + 2 + 2 + 4);
632 /* Data should now be here */
633 tag
= tvb_get_ntohs(tvb
, offset
);
636 /* 2-byte length field */
639 /* Data is here!!! */
640 *data_offset
= offset
;
648 /***********************************/
649 /* SendDataReq (top_tag == 0x0400) */
651 /* AssociateId should follow - check tag */
652 tag
= tvb_get_ntohs(tvb
, offset
);
660 /* Skip 2-byte value */
665 tag
= tvb_get_ntohs(tvb
, offset
);
668 /* Some optional params */
669 while ((tag
!= 0x0c00) && (tvb_reported_length_remaining(tvb
, offset
) > 4)) {
671 case 0x0900: /* Dest address */
673 length
= tvb_get_ntohs(tvb
, offset
) / 2;
674 if ((length
!= 4) && (length
!= 16)) {
679 /* Address data is here */
680 *dest_addr_offset
= offset
;
681 *dest_addr_length
= length
;
686 case 0x0a00: /* Dest port number */
687 *dest_port_offset
= offset
;
691 case 0x0d00: /* StreamNum */
700 /* Get the next tag */
701 tag
= tvb_get_ntohs(tvb
, offset
);
706 /* Mandatory payload type */
710 length
= tvb_get_ntohs(tvb
, offset
) / 2;
715 /* Optional options */
716 tag
= tvb_get_ntohs(tvb
, offset
);
719 length
= tvb_get_ntohs(tvb
, offset
) / 2;
725 tag
= tvb_get_ntohs(tvb
, offset
);
730 /* Data should now be here!! */
732 /* 2-byte length field */
735 /* Data is here!!! */
736 *data_offset
= offset
;
746 /* Dissect a UMTS RLC frame by:
747 - parsing the primitive header
748 - passing those values + outhdeader to dissector
749 - calling the UMTS RLC dissector */
750 static void dissect_rlc_umts(tvbuff_t
*tvb
, int offset
,
751 packet_info
*pinfo
, proto_tree
*tree
,
752 bool is_sent
, unsigned *outhdr_values
,
753 unsigned outhdr_values_found
)
756 bool ueid_set
= false, rbid_set
=false;
761 dissector_handle_t rlc_umts_handle
= 0;
763 /* Top-level opcode */
764 tag
= tvb_get_uint8(tvb
, offset
++);
766 case 0xc0: /* mac data request */
767 case 0xc1: /* mac data indication */
771 /* No data to dissect */
775 /* Keep going until reach data tag or end of frame */
776 while ((tag
!= 0x41) && tvb_reported_length_remaining(tvb
, offset
)) { /* i.e. Data */
777 tag
= tvb_get_uint8(tvb
, offset
++);
779 case 0x72: /* UE Id */
780 ueid
= tvb_get_ntohl(tvb
, offset
);
782 proto_tree_add_item(tree
, hf_catapult_dct2000_ueid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
786 case 0xa2: /* RBID */
787 offset
++; /* skip length */
788 rbid
= tvb_get_uint8(tvb
, offset
);
789 proto_tree_add_item(tree
, hf_catapult_dct2000_rbid
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
793 case 0x22: /* CCCH-id setting rbid to CCCH! */
794 offset
++; /* skip length */
795 proto_tree_add_item(tree
, hf_catapult_dct2000_ccch_id
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
799 case 0xc4: /* No CRC error */
800 proto_tree_add_item(tree
, hf_catapult_dct2000_no_crc_error
, tvb
, offset
-1, 1, ENC_NA
);
802 case 0xc5: /* CRC error */
803 proto_tree_add_item(tree
, hf_catapult_dct2000_crc_error
, tvb
, offset
-1, 1, ENC_NA
);
805 case 0xf7: /* Clear Tx Buffer */
806 proto_tree_add_item(tree
, hf_catapult_dct2000_clear_tx_buffer
, tvb
, offset
-1, 1, ENC_NA
);
809 case 0x41: /* Data !!! */
810 offset
+= skipASNLength(tvb_get_uint8(tvb
, offset
));
814 /* For other fields, just skip length and following data */
815 length
= tvb_get_uint8(tvb
, offset
++);
817 case 0x42: /* Buffer Occupancy */
818 proto_tree_add_item(tree
, hf_catapult_dct2000_buffer_occupancy
, tvb
, offset
, length
, ENC_BIG_ENDIAN
);
820 case 0x49: /* PDU Size */
821 proto_tree_add_item(tree
, hf_catapult_dct2000_pdu_size
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
823 case 0x47: /* UEId type */
824 proto_tree_add_item(tree
, hf_catapult_dct2000_ueid_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
826 case 0x4e: /* Tx Priority */
827 proto_tree_add_item(tree
, hf_catapult_dct2000_tx_priority
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
829 case 0x4c: /* Last in seg set */
830 proto_tree_add_item(tree
, hf_catapult_dct2000_last_in_seg_set
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
832 case 0x43: /* Rx timing deviation */
833 proto_tree_add_item(tree
, hf_catapult_dct2000_rx_timing_deviation
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
835 case 0x46: /* Transport channel type */
836 proto_tree_add_item(tree
, hf_catapult_dct2000_transport_channel_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
838 case 0xc2: /* Number of padding bits */
839 proto_tree_add_item(tree
, hf_catapult_dct2000_no_padding_bits
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
851 /* Have we got enough info to call dissector */
852 if ((tag
== 0x41) && ueid_set
&& rbid_set
) {
853 attach_rlc_info(pinfo
, ueid
, rbid
, is_sent
, outhdr_values
,
854 outhdr_values_found
);
856 /* Set appropriate RLC dissector handle */
858 case 1: case 2: case 3: case 4: case 5:
859 case 6: case 7: case 8: case 9: case 10:
860 case 11: case 12: case 13: case 14: case 15:
862 /* TODO: can't really tell if these are control or transport...
863 maybe control with preferences (UAT?) between "rlc.ps_dtch" and "rlc.dcch" ? */
864 rlc_umts_handle
= find_dissector("rlc.dch_unknown");
867 rlc_umts_handle
= find_dissector("rlc.ccch");
870 rlc_umts_handle
= find_dissector("rlc.ctch");
878 /* Call UMTS RLC dissector */
879 if (rlc_umts_handle
!= 0) {
880 rlc_tvb
= tvb_new_subset_remaining(tvb
, offset
);
881 call_dissector_only(rlc_umts_handle
, rlc_tvb
, pinfo
, tree
, NULL
);
886 static char* get_key(tvbuff_t
*tvb
, int offset
)
889 for (int n
=0; n
< 16; n
++) {
890 snprintf(&key
[n
*2], 33-(n
*2), "%02x", tvb_get_uint8(tvb
, offset
+n
));
896 /* Dissect an RRC LTE or NR frame by first parsing the header entries then passing
897 the data to the RRC dissector, according to direction and channel type. */
898 static void dissect_rrc_lte_nr(tvbuff_t
*tvb
, int offset
,
899 packet_info
*pinfo
, proto_tree
*tree
,
900 enum LTE_or_NR lte_or_nr
)
903 dissector_handle_t protocol_handle
= 0;
904 bool isUplink
= false;
905 LogicalChannelType logicalChannelType
;
907 uint8_t bcch_transport
= 0;
911 /* Top-level opcode */
912 opcode
= tvb_get_uint8(tvb
, offset
++);
914 case 0x00: /* Data_Req_UE */
915 case 0x05: /* Data_Req_UE_SM */
916 case 0x04: /* Data_Ind_eNodeB */
920 case 0x02: /* Data_Req_eNodeB */
921 case 0x03: /* Data_Ind_UE */
922 case 0x07: /* Data_Ind_UE_SM */
927 /* Unexpected opcode tag! */
932 offset
+= skipASNLength(tvb_get_uint8(tvb
, offset
));
935 tag
= tvb_get_uint8(tvb
, offset
++);
937 case 0x12: /* UE_Id_LCId */
939 /* Dedicated channel info */
944 logicalChannelType
= Channel_DCCH
;
947 proto_tree_add_item_ret_uint(tree
, hf_catapult_dct2000_ueid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
, &ueid
);
950 /* Get tag of channel type */
951 tag
= tvb_get_uint8(tvb
, offset
++);
956 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " SRB:%u",
957 tvb_get_uint8(tvb
, offset
));
958 proto_tree_add_item(tree
, hf_catapult_dct2000_srbid
,
959 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
964 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " DRB:%u",
965 tvb_get_uint8(tvb
, offset
));
966 proto_tree_add_item(tree
, hf_catapult_dct2000_drbid
,
967 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
972 /* Unexpected channel type */
979 case 0x1a: /* Cell_LCId */
981 /* Common channel info */
987 proto_tree_add_item(tree
, hf_catapult_dct2000_cellid
,
988 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
989 cell_id
= tvb_get_ntohs(tvb
, offset
);
992 /* Logical channel type */
993 proto_tree_add_item(tree
, hf_catapult_dct2000_rlc_channel_type
,
994 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
995 logicalChannelType
= (LogicalChannelType
)tvb_get_uint8(tvb
, offset
);
998 /* Won't be seen if RRC decoder is called... */
999 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " cell-id=%u %s",
1001 val_to_str_const(logicalChannelType
, rlc_logical_channel_vals
,
1002 "UNKNOWN-CHANNEL"));
1005 switch (logicalChannelType
) {
1010 /* Transport channel type */
1011 bcch_transport
= tvb_get_uint8(tvb
, offset
);
1012 proto_tree_add_item(tree
, hf_catapult_dct2000_bcch_transport
,
1013 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1022 proto_tree_add_item(tree
, hf_catapult_dct2000_ueid
,
1023 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1033 /* Unexpected tag */
1037 /* Optional Carrier Id */
1038 if (tvb_get_uint8(tvb
, offset
)==0x1e) {
1039 offset
+= 2; /* tag + len of 1 */
1040 proto_tree_add_item(tree
, hf_catapult_dct2000_carrier_id
,
1041 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1045 /* Optional Carrier Type */
1046 if (tvb_get_uint8(tvb
, offset
)==0x20) {
1048 proto_tree_add_item(tree
, hf_catapult_dct2000_carrier_type
,
1049 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1053 /* Optional Cell Group */
1054 if (tvb_get_uint8(tvb
, offset
)==0x22) {
1056 proto_tree_add_item(tree
, hf_catapult_dct2000_cell_group
,
1057 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1061 if (opcode
== 0x07) {
1062 /* Data_Ind_UE_SM - 1 byte MAC */
1065 else if (opcode
== 0x05) {
1066 /* Data_Req_UE_SM - SecurityMode Params */
1067 /* N.B. DRB keys do not get configured here.. */
1069 uint8_t len
= tvb_get_uint8(tvb
, offset
++); /* length */
1071 /* Uplink Sec Mode */
1073 proto_tree
*sc_tree
;
1074 sc_ti
= proto_tree_add_item(tree
, hf_catapult_dct2000_security_mode_params
, tvb
, offset
, len
, ENC_NA
);
1075 sc_tree
= proto_item_add_subtree(sc_ti
, ett_catapult_dct2000_security_mode_params
);
1077 uint32_t uplink_sec_mode
;
1078 proto_tree_add_item_ret_uint(sc_tree
, hf_catapult_dct2000_uplink_sec_mode
,
1079 tvb
, offset
++, 1, ENC_BIG_ENDIAN
, &uplink_sec_mode
);
1081 /* Downlink Sec Mode */
1082 uint32_t downlink_sec_mode
;
1083 proto_tree_add_item_ret_uint(sc_tree
, hf_catapult_dct2000_downlink_sec_mode
,
1084 tvb
, offset
++, 1, ENC_BIG_ENDIAN
, &downlink_sec_mode
);
1087 offset
++; /* tag Should be 0x21 */
1090 tag
= tvb_get_uint8(tvb
, offset
++);
1094 proto_tree_add_item(sc_tree
, hf_catapult_dct2000_cell_group
,
1095 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1098 /* Optional cryptParams */
1100 uint32_t cipher_algorithm
;
1102 len
= tvb_get_uint8(tvb
, offset
++);
1104 /* Cipher algorithm (required) */
1105 offset
+= 2; /* Skip tag and length */
1106 proto_tree_add_item_ret_uint(sc_tree
, hf_catapult_dct2000_ciphering_algorithm
,
1107 tvb
, offset
++, 1, ENC_BIG_ENDIAN
, &cipher_algorithm
);
1109 /* Ciphering key (optional) */
1111 /* Skip tag and length */
1113 proto_tree_add_item(sc_tree
, hf_catapult_dct2000_ciphering_key
,
1114 tvb
, offset
, 16, ENC_NA
);
1115 char *key
= get_key(tvb
, offset
);
1117 if (!PINFO_FD_VISITED(pinfo
)) {
1118 if (lte_or_nr
== NR
) {
1119 set_pdcp_nr_rrc_ciphering_key(ueid
, key
, pinfo
->num
);
1122 set_pdcp_lte_rrc_ciphering_key(ueid
, key
, pinfo
->num
);
1132 /* Now should be Auth params (required) */
1133 uint32_t integrity_algorithm
;
1137 len
= tvb_get_uint8(tvb
, offset
++);
1139 /* Integrity algorithm (required) */
1140 offset
+= 2; /* Skip tag and length */
1141 proto_tree_add_item_ret_uint(sc_tree
, hf_catapult_dct2000_integrity_algorithm
,
1142 tvb
, offset
++, 1, ENC_BIG_ENDIAN
, &integrity_algorithm
);
1144 /* Integrity key (optional */
1146 /* Skip tag and length */
1148 proto_tree_add_item(sc_tree
, hf_catapult_dct2000_integrity_key
,
1149 tvb
, offset
, 16, ENC_NA
);
1150 char *key
= get_key(tvb
, offset
);
1152 if (!PINFO_FD_VISITED(pinfo
)) {
1153 if (lte_or_nr
== NR
) {
1154 set_pdcp_nr_rrc_integrity_key(ueid
, key
, pinfo
->num
);
1157 set_pdcp_lte_rrc_integrity_key(ueid
, key
, pinfo
->num
);
1165 /* Optional data tag may follow */
1166 if (!tvb_reported_length_remaining(tvb
, offset
)) {
1169 tag
= tvb_get_uint8(tvb
, offset
++);
1175 offset
+= skipASNLength(tvb_get_uint8(tvb
, offset
));
1177 /* Look up dissector handle corresponding to direction and channel type */
1180 /* Uplink channel types */
1181 switch (logicalChannelType
) {
1183 if (lte_or_nr
== LTE
) {
1184 protocol_handle
= find_dissector("lte_rrc.ul_dcch");
1187 protocol_handle
= find_dissector("nr-rrc.ul.dcch");
1191 if (lte_or_nr
== LTE
) {
1192 protocol_handle
= find_dissector("lte_rrc.ul_ccch");
1195 if (tvb_captured_length_remaining(tvb
, offset
) == 6) {
1196 protocol_handle
= find_dissector("nr-rrc.ul.ccch");
1199 /* Should be 8 bytes.. */
1200 protocol_handle
= find_dissector("nr-rrc.ul.ccch1");
1206 /* Unknown Uplink channel type */
1211 /* Downlink channel types */
1212 switch (logicalChannelType
) {
1214 if (lte_or_nr
== LTE
) {
1215 protocol_handle
= find_dissector("lte_rrc.dl_dcch");
1218 protocol_handle
= find_dissector("nr-rrc.dl.dcch");
1222 if (lte_or_nr
== LTE
) {
1223 protocol_handle
= find_dissector("lte_rrc.dl_ccch");
1226 protocol_handle
= find_dissector("nr-rrc.dl.ccch");
1230 if (lte_or_nr
== LTE
) {
1231 protocol_handle
= find_dissector("lte_rrc.pcch");
1234 protocol_handle
= find_dissector("nr-rrc.pcch");
1238 if (bcch_transport
== 1) {
1239 if (lte_or_nr
== LTE
) {
1240 protocol_handle
= find_dissector("lte_rrc.bcch_bch");
1243 protocol_handle
= find_dissector("nr-rrc.bcch.bch");
1247 if (lte_or_nr
== LTE
) {
1248 protocol_handle
= find_dissector("lte_rrc.bcch_dl_sch");
1251 protocol_handle
= find_dissector("nr-rrc.bcch.dl.sch");
1257 /* Unknown Downlink channel type */
1262 /* Send to RRC dissector, if got here, have sub-dissector and some data left */
1263 if ((protocol_handle
!= NULL
) && (tvb_reported_length_remaining(tvb
, offset
) > 0)) {
1265 /* Set MAC-NR info for this PDU. Needed so that UEId can be found for this frame,
1266 * as used by MAC/RLC/PDCP configuration from RRC dissector */
1268 struct mac_nr_info
*p_mac_nr_info
;
1269 p_mac_nr_info
= wmem_new0(wmem_file_scope(), struct mac_nr_info
);
1270 p_mac_nr_info
->ueid
= ueid
;
1271 p_mac_nr_info
->direction
= (isUplink
) ? DIRECTION_UPLINK
: DIRECTION_DOWNLINK
;
1272 /* Store info in packet */
1273 set_mac_nr_proto_data(pinfo
, p_mac_nr_info
);
1276 rrc_tvb
= tvb_new_subset_remaining(tvb
, offset
);
1277 call_dissector_only(protocol_handle
, rrc_tvb
, pinfo
, tree
, NULL
);
1282 /* Dissect an CCPRI LTE frame by first parsing the header entries then passing
1283 the data to the CPRI C&M dissector
1285 XXX - is this the Common Public Radio Interface? If so, what's the extra
1286 "C" in "CCPRI"? And why is the LAPB dissector involved here? The CPRI
1287 spec just speaks of HDLC; LAPB is certainly a HDLC-based protocol, but
1288 that doesn't mean every HDLC-based protocol is LAPB. */
1289 static void dissect_ccpri_lte(tvbuff_t
*tvb
, int offset
,
1290 packet_info
*pinfo
, proto_tree
*tree
)
1294 tvbuff_t
*ccpri_tvb
;
1295 dissector_handle_t protocol_handle
= 0;
1298 /* Top-level opcode */
1299 proto_tree_add_item(tree
, hf_catapult_dct2000_lte_ccpri_opcode
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1300 opcode
= tvb_get_uint8(tvb
, offset
++);
1302 /* Skip 2-byte length field */
1306 proto_tree_add_item(tree
, hf_catapult_dct2000_cellid
,
1307 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1310 /* Status (ind only) */
1313 uint8_t status
= tvb_get_uint8(tvb
, offset
);
1314 ti
= proto_tree_add_item(tree
, hf_catapult_dct2000_lte_ccpri_status
,
1315 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1319 expert_add_info(pinfo
, ti
, &ei_catapult_dct2000_lte_ccpri_status_error
);
1325 proto_tree_add_item(tree
, hf_catapult_dct2000_lte_ccpri_channel
,
1326 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1329 /* Data tag must follow */
1330 tag
= tvb_get_uint8(tvb
, offset
++);
1336 length
= tvb_get_ntohs(tvb
, offset
);
1339 /* Send remainder to lapb dissector; I assume "CPRI" is the Common
1340 Public Radio Interface, in which case the "lapb" dissector is
1341 being used to dissect the HDLC used by CPRI, and in which case
1342 we should really have a CPRI dissector that dissects its HDLC
1343 and then hands off to a CPRI C&M dissector. */
1344 protocol_handle
= find_dissector("lapb");
1345 if ((protocol_handle
!= NULL
) && (tvb_reported_length_remaining(tvb
, offset
) > 0)) {
1346 ccpri_tvb
= tvb_new_subset_length(tvb
, offset
, length
);
1347 call_dissector_only(protocol_handle
, ccpri_tvb
, pinfo
, tree
, NULL
);
1354 /* Dissect a PDCP LTE frame by first parsing the RLCPrim header then passing
1355 the data to the PDCP LTE dissector */
1356 static void dissect_pdcp_lte(tvbuff_t
*tvb
, int offset
,
1357 packet_info
*pinfo
, proto_tree
*tree
)
1361 struct pdcp_lte_info
*p_pdcp_lte_info
;
1362 tvbuff_t
*pdcp_lte_tvb
;
1366 /* Look this up so can update channel info */
1367 p_pdcp_lte_info
= (struct pdcp_lte_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_pdcp_lte
, 0);
1368 if (p_pdcp_lte_info
== NULL
) {
1369 /* This really should be set...can't dissect anything without it */
1373 /* Top-level opcode */
1374 opcode
= tvb_get_uint8(tvb
, offset
);
1376 proto_tree_add_item(tree
, hf_catapult_dct2000_rlc_op
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1380 col_set_str(pinfo
->cinfo
, COL_INFO
, val_to_str_const(opcode
, rlc_op_vals
, "Unknown"));
1382 /* Assume UE side, so REQ is UL, IND is DL */
1384 case RLC_AM_DATA_REQ
:
1385 case RLC_UM_DATA_REQ
:
1386 case RLC_TR_DATA_REQ
:
1387 p_pdcp_lte_info
->direction
= DIRECTION_UPLINK
;
1391 p_pdcp_lte_info
->direction
= DIRECTION_DOWNLINK
;
1396 case RLC_AM_DATA_REQ
:
1397 case RLC_AM_DATA_IND
:
1398 case RLC_UM_DATA_REQ
:
1399 case RLC_UM_DATA_IND
:
1400 case RLC_TR_DATA_REQ
:
1401 case RLC_TR_DATA_IND
:
1404 tag
= tvb_get_uint8(tvb
, offset
++);
1406 case 0x10: /* UE_Id_LCId */
1408 /* Dedicated channel info */
1410 /* Length will fit in one byte here */
1413 p_pdcp_lte_info
->channelType
= Channel_DCCH
;
1416 ueid
= tvb_get_ntohs(tvb
, offset
);
1417 proto_tree_add_item(tree
, hf_catapult_dct2000_ueid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1418 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
1420 p_pdcp_lte_info
->ueid
= ueid
;
1423 /* Get tag of channel type */
1424 tag
= tvb_get_uint8(tvb
, offset
++);
1429 channelId
= tvb_get_uint8(tvb
, offset
);
1430 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " SRB:%u",
1432 proto_tree_add_item(tree
, hf_catapult_dct2000_srbid
,
1433 tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
1434 p_pdcp_lte_info
->channelId
= channelId
;
1438 channelId
= tvb_get_uint8(tvb
, offset
);
1439 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " DRB:%u",
1441 proto_tree_add_item(tree
, hf_catapult_dct2000_drbid
,
1442 tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
1443 p_pdcp_lte_info
->channelId
= channelId
;
1447 /* Unexpected channel type */
1452 case 0x1a: /* Cell_LCId */
1454 /* Common channel info */
1460 proto_tree_add_item(tree
, hf_catapult_dct2000_cellid
,
1461 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1464 /* Logical channel type */
1465 proto_tree_add_item(tree
, hf_catapult_dct2000_rlc_channel_type
,
1466 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1467 p_pdcp_lte_info
->channelType
= (LogicalChannelType
)tvb_get_uint8(tvb
, offset
++);
1468 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s",
1469 val_to_str_const(p_pdcp_lte_info
->channelType
, rlc_logical_channel_vals
,
1470 "UNKNOWN-CHANNEL"));
1472 switch (p_pdcp_lte_info
->channelType
) {
1477 /* Transport channel type */
1478 p_pdcp_lte_info
->BCCHTransport
= (BCCHTransportType
)tvb_get_uint8(tvb
, offset
);
1479 proto_tree_add_item(tree
, hf_catapult_dct2000_bcch_transport
,
1480 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1489 proto_tree_add_item(tree
, hf_catapult_dct2000_ueid
,
1490 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1491 ueid
= tvb_get_ntohs(tvb
, offset
);
1494 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " UEId=%u", ueid
);
1503 /* Unexpected tag */
1507 /* Other optional fields may follow */
1508 tag
= tvb_get_uint8(tvb
, offset
++);
1509 while ((tag
!= 0x41) && (tvb_reported_length_remaining(tvb
, offset
) > 2)) {
1514 proto_tree_add_item(tree
, hf_catapult_dct2000_rlc_mui
,
1515 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1518 /* CNF follows MUI in AM */
1519 if ((opcode
== RLC_AM_DATA_REQ
) || (opcode
== RLC_AM_DATA_IND
)) {
1520 proto_tree_add_item(tree
, hf_catapult_dct2000_rlc_cnf
,
1521 tvb
, offset
, 1, ENC_NA
);
1525 else if (tag
== 0x45) {
1528 proto_tree_add_item(tree
, hf_catapult_dct2000_rlc_discard_req
,
1529 tvb
, offset
, 1, ENC_NA
);
1533 tag
= tvb_get_uint8(tvb
, offset
++);
1537 /********************************/
1538 /* Should be at data tag now */
1540 /* Call PDCP LTE dissector */
1541 pdcp_lte_tvb
= tvb_new_subset_remaining(tvb
, offset
);
1542 call_dissector_only(pdcp_lte_handle
, pdcp_lte_tvb
, pinfo
, tree
, NULL
);
1555 /* Look up dissector by protocol name. Fix up known name mis-matches.
1556 This includes exact matches and prefixes (e.g. "diameter_rx" -> "diameter") */
1557 static dissector_handle_t
look_for_dissector(const char *protocol_name
)
1559 if (strncmp(protocol_name
, "diameter", strlen("diameter")) == 0) {
1560 return find_dissector("diameter");
1563 if (strncmp(protocol_name
, "gtpv2_r", 7) == 0) {
1564 return find_dissector("gtpv2");
1567 if (strncmp(protocol_name
, "s1ap", 4) == 0) {
1568 return find_dissector("s1ap");
1571 if (strncmp(protocol_name
, "x2ap_r", 6) == 0) {
1572 return find_dissector("x2ap");
1575 if (strncmp(protocol_name
, "xnap_r1", 7) == 0) {
1576 return find_dissector("xnap");
1579 if (strncmp(protocol_name
, "ngap_r1", 7) == 0) {
1580 return find_dissector("ngap");
1583 /* Only check really old names to convert if preference is checked */
1584 else if (catapult_dct2000_dissect_old_protocol_names
) {
1585 /* Use known aliases and protocol name prefixes */
1586 if (strcmp(protocol_name
, "tbcp") == 0) {
1587 return find_dissector("rtcp");
1590 if ((strcmp(protocol_name
, "xcap_caps") == 0) ||
1591 (strcmp(protocol_name
, "soap") == 0) ||
1592 (strcmp(protocol_name
, "mm1") == 0) ||
1593 (strcmp(protocol_name
, "mm3") == 0) ||
1594 (strcmp(protocol_name
, "mm7") == 0)) {
1596 return find_dissector("http");
1599 if ((strncmp(protocol_name
, "fp_r", 4) == 0) ||
1600 (strcmp(protocol_name
, "fpiur_r5") == 0)) {
1602 return find_dissector("fp");
1605 if (strncmp(protocol_name
, "iuup_rtp_r", strlen("iuup_rtp_r")) == 0) {
1606 return find_dissector("rtp");
1609 if (strcmp(protocol_name
, "sipt") == 0) {
1610 return find_dissector("sip");
1613 if (strncmp(protocol_name
, "nbap_sctp", strlen("nbap_sctp")) == 0) {
1614 return find_dissector("nbap");
1617 if (strcmp(protocol_name
, "dhcpv4") == 0) {
1618 return find_dissector("dhcp");
1621 if (strcmp(protocol_name
, "wimax") == 0) {
1622 return find_dissector("wimaxasncp");
1625 if (strncmp(protocol_name
, "sabp", strlen("sabp")) == 0) {
1626 return find_dissector("sabp");
1629 if (strcmp(protocol_name
, "wtp") == 0) {
1630 return find_dissector("wtp-udp");
1633 if (strncmp(protocol_name
, "gtp", strlen("gtp")) == 0) {
1634 return find_dissector("gtp");
1638 /* Try for an exact match */
1639 return find_dissector(protocol_name
);
1643 /* Populate outhdr_values array with numbers found in outhdr_string */
1644 static unsigned parse_outhdr_string(const unsigned char *outhdr_string
, int outhdr_string_len
, unsigned *outhdr_values
)
1647 int outhdr_values_found
;
1649 /* Populate values array */
1650 for (outhdr_values_found
=0; outhdr_values_found
< MAX_OUTHDR_VALUES
; ) {
1652 unsigned digit_array
[MAX_OUTHDR_VALUES
];
1653 unsigned number_digits
= 0;
1655 unsigned number
= 0;
1656 unsigned multiplier
= 1;
1660 for ( ; (n
< outhdr_string_len
) && (number_digits
< MAX_OUTHDR_VALUES
); n
++) {
1661 if (!g_ascii_isdigit(outhdr_string
[n
])) {
1665 digit_array
[number_digits
++] = outhdr_string
[n
] - '0';
1669 if (number_digits
== 0) {
1670 /* No more numbers left */
1674 /* Convert digits into value (much faster than format_text() + atoi()) */
1675 for (d
=number_digits
; d
> 0; d
--) {
1676 number
+= ((digit_array
[d
-1]) * multiplier
);
1679 outhdr_values
[outhdr_values_found
++] = number
;
1684 return outhdr_values_found
;
1689 /* Fill in an FP packet info struct and attach it to the packet for the FP
1691 static void attach_fp_info(packet_info
*pinfo
, bool received
,
1692 const char *protocol_name
, int variant
,
1693 unsigned *outhdr_values
, unsigned outhdr_values_found
)
1697 unsigned tf_start
, num_chans_start
;
1699 int calculated_variant
;
1701 /* Only need to set info once per session. */
1702 struct fp_info
*p_fp_info
= (struct fp_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0);
1703 if (p_fp_info
!= NULL
) {
1707 /* Allocate struct */
1708 p_fp_info
= wmem_new0(wmem_file_scope(), struct fp_info
);
1710 /* Check that the number of outhdr values looks sensible */
1711 if (((strcmp(protocol_name
, "fpiur_r5") == 0) && (outhdr_values_found
!= 2)) ||
1712 (outhdr_values_found
< 5)) {
1717 /* 3gpp release (99, 4, 5, 6, 7) */
1718 if (strcmp(protocol_name
, "fp") == 0) {
1719 p_fp_info
->release
= 99;
1721 else if (strcmp(protocol_name
, "fp_r4") == 0) {
1722 p_fp_info
->release
= 4;
1724 else if (strcmp(protocol_name
, "fp_r5") == 0) {
1725 p_fp_info
->release
= 5;
1727 else if (strcmp(protocol_name
, "fp_r6") == 0) {
1728 p_fp_info
->release
= 6;
1730 else if (strcmp(protocol_name
, "fp_r7") == 0) {
1731 p_fp_info
->release
= 7;
1733 else if (strcmp(protocol_name
, "fp_r8") == 0) {
1734 p_fp_info
->release
= 8;
1736 else if (strcmp(protocol_name
, "fpiur_r5") == 0) {
1737 p_fp_info
->release
= 5;
1740 /* Really shouldn't get here */
1741 DISSECTOR_ASSERT_NOT_REACHED();
1745 /* Release date is derived from variant number */
1746 /* Only R6 sub-versions currently influence format within a release */
1747 switch (p_fp_info
->release
) {
1749 if (variant
< 256) {
1750 calculated_variant
= variant
;
1753 calculated_variant
= variant
/ 256;
1756 switch (calculated_variant
) {
1758 p_fp_info
->release_year
= 2005;
1759 p_fp_info
->release_month
= 6;
1762 p_fp_info
->release_year
= 2005;
1763 p_fp_info
->release_month
= 9;
1767 p_fp_info
->release_year
= 2006;
1768 p_fp_info
->release_month
= 3;
1773 p_fp_info
->release_year
= 2008;
1774 p_fp_info
->release_month
= 3;
1778 p_fp_info
->release_year
= 2010;
1779 p_fp_info
->release_month
= 6;
1784 p_fp_info
->release_year
= 0;
1785 p_fp_info
->release_month
= 0;
1790 p_fp_info
->channel
= outhdr_values
[i
++];
1791 /* Sad hack until this value is filled in properly */
1792 if (p_fp_info
->channel
== 0) {
1793 p_fp_info
->channel
= CHANNEL_DCH
;
1796 /* Derive direction from node type/side */
1797 node_type
= outhdr_values
[i
++];
1798 p_fp_info
->is_uplink
= (( received
&& (node_type
== 2)) ||
1799 (!received
&& (node_type
== 1)));
1801 /* Division type introduced for R7 */
1802 if ((p_fp_info
->release
== 7) ||
1803 (p_fp_info
->release
== 8)) {
1804 p_fp_info
->division
= (enum division_type
)outhdr_values
[i
++];
1807 /* HS-DSCH config */
1808 if (p_fp_info
->channel
== CHANNEL_HSDSCH
) {
1809 if ((p_fp_info
->release
== 7) ||
1810 (p_fp_info
->release
== 8)) {
1811 /* Entity (MAC-hs or MAC-ehs) used */
1812 if (outhdr_values
[i
++]) {
1813 p_fp_info
->hsdsch_entity
= ehs
;
1817 /* This is the pre-R7 default */
1818 p_fp_info
->hsdsch_entity
= hs
;
1823 /* IUR only uses the above... */
1824 if (strcmp(protocol_name
, "fpiur_r5") == 0) {
1825 /* Store info in packet */
1826 p_fp_info
->iface_type
= IuR_Interface
;
1827 p_add_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0, p_fp_info
);
1831 /* DCH CRC present... */
1832 p_fp_info
->dch_crc_present
= outhdr_values
[i
++];
1834 /* ... but don't trust for edch */
1835 if (p_fp_info
->channel
== CHANNEL_EDCH
) {
1836 p_fp_info
->dch_crc_present
= 2; /* unknown */
1839 /* How many paging indications (if PCH data) */
1840 p_fp_info
->paging_indications
= outhdr_values
[i
++];
1842 /* Number of channels (for coordinated channels) */
1843 p_fp_info
->num_chans
= outhdr_values
[i
++];
1844 if (p_fp_info
->num_chans
> MAX_FP_CHANS
) {
1845 p_fp_info
->num_chans
= MAX_FP_CHANS
;
1848 /* EDCH-Common is always T2 */
1849 if (p_fp_info
->channel
== CHANNEL_EDCH_COMMON
) {
1850 p_fp_info
->edch_type
= 1;
1853 if (p_fp_info
->channel
!= CHANNEL_EDCH
) {
1854 /* TF size for each channel */
1856 for (chan
=0; chan
< p_fp_info
->num_chans
; chan
++) {
1857 if (outhdr_values_found
> tf_start
+chan
) {
1858 p_fp_info
->chan_tf_size
[chan
] = outhdr_values
[tf_start
+chan
];
1860 p_fp_info
->chan_tf_size
[chan
] = 0;
1864 /* Number of TBs for each channel */
1865 num_chans_start
= tf_start
+ p_fp_info
->num_chans
;
1866 for (chan
=0; chan
< p_fp_info
->num_chans
; chan
++) {
1867 if (outhdr_values_found
> num_chans_start
+chan
) {
1868 p_fp_info
->chan_num_tbs
[chan
] = outhdr_values
[num_chans_start
+chan
];
1870 p_fp_info
->chan_num_tbs
[chan
] = 0;
1878 p_fp_info
->no_ddi_entries
= outhdr_values
[i
++];
1881 for (n
=0; n
< p_fp_info
->no_ddi_entries
; n
++) {
1882 if (outhdr_values_found
> i
) {
1883 p_fp_info
->edch_ddi
[n
] = outhdr_values
[i
++];
1885 p_fp_info
->edch_ddi
[n
] = 0;
1889 /* Corresponding MAC-d sizes */
1890 for (n
=0; n
< p_fp_info
->no_ddi_entries
; n
++) {
1891 if (outhdr_values_found
> i
) {
1892 p_fp_info
->edch_macd_pdu_size
[n
] = outhdr_values
[i
++];
1894 p_fp_info
->edch_macd_pdu_size
[n
] = 0;
1898 if (strcmp(protocol_name
, "fp_r8") == 0) {
1899 if (outhdr_values_found
> i
) {
1900 p_fp_info
->edch_type
= outhdr_values
[i
];
1902 p_fp_info
->edch_type
= 0;
1906 p_fp_info
->edch_type
= 0;
1910 /* Interface must be IuB */
1911 p_fp_info
->iface_type
= IuB_Interface
;
1913 /* Store info in packet */
1914 p_add_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0, p_fp_info
);
1918 /* Fill in an RLC packet info struct and attach it to the packet for the RLC
1920 static void attach_rlc_info(packet_info
*pinfo
, uint32_t urnti
, uint8_t rbid
,
1921 bool is_sent
, unsigned *outhdr_values
,
1922 unsigned outhdr_values_found
)
1924 /* Only need to set info once per session. */
1925 struct fp_info
*p_fp_info
;
1926 struct rlc_info
*p_rlc_info
= (struct rlc_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_umts_rlc
, 0);
1928 if (p_rlc_info
!= NULL
) {
1932 /* Check that the number of outhdr values looks correct */
1933 if (outhdr_values_found
!= 2) {
1937 /* Allocate structs */
1938 p_rlc_info
= wmem_new(wmem_file_scope(), struct rlc_info
);
1939 p_fp_info
= wmem_new0(wmem_file_scope(), struct fp_info
);
1941 /* Fill in struct fields for first (only) PDU in this frame */
1943 /* Urnti. Just use UEId */
1944 p_rlc_info
->ueid
[0] = urnti
;
1946 /* ciphered (off by default) */
1947 p_rlc_info
->ciphered
[0] = false;
1949 /* deciphered (off by default) */
1950 p_rlc_info
->deciphered
[0] = false;
1953 switch (outhdr_values
[1]) {
1955 p_rlc_info
->mode
[0] = RLC_TM
;
1958 p_rlc_info
->mode
[0] = RLC_UM
;
1961 p_rlc_info
->mode
[0] = RLC_AM
;
1964 p_rlc_info
->mode
[0] = RLC_UM
;
1965 p_rlc_info
->ciphered
[0] = true;
1968 p_rlc_info
->mode
[0] = RLC_AM
;
1969 p_rlc_info
->ciphered
[0] = true;
1975 /* rbid. TODO: does this need conversion? */
1976 p_rlc_info
->rbid
[0] = rbid
;
1979 p_rlc_info
->li_size
[0] = (enum rlc_li_size
)outhdr_values
[0];
1981 /* Store info in packet */
1982 p_add_proto_data(wmem_file_scope(), pinfo
, proto_umts_rlc
, 0, p_rlc_info
);
1984 /* Also store minimal FP info consulted by RLC dissector
1985 TODO: Don't really know direction, but use S/R flag to make
1986 logs in same context consistent. Will be correct for NodeB logs,
1987 but RLC dissector seems to not use anyway... */
1988 p_fp_info
->is_uplink
= is_sent
;
1989 p_fp_info
->cur_tb
= 0; /* Always the first/only one */
1990 p_add_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0, p_fp_info
);
1994 /* Fill in a MAC LTE packet info struct and attach it to the packet for that
1996 static void attach_mac_lte_info(packet_info
*pinfo
, unsigned *outhdr_values
, unsigned outhdr_values_found
)
1998 struct mac_lte_info
*p_mac_lte_info
;
2001 /* Only need to set info once per session. */
2002 p_mac_lte_info
= get_mac_lte_proto_data(pinfo
);
2003 if (p_mac_lte_info
!= NULL
) {
2007 /* Allocate & zero struct */
2008 p_mac_lte_info
= wmem_new0(wmem_file_scope(), struct mac_lte_info
);
2010 /* Populate the struct from outhdr values */
2011 p_mac_lte_info
->crcStatusValid
= false; /* not set yet */
2013 p_mac_lte_info
->radioType
= outhdr_values
[i
++] + 1; // 1
2014 p_mac_lte_info
->rntiType
= outhdr_values
[i
++]; // 2
2015 p_mac_lte_info
->direction
= outhdr_values
[i
++]; // 3
2016 /* Set these extra PHY present flags to false by default */
2017 if (p_mac_lte_info
->direction
== DIRECTION_UPLINK
) {
2018 p_mac_lte_info
->detailed_phy_info
.ul_info
.present
= false;
2021 p_mac_lte_info
->detailed_phy_info
.dl_info
.present
= false;
2024 p_mac_lte_info
->sfnSfInfoPresent
= true;
2025 p_mac_lte_info
->subframeNumber
= outhdr_values
[i
++]; // 4
2026 p_mac_lte_info
->isPredefinedData
= outhdr_values
[i
++]; // 5
2027 p_mac_lte_info
->rnti
= outhdr_values
[i
++]; // 6
2028 p_mac_lte_info
->ueid
= outhdr_values
[i
++]; // 7
2029 p_mac_lte_info
->length
= outhdr_values
[i
++]; // 8
2030 if (outhdr_values_found
> 8) {
2031 p_mac_lte_info
->reTxCount
= outhdr_values
[i
++]; // 9
2033 /* TODO: delete if won't see this special case anymore? */
2034 if (outhdr_values_found
== 10) {
2035 /* CRC only valid for Downlink */
2036 if (p_mac_lte_info
->direction
== DIRECTION_DOWNLINK
) {
2037 p_mac_lte_info
->crcStatusValid
= true;
2038 p_mac_lte_info
->crcStatus
= (mac_lte_crc_status
)outhdr_values
[i
++]; // 10
2041 i
++; // 10 (ignoring for UL)
2045 p_mac_lte_info
->dl_retx
= dl_retx_unknown
;
2047 if (outhdr_values_found
> 10) {
2048 /* Extra PHY parameters */
2049 if (p_mac_lte_info
->direction
== DIRECTION_DOWNLINK
) {
2050 p_mac_lte_info
->detailed_phy_info
.dl_info
.present
= outhdr_values
[i
++]; // 10
2051 p_mac_lte_info
->detailed_phy_info
.dl_info
.dci_format
= outhdr_values
[i
++]; // 11
2052 p_mac_lte_info
->detailed_phy_info
.dl_info
.resource_allocation_type
= outhdr_values
[i
++]; // 12
2053 p_mac_lte_info
->detailed_phy_info
.dl_info
.aggregation_level
= outhdr_values
[i
++]; // 13
2054 p_mac_lte_info
->detailed_phy_info
.dl_info
.mcs_index
= outhdr_values
[i
++]; // 14
2055 p_mac_lte_info
->detailed_phy_info
.dl_info
.redundancy_version_index
= outhdr_values
[i
++]; // 15
2056 p_mac_lte_info
->dl_retx
= (outhdr_values
[i
++]) ? dl_retx_yes
: dl_retx_no
; // 16
2058 p_mac_lte_info
->detailed_phy_info
.dl_info
.resource_block_length
= outhdr_values
[i
++]; // 17
2059 p_mac_lte_info
->crcStatusValid
= true; // 18
2060 p_mac_lte_info
->crcStatus
= (mac_lte_crc_status
)outhdr_values
[i
++];
2061 if (outhdr_values_found
> 18) {
2062 p_mac_lte_info
->detailed_phy_info
.dl_info
.harq_id
= outhdr_values
[i
++]; // 19
2063 p_mac_lte_info
->detailed_phy_info
.dl_info
.ndi
= outhdr_values
[i
++]; // 20
2065 if (outhdr_values_found
> 20) {
2066 p_mac_lte_info
->detailed_phy_info
.dl_info
.transport_block
= outhdr_values
[i
++]; // 21
2071 p_mac_lte_info
->detailed_phy_info
.ul_info
.present
= outhdr_values
[i
++]; // 10
2072 p_mac_lte_info
->detailed_phy_info
.ul_info
.modulation_type
= outhdr_values
[i
++]; // 11
2073 p_mac_lte_info
->detailed_phy_info
.ul_info
.tbs_index
= outhdr_values
[i
++]; // 12
2074 p_mac_lte_info
->detailed_phy_info
.ul_info
.resource_block_length
= outhdr_values
[i
++]; // 13
2075 p_mac_lte_info
->detailed_phy_info
.ul_info
.resource_block_start
= outhdr_values
[i
++]; // 14
2076 /* Skip retx flag */
2079 /* TODO: delete if won't see this special case anymore? */
2080 if (outhdr_values_found
== 16) {
2081 p_mac_lte_info
->subframeNumberOfGrantPresent
= true;
2082 p_mac_lte_info
->subframeNumberOfGrant
= outhdr_values
[i
++]; // 16
2084 if (outhdr_values_found
> 16) {
2085 p_mac_lte_info
->detailed_phy_info
.ul_info
.harq_id
= outhdr_values
[i
++]; // 16
2086 p_mac_lte_info
->detailed_phy_info
.ul_info
.ndi
= outhdr_values
[i
++]; // 17
2088 p_mac_lte_info
->subframeNumberOfGrantPresent
= true;
2089 p_mac_lte_info
->subframeNumberOfGrant
= outhdr_values
[i
++]; // 18
2094 /* System frame number */
2095 if (i
< outhdr_values_found
) {
2096 p_mac_lte_info
->sysframeNumber
= outhdr_values
[i
++];
2099 if ((p_mac_lte_info
->direction
== DIRECTION_UPLINK
) &&
2100 (i
< outhdr_values_found
)) {
2102 p_mac_lte_info
->isPHICHNACK
= outhdr_values
[i
++];
2105 if (p_mac_lte_info
->direction
== DIRECTION_UPLINK
) {
2106 /* R10 parameter not set yet */
2107 p_mac_lte_info
->isExtendedBSRSizes
= false;
2110 if (i
< outhdr_values_found
) {
2112 p_mac_lte_info
->carrierId
= (mac_lte_carrier_id
)outhdr_values
[i
++];
2115 /* Remaining fields not (yet?) supported in
2116 the mac-lte dissector. */
2117 if (i
++ < outhdr_values_found
) {
2118 /* Serving cell index */
2120 if (i
< outhdr_values_found
) {
2124 /* Store info in packet */
2125 set_mac_lte_proto_data(pinfo
, p_mac_lte_info
);
2129 /* Fill in a RLC LTE packet info struct and attach it to the packet for that
2131 static void attach_rlc_lte_info(packet_info
*pinfo
, unsigned *outhdr_values
,
2132 unsigned outhdr_values_found _U_
)
2134 struct rlc_lte_info
*p_rlc_lte_info
;
2137 /* Only need to set info once per session. */
2138 p_rlc_lte_info
= (rlc_lte_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_rlc_lte
, 0);
2139 if (p_rlc_lte_info
!= NULL
) {
2143 /* Allocate & zero struct */
2144 p_rlc_lte_info
= wmem_new0(wmem_file_scope(), rlc_lte_info
);
2146 p_rlc_lte_info
->rlcMode
= outhdr_values
[i
++];
2147 p_rlc_lte_info
->direction
= outhdr_values
[i
++];
2148 p_rlc_lte_info
->priority
= outhdr_values
[i
++];
2149 p_rlc_lte_info
->sequenceNumberLength
= outhdr_values
[i
++];
2150 p_rlc_lte_info
->channelId
= outhdr_values
[i
++];
2151 p_rlc_lte_info
->channelType
= outhdr_values
[i
++];
2152 p_rlc_lte_info
->ueid
= outhdr_values
[i
++];
2153 p_rlc_lte_info
->pduLength
= outhdr_values
[i
];
2155 /* Store info in packet */
2156 p_add_proto_data(wmem_file_scope(), pinfo
, proto_rlc_lte
, 0, p_rlc_lte_info
);
2159 /* Fill in a PDCP LTE packet info struct and attach it to the packet for the PDCP LTE
2161 static void attach_pdcp_lte_info(packet_info
*pinfo
, unsigned *outhdr_values
,
2162 unsigned outhdr_values_found _U_
)
2164 struct pdcp_lte_info
*p_pdcp_lte_info
;
2167 /* Only need to set info once per session. */
2168 p_pdcp_lte_info
= (pdcp_lte_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_pdcp_lte
, 0);
2169 if (p_pdcp_lte_info
!= NULL
) {
2173 /* Allocate & zero struct */
2174 p_pdcp_lte_info
= wmem_new0(wmem_file_scope(), pdcp_lte_info
);
2176 p_pdcp_lte_info
->no_header_pdu
= outhdr_values
[i
++];
2177 p_pdcp_lte_info
->plane
= (enum pdcp_plane
)outhdr_values
[i
++];
2178 if (p_pdcp_lte_info
->plane
!= USER_PLANE
) {
2179 p_pdcp_lte_info
->plane
= SIGNALING_PLANE
;
2181 p_pdcp_lte_info
->seqnum_length
= outhdr_values
[i
++];
2183 p_pdcp_lte_info
->rohc
.rohc_compression
= outhdr_values
[i
++];
2184 p_pdcp_lte_info
->rohc
.rohc_ip_version
= outhdr_values
[i
++];
2185 p_pdcp_lte_info
->rohc
.cid_inclusion_info
= outhdr_values
[i
++];
2186 p_pdcp_lte_info
->rohc
.large_cid_present
= outhdr_values
[i
++];
2187 p_pdcp_lte_info
->rohc
.mode
= (enum rohc_mode
)outhdr_values
[i
++];
2188 p_pdcp_lte_info
->rohc
.rnd
= outhdr_values
[i
++];
2189 p_pdcp_lte_info
->rohc
.udp_checksum_present
= outhdr_values
[i
++];
2190 p_pdcp_lte_info
->rohc
.profile
= outhdr_values
[i
];
2192 /* Remaining 2 (fixed) fields are ah_length and gre_checksum */
2194 /* Store info in packet */
2195 p_add_proto_data(wmem_file_scope(), pinfo
, proto_pdcp_lte
, 0, p_pdcp_lte_info
);
2199 /* Attempt to show tty (raw character messages) as text lines. */
2200 static void dissect_tty_lines(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
)
2203 proto_tree
*tty_tree
;
2207 /* Create tty tree. */
2208 ti
= proto_tree_add_item(tree
, hf_catapult_dct2000_tty
, tvb
, offset
, -1, ENC_NA
);
2209 tty_tree
= proto_item_add_subtree(ti
, ett_catapult_dct2000_tty
);
2211 /* Show the tty lines one at a time. */
2212 while (tvb_offset_exists(tvb
, offset
)) {
2213 /* Find the end of the line. */
2214 int linelen
= tvb_find_line_end_unquoted(tvb
, offset
, -1, &next_offset
);
2216 /* Extract & add the string. */
2217 char *string
= (char*)tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, linelen
, ENC_ASCII
);
2218 if (g_ascii_isprint(string
[0])) {
2219 /* If the first byte of the string is printable ASCII treat as string... */
2220 proto_tree_add_string_format(tty_tree
, hf_catapult_dct2000_tty_line
,
2226 /* Otherwise show as $hex */
2229 int tty_string_length
= tvb_reported_length_remaining(tvb
, offset
);
2230 int hex_string_length
= 1+(2*tty_string_length
)+1;
2231 hex_string
= (char *)wmem_alloc(pinfo
->pool
, hex_string_length
);
2233 idx
= snprintf(hex_string
, hex_string_length
, "$");
2235 /* Write hex out to new string */
2236 for (n
=0; n
< tty_string_length
; n
++) {
2237 idx
+= snprintf(hex_string
+idx
, 3, "%02x",
2238 tvb_get_uint8(tvb
, offset
+n
));
2240 string
= hex_string
;
2244 /* Show first line in info column */
2246 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "tty (%s", string
);
2247 proto_item_append_text(ti
, " (%s)", string
);
2250 /* Move onto next line. */
2251 offset
= next_offset
;
2254 /* Close off summary of tty message in info column */
2256 col_append_str(pinfo
->cinfo
, COL_INFO
, (lines
> 1) ? "...)" : ")");
2261 /* Scan the log comment looking for notable out-of-band MAC events that should
2262 be sent to the MAC dissector */
2263 static void check_for_oob_mac_lte_events(packet_info
*pinfo
, tvbuff_t
*tvb
, proto_tree
*tree
,
2266 unsigned number_of_ues
;
2267 unsigned ueids
[MAX_SRs
];
2268 unsigned rntis
[MAX_SRs
];
2270 unsigned rach_attempt_number
;
2272 mac_lte_oob_event oob_event
;
2273 struct mac_lte_info
*p_mac_lte_info
;
2276 /* Current strings of interest begin with ">> ", so if don't see, avoid sscanf() calls. */
2277 if (strncmp(string
, ">> ", 3) != 0) {
2281 /*********************************************/
2282 /* Look for strings matching formats */
2284 /* RACH Preamble request */
2285 if (sscanf(string
, ">> RACH Preamble Request [CarrierId=%u] [LTE UE = %u] [RAPID = %u] [Attempt = %u",
2286 &temp
, &ueids
[0], &rapid
, &rach_attempt_number
) == 4) {
2287 oob_event
= ltemac_send_preamble
;
2290 /* Scheduling Requests */
2291 else if (sscanf(string
, ">> Schedule Requests (%u) [CarrierId=%u][UE=%u][RNTI=%u]",
2292 &number_of_ues
, &temp
, &ueids
[0], &rntis
[0]) == 4) {
2293 const char *current_position
;
2295 /* Newer, multi-UE format */
2296 oob_event
= ltemac_send_sr
;
2298 /* Parse other ueid/rnti pairs */
2299 number_of_ues
= MIN(number_of_ues
, MAX_SRs
);
2300 if (number_of_ues
> 1) {
2301 current_position
= string
;
2303 for (n
=1; n
< number_of_ues
; n
++) {
2305 /* Find the start of the next entry */
2306 current_position
= strstr(current_position
, "] ");
2307 if (current_position
!= NULL
) {
2308 current_position
+= 2;
2311 /* This is an error - shouldn't happen */
2315 /* Read this entry */
2316 if (sscanf(current_position
, "[UE=%u][RNTI=%u]", &ueids
[n
], &rntis
[n
]) != 2) {
2317 /* Assuming that if we can't read this one there is no point trying others */
2326 else if (sscanf(string
, ">> INFO (inst %u) MAC: [UE = %u] SR failed (CRNTI=%u)",
2327 &temp
, &ueids
[0], &rntis
[0]) == 3) {
2328 oob_event
= ltemac_sr_failure
;
2331 /* No events found */
2335 /********************************************/
2336 /* We have an event. Allocate & zero struct */
2337 p_mac_lte_info
= wmem_new0(wmem_file_scope(), mac_lte_info
);
2339 /* This indicates to MAC dissector that it has an oob event */
2340 p_mac_lte_info
->length
= 0;
2342 switch (oob_event
) {
2343 case ltemac_send_preamble
:
2344 p_mac_lte_info
->ueid
= ueids
[0];
2345 p_mac_lte_info
->rapid
= rapid
;
2346 p_mac_lte_info
->rach_attempt_number
= rach_attempt_number
;
2347 p_mac_lte_info
->direction
= DIRECTION_UPLINK
;
2349 case ltemac_send_sr
:
2350 for (n
=0; n
< number_of_ues
; n
++) {
2351 p_mac_lte_info
->oob_ueid
[n
] = ueids
[n
];
2352 p_mac_lte_info
->oob_rnti
[n
] = rntis
[n
];
2354 p_mac_lte_info
->number_of_srs
= number_of_ues
;
2355 p_mac_lte_info
->direction
= DIRECTION_UPLINK
;
2357 case ltemac_sr_failure
:
2358 p_mac_lte_info
->rnti
= rntis
[0];
2359 p_mac_lte_info
->ueid
= ueids
[0];
2360 p_mac_lte_info
->direction
= DIRECTION_DOWNLINK
;
2364 p_mac_lte_info
->radioType
= FDD_RADIO
; /* TODO: will be the same as rest of log... */
2365 p_mac_lte_info
->sfnSfInfoPresent
= false; /* We don't have this */
2366 p_mac_lte_info
->oob_event
= oob_event
;
2368 /* Store info in packet */
2369 set_mac_lte_proto_data(pinfo
, p_mac_lte_info
);
2371 /* Call MAC dissector */
2372 call_dissector_only(mac_lte_handle
, tvb
, pinfo
, tree
, NULL
);
2376 hex_from_char(char c
)
2378 if ((c
>= '0') && (c
<= '9')) {
2382 if ((c
>= 'a') && (c
<= 'f')) {
2383 return 0x0a + (c
- 'a');
2386 /* Not a valid hex string character */
2391 /*****************************************/
2392 /* Main dissection function. */
2393 /*****************************************/
2395 dissect_catapult_dct2000(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
2397 proto_tree
*dct2000_tree
= NULL
;
2398 proto_item
*ti
= NULL
;
2401 const char *context_name
;
2402 uint8_t port_number
;
2403 int protocol_length
;
2404 int timestamp_length
;
2405 const char *timestamp_string
;
2407 const char *variant_string
;
2410 const char *outhdr_string
;
2414 dissector_handle_t protocol_handle
= 0;
2415 dissector_handle_t heur_protocol_handle
= 0;
2416 void *protocol_data
= 0;
2417 int sub_dissector_result
= 0;
2418 const char *protocol_name
;
2419 bool is_comment
, is_sprint
= false;
2420 unsigned outhdr_values
[MAX_OUTHDR_VALUES
];
2421 unsigned outhdr_values_found
;
2424 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DCT2000");
2427 col_clear(pinfo
->cinfo
, COL_INFO
);
2429 /* Create root (protocol) tree. */
2431 ti
= proto_tree_add_item(tree
, proto_catapult_dct2000
, tvb
, offset
, -1, ENC_NA
);
2432 dct2000_tree
= proto_item_add_subtree(ti
, ett_catapult_dct2000
);
2435 /*********************************************************************/
2436 /* Note that these are the fields of the stub header as written out */
2437 /* by the wiretap module */
2440 context_name
= tvb_get_stringz_enc(pinfo
->pool
, tvb
, offset
, &context_length
, ENC_ASCII
);
2442 proto_tree_add_string(dct2000_tree
, hf_catapult_dct2000_context
, tvb
,
2443 offset
, context_length
, context_name
);
2445 offset
+= context_length
;
2447 /* Context port number */
2448 port_number
= tvb_get_uint8(tvb
, offset
);
2450 proto_tree_add_item(dct2000_tree
, hf_catapult_dct2000_port_number
, tvb
,
2451 offset
, 1, ENC_BIG_ENDIAN
);
2455 /* Timestamp in file */
2456 timestamp_string
= tvb_get_stringz_enc(pinfo
->pool
, tvb
, offset
, ×tamp_length
, ENC_ASCII
);
2458 /* g_ascii_strtod(timestamp_string, NULL)) is much simpler, but *very* slow..
2459 There will be seconds, a dot, and 4 decimal places.
2460 N.B. timestamp_length also includes following NULL character */
2461 if (timestamp_length
< 7) {
2462 /* Can't properly parse, but leave showing how far we got */
2469 for (int d
=timestamp_length
-7; d
>= 0; d
--) {
2470 seconds
+= ((timestamp_string
[d
]-'0') * multiplier
);
2474 /* Subseconds (4 digits). N.B. trailing zeros are written out by wiretap module. */
2476 subseconds
+= (timestamp_string
[timestamp_length
-2]-'0');
2477 subseconds
+= (timestamp_string
[timestamp_length
-3]-'0')*10;
2478 subseconds
+= (timestamp_string
[timestamp_length
-4]-'0')*100;
2479 subseconds
+= (timestamp_string
[timestamp_length
-5]-'0')*1000;
2481 proto_tree_add_double(dct2000_tree
, hf_catapult_dct2000_timestamp
, tvb
,
2482 offset
, timestamp_length
,
2483 seconds
+(subseconds
/10000.0));
2485 offset
+= timestamp_length
;
2488 /* DCT2000 protocol name */
2489 protocol_name
= tvb_get_stringz_enc(pinfo
->pool
, tvb
, offset
, &protocol_length
, ENC_ASCII
);
2491 proto_tree_add_string(dct2000_tree
, hf_catapult_dct2000_protocol
, tvb
,
2492 offset
, protocol_length
, protocol_name
);
2494 is_comment
= (strcmp(protocol_name
, "comment") == 0);
2496 is_sprint
= (strcmp(protocol_name
, "sprint") == 0);
2498 offset
+= protocol_length
;
2501 /* Protocol Variant */
2502 variant_string
= tvb_get_stringz_enc(pinfo
->pool
, tvb
, offset
, &variant_length
, ENC_ASCII
);
2503 if (!is_comment
&& !is_sprint
) {
2504 proto_tree_add_string(dct2000_tree
, hf_catapult_dct2000_variant
, tvb
,
2505 offset
, variant_length
, variant_string
);
2507 offset
+= variant_length
;
2509 /* Outhdr (shown as string) */
2510 outhdr_string
= tvb_get_stringz_enc(pinfo
->pool
, tvb
, offset
, &outhdr_length
, ENC_ASCII
);
2511 if (!is_comment
&& !is_sprint
&& (outhdr_length
> 1)) {
2512 proto_tree_add_string(dct2000_tree
, hf_catapult_dct2000_outhdr
, tvb
,
2513 offset
, outhdr_length
, outhdr_string
);
2515 offset
+= outhdr_length
;
2519 direction
= tvb_get_uint8(tvb
, offset
);
2521 proto_tree_add_item(dct2000_tree
, hf_catapult_dct2000_direction
, tvb
,
2522 offset
, 1, ENC_BIG_ENDIAN
);
2526 /* Read frame encapsulation set by wiretap */
2527 if (!is_comment
&& !is_sprint
) {
2528 proto_tree_add_item(dct2000_tree
, hf_catapult_dct2000_encap
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2530 encap
= tvb_get_uint8(tvb
, offset
);
2533 /* Add useful details to protocol tree label */
2534 proto_item_append_text(ti
, " context=%s.%u t=%s %c prot=%s (v=%s)",
2538 (direction
== 0) ? 'S' : 'R',
2543 memset(outhdr_values
, 0, sizeof outhdr_values
);
2544 outhdr_values_found
= 0;
2546 /* FP protocols need info from outhdr attached */
2547 if ((strcmp(protocol_name
, "fp") == 0) ||
2548 (strncmp(protocol_name
, "fp_r", 4) == 0) ||
2549 (strcmp(protocol_name
, "fpiur_r5") == 0)) {
2551 outhdr_values_found
= parse_outhdr_string(outhdr_string
, outhdr_length
,
2553 if (ws_strtou32(variant_string
, NULL
, &variant
))
2554 attach_fp_info(pinfo
, direction
, protocol_name
, variant
,
2555 outhdr_values
, outhdr_values_found
);
2557 expert_add_info(pinfo
, ti
, &ei_catapult_dct2000_string_invalid
);
2560 /* RLC protocols need info from outhdr attached */
2561 else if ((strcmp(protocol_name
, "rlc") == 0) ||
2562 (strcmp(protocol_name
, "rlc_r4") == 0) ||
2563 (strcmp(protocol_name
, "rlc_r5") == 0) ||
2564 (strcmp(protocol_name
, "rlc_r6") == 0) ||
2565 (strcmp(protocol_name
, "rlc_r7") == 0) ||
2566 (strcmp(protocol_name
, "rlc_r8") == 0) ||
2567 (strcmp(protocol_name
, "rlc_r9") == 0)) {
2569 outhdr_values_found
= parse_outhdr_string(outhdr_string
, outhdr_length
,
2571 /* Can't attach info yet. Need combination of outheader values
2572 and fields parsed from primitive header... */
2575 /* LTE MAC needs info attached */
2576 else if ((strcmp(protocol_name
, "mac_r8_lte") == 0) ||
2577 (strcmp(protocol_name
, "mac_r9_lte") == 0) ||
2578 (strcmp(protocol_name
, "mac_r10_lte") == 0)) {
2579 outhdr_values_found
= parse_outhdr_string(outhdr_string
, outhdr_length
,
2581 attach_mac_lte_info(pinfo
, outhdr_values
, outhdr_values_found
);
2584 /* LTE RLC needs info attached */
2585 else if ((strcmp(protocol_name
, "rlc_r8_lte") == 0) ||
2586 (strcmp(protocol_name
, "rlc_r9_lte") == 0) ||
2587 (strcmp(protocol_name
, "rlc_r10_lte") == 0)) {
2588 outhdr_values_found
= parse_outhdr_string(outhdr_string
, outhdr_length
,
2590 attach_rlc_lte_info(pinfo
, outhdr_values
, outhdr_values_found
);
2593 /* LTE PDCP needs info attached */
2594 else if ((strcmp(protocol_name
, "pdcp_r8_lte") == 0) ||
2595 (strcmp(protocol_name
, "pdcp_r9_lte") == 0) ||
2596 (strcmp(protocol_name
, "pdcp_r10_lte") == 0)) {
2597 outhdr_values_found
= parse_outhdr_string(outhdr_string
, outhdr_length
,
2599 attach_pdcp_lte_info(pinfo
, outhdr_values
, outhdr_values_found
);
2602 else if ((strcmp(protocol_name
, "nas_rrc_r8_lte") == 0) ||
2603 (strcmp(protocol_name
, "nas_rrc_r9_lte") == 0) ||
2604 (strcmp(protocol_name
, "nas_rrc_r10_lte") == 0) ||
2605 (strcmp(protocol_name
, "nas_rrc_r13_lte") == 0) ||
2606 (strcmp(protocol_name
, "nas_rrc_r15_5gnr") == 0)) {
2607 bool nas_body_found
= true;
2608 uint8_t opcode
= tvb_get_uint8(tvb
, offset
);
2609 proto_tree_add_item(tree
, hf_catapult_dct2000_lte_nas_rrc_opcode
,
2610 tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
2612 offset
++; /* Skip overall length */
2615 case LTE_NAS_RRC_DATA_IND
:
2616 case LTE_NAS_RRC_DATA_REQ
:
2619 offset
+= 2; /* 2 wasted bytes of UEId*/
2620 proto_tree_add_item(tree
, hf_catapult_dct2000_ueid
,
2621 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
2624 case LTE_NAS_RRC_ESTABLISH_REQ
:
2627 offset
+= 2; /* 2 wasted bytes of UEId*/
2628 proto_tree_add_item(tree
, hf_catapult_dct2000_ueid
,
2629 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
2632 /* Establish cause. TODO: value_string */
2633 offset
+= 2; /* tag + length */
2634 proto_tree_add_item(tree
, hf_catapult_dct2000_lte_nas_rrc_establish_cause
,
2635 tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
2637 /* Priority. TODO: Vals are low | high */
2638 offset
+= 2; /* tag + length */
2639 proto_tree_add_item(tree
, hf_catapult_dct2000_lte_nas_rrc_priority
,
2640 tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
2642 case LTE_NAS_RRC_RELEASE_IND
:
2645 offset
+= 2; /* 2 wasted bytes of UEId*/
2646 proto_tree_add_item(tree
, hf_catapult_dct2000_ueid
,
2647 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
2650 /* Release cause. TODO: value_string */
2651 offset
+= 2; /* tag + length */
2652 proto_tree_add_item(tree
, hf_catapult_dct2000_lte_nas_rrc_release_cause
,
2653 tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
2657 nas_body_found
= false;
2661 /* Look up dissector if it looks right */
2662 if (nas_body_found
) {
2663 offset
+= 2; /* L3 tag + len */
2664 if (strcmp(protocol_name
, "nas_rrc_r15_5gnr") == 0) {
2665 protocol_handle
= find_dissector("nas-5gs");
2668 protocol_handle
= find_dissector("nas-eps");
2673 /* NR NAS for S1AP */
2674 else if (strcmp(protocol_name
, "nas_s1ap_r15_5gnr") == 0) {
2675 uint8_t opcode
= tvb_get_uint8(tvb
, offset
);
2676 if (opcode
<= NAS_S1AP_DATA_IND
) {
2677 /* Opcode tag (only interested in ones that carry NAS PDU) */
2678 proto_tree_add_item(tree
, hf_catapult_dct2000_nr_nas_s1ap_opcode
,
2679 tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
2681 /* Skip overall length */
2682 offset
+= skipASNLength(tvb_get_uint8(tvb
, offset
));
2684 /* UE Id. Skip tag and fixed length */
2686 proto_tree_add_item(tree
, hf_catapult_dct2000_ueid
,
2687 tvb
, offset
, 4, ENC_BIG_ENDIAN
);
2690 /* NAS PDU tag is 2 bytes */
2691 uint16_t data_tag
= tvb_get_ntohs(tvb
, offset
);
2692 if (data_tag
== 0x0021) {
2694 /* Also skip length */
2696 protocol_handle
= find_dissector("nas-5gs");
2698 /* N.B. Ignoring some optional fields after the NAS PDU */
2704 /* Note that the first item of pinfo->pseudo_header->dct2000 will contain
2705 the pseudo-header needed (in some cases) by the Wireshark dissector that
2706 this packet data will be handed off to. */
2709 /***********************************************************************/
2710 /* Now hand off to the dissector of intended packet encapsulation type */
2712 /* Get protocol handle, and set p2p_dir where necessary.
2713 (packet-frame.c won't copy it from pseudo-header because it doesn't
2714 know about Catapult DCT2000 encap type...)
2717 case WTAP_ENCAP_RAW_IP
:
2718 protocol_handle
= find_dissector("ip");
2720 /* TODO: this doesn't work yet.
2721 pseudo_header isn't copied from wtap to pinfo... */
2722 if ((pinfo
->pseudo_header
!= NULL
) &&
2723 (pinfo
->pseudo_header
->dct2000
.inner_pseudo_header
.pdcp
.ueid
!= 0)) {
2727 /* Add PDCP thread info as generated fields */
2728 ti
= proto_tree_add_uint(dct2000_tree
, hf_catapult_dct2000_lte_ueid
, tvb
, 0, 0,
2729 pinfo
->pseudo_header
->dct2000
.inner_pseudo_header
.pdcp
.ueid
);
2730 proto_item_set_generated(ti
);
2731 ti
= proto_tree_add_uint(dct2000_tree
, hf_catapult_dct2000_lte_drbid
, tvb
, 0, 0,
2732 pinfo
->pseudo_header
->dct2000
.inner_pseudo_header
.pdcp
.drbid
);
2733 proto_item_set_generated(ti
);
2737 case WTAP_ENCAP_ETHERNET
:
2738 protocol_handle
= find_dissector("eth_withoutfcs");
2740 case WTAP_ENCAP_ISDN
:
2742 * XXX - if the file can handle B-channel traffic as well
2743 * as D-channel traffic, have the libwiretap code fill
2744 * in the channel, and call the ISDN dissector rather
2745 * than the LAPD-with-pseudoheader dissector.
2747 protocol_handle
= find_dissector("lapd-phdr");
2748 protocol_data
= &pinfo
->pseudo_header
->dct2000
.inner_pseudo_header
.isdn
;
2750 case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED
:
2751 protocol_handle
= find_dissector("atm_untruncated");
2752 protocol_data
= &pinfo
->pseudo_header
->dct2000
.inner_pseudo_header
.atm
;
2754 case WTAP_ENCAP_PPP
:
2755 protocol_handle
= find_dissector("ppp_hdlc");
2756 pinfo
->p2p_dir
= pinfo
->pseudo_header
->p2p
.sent
;
2758 case DCT2000_ENCAP_SSCOP
:
2759 protocol_handle
= find_dissector("sscop");
2761 case WTAP_ENCAP_FRELAY
:
2762 protocol_handle
= find_dissector("fr");
2764 case DCT2000_ENCAP_MTP2
:
2765 protocol_handle
= find_dissector("mtp2");
2767 case DCT2000_ENCAP_NBAP
:
2768 protocol_handle
= find_dissector("nbap");
2771 case DCT2000_ENCAP_UNHANDLED
:
2772 /**********************************************************/
2773 /* The wiretap module wasn't able to set an encapsulation */
2774 /* type, but it may still be possible to dissect the data */
2775 /* if we know about the protocol or if we can recognise */
2776 /* and parse or skip a primitive header */
2777 /**********************************************************/
2779 /* Show context.port in src or dest column as appropriate */
2780 if (direction
== 0) {
2781 col_add_fstr(pinfo
->cinfo
, COL_DEF_SRC
,
2787 if (direction
== 1) {
2788 col_add_fstr(pinfo
->cinfo
, COL_DEF_DST
,
2795 /**************************************************************************/
2796 /* These protocols have no encapsulation type, just look them up directly */
2798 if ((strcmp(protocol_name
, "rlc") == 0) ||
2799 (strcmp(protocol_name
, "rlc_r4") == 0) ||
2800 (strcmp(protocol_name
, "rlc_r5") == 0) ||
2801 (strcmp(protocol_name
, "rlc_r6") == 0) ||
2802 (strcmp(protocol_name
, "rlc_r7") == 0) ||
2803 (strcmp(protocol_name
, "rlc_r8") == 0) ||
2804 (strcmp(protocol_name
, "rlc_r9") == 0)) {
2806 dissect_rlc_umts(tvb
, offset
, pinfo
, tree
, direction
,
2807 outhdr_values
, outhdr_values_found
);
2808 return tvb_captured_length(tvb
);
2812 if ((strcmp(protocol_name
, "mac_r8_lte") == 0) ||
2813 (strcmp(protocol_name
, "mac_r9_lte") == 0) ||
2814 (strcmp(protocol_name
, "mac_r10_lte") == 0)) {
2815 protocol_handle
= mac_lte_handle
;
2819 if ((strcmp(protocol_name
, "rlc_r8_lte") == 0) ||
2820 (strcmp(protocol_name
, "rlc_r9_lte") == 0) ||
2821 (strcmp(protocol_name
, "rlc_r10_lte") == 0)) {
2822 protocol_handle
= rlc_lte_handle
;
2826 if ((strcmp(protocol_name
, "pdcp_r8_lte") == 0) ||
2827 (strcmp(protocol_name
, "pdcp_r9_lte") == 0) ||
2828 (strcmp(protocol_name
, "pdcp_r10_lte") == 0)) {
2829 /* Dissect proprietary header, then pass remainder to PDCP */
2830 dissect_pdcp_lte(tvb
, offset
, pinfo
, tree
);
2831 return tvb_captured_length(tvb
);
2835 /* Work with generic XML protocol. */
2837 if (strcmp(protocol_name
, "xml") == 0) {
2838 protocol_handle
= find_dissector("xml");
2842 /* Attempt to show tty messages as raw text */
2844 if (strcmp(protocol_name
, "tty") == 0) {
2845 dissect_tty_lines(tvb
, pinfo
, dct2000_tree
, offset
);
2846 return tvb_captured_length(tvb
);
2850 if (strcmp(protocol_name
, "sipprim") == 0) {
2851 protocol_handle
= find_dissector("sipprim");
2855 if (strcmp(protocol_name
, "comment") == 0) {
2856 /* Extract & add the string. */
2857 proto_item
*string_ti
;
2858 const uint8_t *string
;
2860 /* Show comment string */
2861 string_ti
= proto_tree_add_item_ret_string(dct2000_tree
, hf_catapult_dct2000_comment
, tvb
,
2862 offset
, tvb_reported_length_remaining(tvb
, offset
), ENC_ASCII
|ENC_NA
, pinfo
->pool
, &string
);
2863 col_append_str(pinfo
->cinfo
, COL_INFO
, string
);
2865 if (catapult_dct2000_dissect_mac_lte_oob_messages
) {
2866 /* Look into string for out-of-band MAC events, such as SRReq, SRInd */
2867 check_for_oob_mac_lte_events(pinfo
, tvb
, tree
, string
);
2870 /* Look for and flag generic error messages */
2871 if (strncmp(string
, ">> ERR", 6) == 0) {
2872 proto_item
*error_ti
= proto_tree_add_item(dct2000_tree
, hf_catapult_dct2000_error_comment
, tvb
,
2873 offset
, -1, ENC_NA
);
2874 proto_item_set_generated(error_ti
);
2875 expert_add_info_format(pinfo
, string_ti
, &ei_catapult_dct2000_error_comment_expert
,
2880 /* Look for logged MAC-NR PDU */
2881 /* Example contents would be:
2882 $Debug - NRMAC PDU: direction=0 rntiType=3 rnti=8495 ueid=1 SN=0 SFN=0 length=22 $40111212121212121212121212121212121212121212
2884 int dir
, rntiType
, rnti
, ueid
, sn
, sfn
, length
;
2886 if ((sscanf(string
, "L1_App: NRMAC PDU: direction=%d rntiType=%d rnti=%d ueid=%d SN=%d SFN=%d length=%d $",
2887 &dir
, &rntiType
, &rnti
, &ueid
, &sn
, &sfn
, &length
) == 7) ||
2888 (sscanf(string
, "NRMAC PDU: direction=%d rntiType=%d rnti=%d ueid=%d SN=%d SFN=%d length=%d $",
2889 &dir
, &rntiType
, &rnti
, &ueid
, &sn
, &sfn
, &length
) == 7))
2891 struct mac_nr_info
*p_mac_nr_info
;
2893 /* Only need to set info once per session? */
2894 /* p_mac_nr_info = get_mac_nr_proto_data(pinfo); */
2896 /* Allocate & zero struct */
2897 p_mac_nr_info
= wmem_new0(wmem_file_scope(), struct mac_nr_info
);
2899 /* Populate the struct from outhdr values */
2900 p_mac_nr_info
->radioType
= FDD_RADIO
;
2902 /* Map internal RNTI type -> Wireshark #defines from packet-mac-nr.h */
2905 p_mac_nr_info
->rntiType
= P_RNTI
;
2908 p_mac_nr_info
->rntiType
= RA_RNTI
;
2911 p_mac_nr_info
->rntiType
= C_RNTI
; /* temp C-RNTI */
2914 p_mac_nr_info
->rntiType
= C_RNTI
;
2917 p_mac_nr_info
->rntiType
= MSGB_RNTI
;
2920 p_mac_nr_info
->rntiType
= NO_RNTI
;
2924 p_mac_nr_info
->direction
= dir
;
2925 p_mac_nr_info
->rnti
= rnti
;
2926 // 0xFFFF trumps logged rntiType...
2927 if (rnti
== 65535) {
2928 p_mac_nr_info
->rntiType
= SI_RNTI
;
2930 p_mac_nr_info
->ueid
= ueid
;
2932 p_mac_nr_info
->phr_type2_othercell
= false;
2934 p_mac_nr_info
->length
= length
;
2936 /* Always present. TODO: miss out if both zero? */
2937 p_mac_nr_info
->sfnSlotInfoPresent
= true;
2938 p_mac_nr_info
->sysframeNumber
= sfn
;
2939 p_mac_nr_info
->slotNumber
= sn
; /* only right if mu==0, but don't know SCS */
2941 /* Store info in packet */
2942 set_mac_nr_proto_data(pinfo
, p_mac_nr_info
);
2944 /* Payload is from $ to end of string */
2945 int data_offset
= 0;
2946 for (unsigned int n
=0; n
< strlen(string
); n
++) {
2947 if (string
[n
] == '$') {
2953 /* Convert data to hex. */
2954 char *mac_data
= (char *)wmem_alloc(pinfo
->pool
, 2 + (strlen(string
)-data_offset
)/2);
2956 for (idx
=0, m
=data_offset
+1; string
[m
] != '\0'; m
+=2, idx
++) {
2957 mac_data
[idx
] = (hex_from_char(string
[m
]) << 4) + hex_from_char(string
[m
+1]);
2961 tvbuff_t
*mac_nr_tvb
= tvb_new_real_data(mac_data
, idx
, idx
);
2962 add_new_data_source(pinfo
, mac_nr_tvb
, "MAC-NR Payload");
2963 /* Call the dissector! */
2964 call_dissector_only(mac_nr_handle
, mac_nr_tvb
, pinfo
, tree
, NULL
);
2967 /* Look for logged NRUP PDU */
2968 const char *nrup_pattern
= "NRUP PDU: ";
2969 char *start
= strstr(string
, nrup_pattern
);
2973 while (start
[off
] && start
[off
] != '$') {
2977 const char *payload
= &start
[off
+1];
2979 /* Pad out to nearest 4 bytes if necessary. */
2980 /* Convert data to hex. */
2981 #define MAX_NRUP_DATA_LENGTH 200
2982 static uint8_t nrup_data
[MAX_NRUP_DATA_LENGTH
];
2985 /* The rest (or all) is data! */
2986 length
= (int)strlen(payload
) / 2;
2987 for (m
=0, idx
=0; payload
[m
] != '\0' && idx
< MAX_NRUP_DATA_LENGTH
-4; m
+=2, idx
++) {
2988 nrup_data
[idx
] = (hex_from_char(payload
[m
]) << 4) + hex_from_char(payload
[m
+1]);
2990 /* Pad out to nearest 4 bytes if necessary. */
2991 if (length
% 4 != 0) {
2992 for (int p
=length
% 4; p
< 4; p
++) {
2993 nrup_data
[length
++] = '\0';
2997 /* Create separate NRUP tvb */
2998 tvbuff_t
*nrup_tvb
= tvb_new_real_data(nrup_data
, length
, length
);
2999 add_new_data_source(pinfo
, nrup_tvb
, "NRUP Payload");
3001 /* Call the dissector! */
3002 call_dissector_only(nrup_handle
, nrup_tvb
, pinfo
, tree
, NULL
);
3005 /* Read key info from formatted lines */
3006 /* e.g. NRPDCP: RRCPRIM:ueId= 1;setThreadAuthKey: RRC id=1 alg 2 key: 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 */
3007 if (strstr(string
, "setThreadAuthKey:")) {
3008 unsigned ue_id
, id
, alg
;
3009 if (!PINFO_FD_VISITED(pinfo
) && sscanf(string
, "NRPDCP: RRCPRIM:ueId= %u;setThreadAuthKey: RRC id=%u alg %u key: ", &ue_id
, &id
, &alg
) == 3) {
3010 char *key
= g_strdup(strstr(string
, "key: ")+5);
3011 set_pdcp_nr_rrc_integrity_key(ue_id
, key
, pinfo
->num
);
3014 else if (!PINFO_FD_VISITED(pinfo
) && sscanf(string
, "NRPDCP: RRCPRIM:ueId= %u;setThreadAuthKey: UP id=%u alg %u key: ", &ue_id
, &id
, &alg
) == 3) {
3015 char *key
= g_strdup(strstr(string
, "key: ")+5);
3016 set_pdcp_nr_up_integrity_key(ue_id
, key
, pinfo
->num
);
3020 else if (strstr(string
, "setThreadCryptKey:")) {
3021 unsigned ue_id
, id
, alg
;
3022 if (!PINFO_FD_VISITED(pinfo
) && sscanf(string
, "NRPDCP: RRCPRIM:ueId= %u;setThreadCryptKey: RRC id=%u alg %u key: ", &ue_id
, &id
, &alg
) == 3) {
3023 char *key
= g_strdup(strstr(string
, "key: ")+5);
3024 set_pdcp_nr_rrc_ciphering_key(ue_id
, key
, pinfo
->num
);
3027 else if (!PINFO_FD_VISITED(pinfo
) && sscanf(string
, "NRPDCP: RRCPRIM:ueId= %u;setThreadCryptKey: UP id=%u alg %u key: ", &ue_id
, &id
, &alg
) == 3) {
3028 char *key
= g_strdup(strstr(string
, "key: ")+5);
3029 set_pdcp_nr_up_ciphering_key(ue_id
, key
, pinfo
->num
);
3034 /* 'raw' (ethernet) frames logged as text comments */
3037 if (sscanf(string
, "RawTraffic: Interface: %d %c $",
3038 &raw_interface
, &raw_direction
) == 2)
3041 proto_tree_add_uint(tree
, hf_catapult_dct2000_rawtraffic_interface
,
3042 tvb
, 0, 0, raw_interface
);
3045 proto_tree_add_uint(tree
, hf_catapult_dct2000_rawtraffic_direction
,
3046 tvb
, 0, 0, raw_direction
== 'r');
3048 /* Payload is from $ to end of string */
3049 int data_offset
= 0;
3050 for (unsigned int n
=0; n
< strlen(string
); n
++) {
3051 if (string
[n
] == '$') {
3057 /* Convert data to hex. */
3058 static uint8_t eth_data
[36000];
3060 for (idx
=0, m
=data_offset
+1; idx
<36000 && string
[m
] != '\0'; m
+=2, idx
++) {
3061 eth_data
[idx
] = (hex_from_char(string
[m
]) << 4) + hex_from_char(string
[m
+1]);
3065 tvbuff_t
*raw_traffic_tvb
= tvb_new_real_data(eth_data
, idx
, idx
);
3066 add_new_data_source(pinfo
, raw_traffic_tvb
, "Raw-Traffic Payload");
3069 proto_tree_add_item(tree
, hf_catapult_dct2000_rawtraffic_pdu
, raw_traffic_tvb
,
3070 0, tvb_reported_length(raw_traffic_tvb
), ENC_NA
);
3072 /* Call the dissector! */
3073 call_dissector_only(eth_handle
, raw_traffic_tvb
, pinfo
, tree
, NULL
);
3076 return tvb_captured_length(tvb
);
3080 if (strcmp(protocol_name
, "sprint") == 0) {
3081 /* Extract & add the string. */
3082 const uint8_t *string
;
3084 /* Show sprint string */
3085 proto_tree_add_item_ret_string(dct2000_tree
, hf_catapult_dct2000_sprint
, tvb
,
3086 offset
, tvb_reported_length_remaining(tvb
, offset
), ENC_ASCII
|ENC_NA
, pinfo
->pool
, &string
);
3087 col_append_str(pinfo
->cinfo
, COL_INFO
, string
);
3089 return tvb_captured_length(tvb
);
3093 Dissect proprietary header, then pass remainder
3094 to RRC dissector (depending upon direction and channel type) */
3096 if (catapult_dct2000_dissect_lte_rrc
&&
3097 ((strcmp(protocol_name
, "rrc_r8_lte") == 0) ||
3098 (strcmp(protocol_name
, "rrcpdcpprim_r8_lte") == 0) ||
3099 (strcmp(protocol_name
, "rrc_r9_lte") == 0) ||
3100 (strcmp(protocol_name
, "rrcpdcpprim_r9_lte") == 0) ||
3101 (strcmp(protocol_name
, "rrc_r10_lte") == 0) ||
3102 (strcmp(protocol_name
, "rrc_r11_lte") == 0) ||
3103 (strcmp(protocol_name
, "rrc_r12_lte") == 0) ||
3104 (strcmp(protocol_name
, "rrc_r13_lte") == 0) ||
3105 (strcmp(protocol_name
, "rrc_r15_lte") == 0) ||
3106 (strcmp(protocol_name
, "rrc_r16_lte") == 0) ||
3107 (strcmp(protocol_name
, "rrcpdcpprim_r15_lte") == 0))) {
3109 dissect_rrc_lte_nr(tvb
, offset
, pinfo
, tree
, LTE
);
3110 return tvb_captured_length(tvb
);
3112 else if ((strcmp(protocol_name
, "rrc_r15_5g") == 0) ||
3113 (strcmp(protocol_name
, "rrc_r16_5g") == 0)) {
3114 dissect_rrc_lte_nr(tvb
, offset
, pinfo
, tree
, NR
);
3115 return tvb_captured_length(tvb
);
3119 if ((strcmp(protocol_name
, "ccpri_r8_lte") == 0) ||
3120 (strcmp(protocol_name
, "ccpri_r9_lte") == 0)) {
3122 /* Dissect proprietary header, then pass remainder to lapb */
3123 dissect_ccpri_lte(tvb
, offset
, pinfo
, tree
);
3124 return tvb_captured_length(tvb
);
3127 /* Many DCT2000 protocols have at least one IPPrim variant. If the
3128 protocol name can be matched to a dissector, try to find the
3129 UDP/TCP data inside and dissect it.
3132 if (!protocol_handle
&& catapult_dct2000_try_ipprim_heuristic
) {
3133 uint32_t source_addr_offset
= 0, dest_addr_offset
= 0;
3134 uint8_t source_addr_length
= 0, dest_addr_length
= 0;
3135 uint32_t source_port_offset
= 0, dest_port_offset
= 0;
3136 port_type type_of_port
= PT_NONE
;
3137 uint16_t conn_id_offset
= 0;
3138 int offset_before_ipprim_header
= offset
;
3140 /* For ipprim, want to show ipprim header even if can't find dissector to call for payload.. */
3141 if (find_ipprim_data_offset(tvb
, &offset
, direction
,
3142 &source_addr_offset
, &source_addr_length
,
3143 &dest_addr_offset
, &dest_addr_length
,
3144 &source_port_offset
, &dest_port_offset
,
3148 proto_tree
*ipprim_tree
;
3149 proto_item
*ipprim_ti
;
3150 struct e_in6_addr sourcev6
, destv6
;
3152 /* Fetch IPv6 addresses */
3153 if (source_addr_length
!= 4) {
3154 tvb_get_ipv6(tvb
, source_addr_offset
, &sourcev6
);
3156 if (dest_addr_length
!= 4) {
3157 tvb_get_ipv6(tvb
, dest_addr_offset
, &destv6
);
3161 /* Will use this dissector then. */
3162 heur_protocol_handle
= look_for_dissector(protocol_name
);
3163 protocol_handle
= heur_protocol_handle
;
3165 /* Add address parameters to tree */
3166 /* Unfortunately can't automatically create a conversation filter for this...
3167 I *could* create a fake IP header from these details, but then it would be tricky
3168 to get the FP dissector called as it has no well-known ports or heuristics... */
3169 ipprim_ti
= proto_tree_add_string_format(dct2000_tree
, hf_catapult_dct2000_ipprim_addresses
,
3170 tvb
, offset_before_ipprim_header
, 0,
3171 "", "IPPrim transport (%s): %s:%u -> %s:%u",
3172 (type_of_port
== PT_UDP
) ? "UDP" : "TCP",
3173 (source_addr_offset
) ?
3174 ((source_addr_length
== 4) ?
3175 get_hostname(tvb_get_ipv4(tvb
, source_addr_offset
)) :
3176 get_hostname6(&sourcev6
)
3179 (source_port_offset
) ?
3180 tvb_get_ntohs(tvb
, source_port_offset
) :
3182 (dest_addr_offset
) ?
3183 ((source_addr_length
== 4) ?
3184 get_hostname(tvb_get_ipv4(tvb
, dest_addr_offset
)) :
3185 get_hostname6(&destv6
)
3188 (dest_port_offset
) ?
3189 tvb_get_ntohs(tvb
, dest_port_offset
) :
3191 if ((type_of_port
== PT_TCP
) && (conn_id_offset
!= 0)) {
3192 proto_item_append_text(ipprim_ti
, " (conn_id=%u)", tvb_get_ntohs(tvb
, conn_id_offset
));
3195 /* Add these IPPRIM fields inside an IPPRIM subtree */
3196 ipprim_tree
= proto_item_add_subtree(ipprim_ti
, ett_catapult_dct2000_ipprim
);
3198 /* Try to add right stuff to pinfo so conversation stuff works... */
3199 pinfo
->ptype
= type_of_port
;
3201 /* Add addresses & ports into ipprim tree.
3202 Also set address info in pinfo for conversations... */
3203 if (source_addr_offset
!= 0) {
3204 proto_item
*addr_ti
;
3206 set_address_tvb(&pinfo
->net_src
,
3207 (source_addr_length
== 4) ? AT_IPv4
: AT_IPv6
,
3208 source_addr_length
, tvb
, source_addr_offset
);
3209 copy_address_shallow(&pinfo
->src
, &pinfo
->net_src
);
3211 proto_tree_add_item(ipprim_tree
,
3212 (source_addr_length
== 4) ?
3213 hf_catapult_dct2000_ipprim_src_addr_v4
:
3214 hf_catapult_dct2000_ipprim_src_addr_v6
,
3215 tvb
, source_addr_offset
, source_addr_length
,
3218 /* Add hidden item for "side-less" addr */
3219 addr_ti
= proto_tree_add_item(ipprim_tree
,
3220 (source_addr_length
== 4) ?
3221 hf_catapult_dct2000_ipprim_addr_v4
:
3222 hf_catapult_dct2000_ipprim_addr_v6
,
3223 tvb
, source_addr_offset
, source_addr_length
,
3225 proto_item_set_hidden(addr_ti
);
3227 if (source_port_offset
!= 0) {
3228 proto_item
*port_ti
;
3230 pinfo
->srcport
= tvb_get_ntohs(tvb
, source_port_offset
);
3232 proto_tree_add_item(ipprim_tree
,
3233 (type_of_port
== PT_UDP
) ?
3234 hf_catapult_dct2000_ipprim_udp_src_port
:
3235 hf_catapult_dct2000_ipprim_tcp_src_port
,
3236 tvb
, source_port_offset
, 2, ENC_BIG_ENDIAN
);
3237 port_ti
= proto_tree_add_item(ipprim_tree
,
3238 (type_of_port
== PT_UDP
) ?
3239 hf_catapult_dct2000_ipprim_udp_port
:
3240 hf_catapult_dct2000_ipprim_tcp_port
,
3241 tvb
, source_port_offset
, 2, ENC_BIG_ENDIAN
);
3242 proto_item_set_hidden(port_ti
);
3244 if (dest_addr_offset
!= 0) {
3245 proto_item
*addr_ti
;
3247 set_address_tvb(&pinfo
->net_dst
,
3248 (dest_addr_length
== 4) ? AT_IPv4
: AT_IPv6
,
3249 dest_addr_length
, tvb
, dest_addr_offset
);
3250 copy_address_shallow(&pinfo
->dst
, &pinfo
->net_dst
);
3251 proto_tree_add_item(ipprim_tree
,
3252 (dest_addr_length
== 4) ?
3253 hf_catapult_dct2000_ipprim_dst_addr_v4
:
3254 hf_catapult_dct2000_ipprim_dst_addr_v6
,
3255 tvb
, dest_addr_offset
, dest_addr_length
,
3258 /* Add hidden item for "side-less" addr */
3259 addr_ti
= proto_tree_add_item(ipprim_tree
,
3260 (dest_addr_length
== 4) ?
3261 hf_catapult_dct2000_ipprim_addr_v4
:
3262 hf_catapult_dct2000_ipprim_addr_v6
,
3263 tvb
, dest_addr_offset
, dest_addr_length
,
3265 proto_item_set_hidden(addr_ti
);
3267 if (dest_port_offset
!= 0) {
3268 proto_item
*port_ti
;
3270 pinfo
->destport
= tvb_get_ntohs(tvb
, dest_port_offset
);
3272 proto_tree_add_item(ipprim_tree
,
3273 (type_of_port
== PT_UDP
) ?
3274 hf_catapult_dct2000_ipprim_udp_dst_port
:
3275 hf_catapult_dct2000_ipprim_tcp_dst_port
,
3276 tvb
, dest_port_offset
, 2, ENC_BIG_ENDIAN
);
3277 port_ti
= proto_tree_add_item(ipprim_tree
,
3278 (type_of_port
== PT_UDP
) ?
3279 hf_catapult_dct2000_ipprim_udp_port
:
3280 hf_catapult_dct2000_ipprim_tcp_port
,
3281 tvb
, dest_port_offset
, 2, ENC_BIG_ENDIAN
);
3282 proto_item_set_hidden(port_ti
);
3284 if (conn_id_offset
!= 0) {
3285 proto_tree_add_item(ipprim_tree
,
3286 hf_catapult_dct2000_ipprim_conn_id
,
3287 tvb
, conn_id_offset
, 2, ENC_BIG_ENDIAN
);
3291 /* Set source and dest columns now (will be overwriiten if
3292 src and dst IP addresses set) */
3293 if (source_addr_offset
) {
3294 col_append_fstr(pinfo
->cinfo
, COL_DEF_SRC
,
3296 get_hostname(tvb_get_ipv4(tvb
, source_addr_offset
)),
3297 tvb_get_ntohs(tvb
, source_port_offset
));
3299 if (dest_addr_offset
) {
3300 col_append_fstr(pinfo
->cinfo
, COL_DEF_DST
,
3302 get_hostname(tvb_get_ipv4(tvb
, dest_addr_offset
)),
3303 tvb_get_ntohs(tvb
, dest_port_offset
));
3306 /* Set length for IPPrim tree */
3307 proto_item_set_len(ipprim_tree
, offset
- offset_before_ipprim_header
);
3312 /* Try SCTP Prim heuristic if configured to */
3313 if (!protocol_handle
&& catapult_dct2000_try_sctpprim_heuristic
) {
3314 uint32_t dest_addr_offset
= 0;
3315 uint16_t dest_addr_length
= 0;
3316 uint32_t dest_port_offset
= 0;
3317 int offset_before_sctpprim_header
= offset
;
3319 heur_protocol_handle
= look_for_dissector(protocol_name
);
3320 if ((heur_protocol_handle
!= 0) &&
3321 (find_sctpprim_variant1_data_offset(tvb
, &offset
,
3324 &dest_port_offset
) ||
3325 find_sctpprim_variant3_data_offset(tvb
, &offset
,
3328 &dest_port_offset
))) {
3330 proto_tree
*sctpprim_tree
;
3331 proto_item
*ti_local
;
3333 /* Will use this dissector then. */
3334 protocol_handle
= heur_protocol_handle
;
3336 ti_local
= proto_tree_add_string_format(dct2000_tree
, hf_catapult_dct2000_sctpprim_addresses
,
3337 tvb
, offset_before_sctpprim_header
, 0,
3338 "", "SCTPPrim transport: -> %s:%u",
3339 (dest_addr_offset
) ?
3340 ((dest_addr_length
== 4) ?
3341 get_hostname(tvb_get_ipv4(tvb
, dest_addr_offset
)) :
3345 (dest_port_offset
) ?
3346 tvb_get_ntohs(tvb
, dest_port_offset
) :
3349 /* Add these SCTPPRIM fields inside an SCTPPRIM subtree */
3350 sctpprim_tree
= proto_item_add_subtree(ti_local
, ett_catapult_dct2000_sctpprim
);
3352 /* Destination address */
3353 if (dest_addr_offset
!= 0) {
3354 proto_item
*addr_ti
;
3356 set_address_tvb(&pinfo
->net_dst
,
3357 (dest_addr_length
== 4) ? AT_IPv4
: AT_IPv6
,
3358 dest_addr_length
, tvb
, dest_addr_offset
);
3359 copy_address_shallow(&pinfo
->dst
, &pinfo
->net_dst
);
3360 proto_tree_add_item(sctpprim_tree
,
3361 (dest_addr_length
== 4) ?
3362 hf_catapult_dct2000_sctpprim_dst_addr_v4
:
3363 hf_catapult_dct2000_sctpprim_dst_addr_v6
,
3364 tvb
, dest_addr_offset
, dest_addr_length
,
3367 /* Add hidden item for "side-less" addr */
3368 addr_ti
= proto_tree_add_item(sctpprim_tree
,
3369 (dest_addr_length
== 4) ?
3370 hf_catapult_dct2000_sctpprim_addr_v4
:
3371 hf_catapult_dct2000_sctpprim_addr_v6
,
3372 tvb
, dest_addr_offset
, dest_addr_length
,
3374 proto_item_set_hidden(addr_ti
);
3377 if (dest_port_offset
!= 0) {
3378 pinfo
->destport
= tvb_get_ntohs(tvb
, dest_port_offset
);
3380 proto_tree_add_item(sctpprim_tree
,
3381 hf_catapult_dct2000_sctpprim_dst_port
,
3382 tvb
, dest_port_offset
, 2, ENC_BIG_ENDIAN
);
3385 /* Set length for SCTPPrim tree */
3386 proto_item_set_len(sctpprim_tree
, offset
- offset_before_sctpprim_header
);
3390 /* Next chance: is there a (private) registered protocol of the form
3391 "dct2000.protocol" ? */
3392 if (protocol_handle
== 0) {
3393 /* TODO: only look inside if a preference enabled? */
3394 char dotted_protocol_name
[128];
3395 /* N.B. avoiding snprintf(), which was slow */
3396 (void) g_strlcpy(dotted_protocol_name
, "dct2000.", 128);
3397 (void) g_strlcpy(dotted_protocol_name
+8, protocol_name
, 128-8);
3398 protocol_handle
= find_dissector(dotted_protocol_name
);
3401 /* Last resort: Allow any PDU to be dissected if the protocol matches with
3403 if ( !protocol_handle
&& catapult_dct2000_use_protocol_name_as_dissector_name
) {
3404 protocol_handle
= find_dissector(protocol_name
);
3411 /* !! If get here, there is a mismatch between
3412 this dissector and the wiretap module catapult_dct2000.c !!
3414 DISSECTOR_ASSERT_NOT_REACHED();
3418 /* Set selection length of dct2000 tree */
3419 proto_item_set_len(dct2000_tree
, offset
);
3421 /* Try appropriate dissector, if one has been selected */
3422 if (protocol_handle
!= 0) {
3423 /* Dissect the remainder of the frame using chosen protocol handle */
3424 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
3425 sub_dissector_result
= call_dissector_only(protocol_handle
, next_tvb
, pinfo
, tree
, protocol_data
);
3429 if (protocol_handle
== 0 || sub_dissector_result
== 0) {
3430 /* Could get here because:
3431 - encap is DCT2000_ENCAP_UNHANDLED and we still didn't handle it, OR
3432 - desired protocol is unavailable (probably disabled), OR
3433 - protocol rejected our data
3434 Show remaining bytes as unparsed data */
3435 proto_tree_add_item(dct2000_tree
, hf_catapult_dct2000_unparsed_data
,
3436 tvb
, offset
, -1, ENC_NA
);
3438 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
3439 "Not dissected (context=%s.%u t=%s %c prot=%s (v=%s))",
3443 (direction
== 0) ? 'S' : 'R',
3448 /* Show number of dissected bytes */
3450 proto_item
*ti_local
= proto_tree_add_uint(dct2000_tree
,
3451 hf_catapult_dct2000_dissected_length
,
3452 tvb
, 0, 0, tvb_reported_length(tvb
)-offset
);
3453 proto_item_set_generated(ti_local
);
3457 return tvb_captured_length(tvb
);
3462 /******************************************************************************/
3463 /* Associate this protocol with the Catapult DCT2000 file encapsulation type. */
3464 /******************************************************************************/
3465 void proto_reg_handoff_catapult_dct2000(void)
3467 dissector_add_uint("wtap_encap", WTAP_ENCAP_CATAPULT_DCT2000
, catapult_dct2000_handle
);
3469 mac_lte_handle
= find_dissector("mac-lte");
3470 rlc_lte_handle
= find_dissector("rlc-lte");
3471 pdcp_lte_handle
= find_dissector("pdcp-lte");
3473 mac_nr_handle
= find_dissector("mac-nr");
3474 nrup_handle
= find_dissector("nrup");
3475 eth_handle
= find_dissector("eth_withoutfcs");
3476 nrup_handle
= find_dissector("nrup");
3479 /****************************************/
3480 /* Register the protocol */
3481 /****************************************/
3482 void proto_register_catapult_dct2000(void)
3484 static hf_register_info hf
[] =
3486 { &hf_catapult_dct2000_context
,
3488 "dct2000.context", FT_STRING
, BASE_NONE
, NULL
, 0x0,
3489 "Context name", HFILL
3492 { &hf_catapult_dct2000_port_number
,
3493 { "Context Port number",
3494 "dct2000.context_port", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3498 { &hf_catapult_dct2000_timestamp
,
3500 "dct2000.timestamp", FT_DOUBLE
, BASE_NONE
, NULL
, 0x0,
3501 "File timestamp", HFILL
3504 { &hf_catapult_dct2000_protocol
,
3505 { "DCT2000 protocol",
3506 "dct2000.protocol", FT_STRING
, BASE_NONE
, NULL
, 0x0,
3507 "Original (DCT2000) protocol name", HFILL
3510 { &hf_catapult_dct2000_variant
,
3511 { "Protocol variant",
3512 "dct2000.variant", FT_STRING
, BASE_NONE
, NULL
, 0x0,
3513 "DCT2000 protocol variant", HFILL
3516 { &hf_catapult_dct2000_outhdr
,
3518 "dct2000.outhdr", FT_STRING
, BASE_NONE
, NULL
, 0x0,
3519 "DCT2000 protocol outhdr", HFILL
3522 { &hf_catapult_dct2000_direction
,
3524 "dct2000.direction", FT_UINT8
, BASE_DEC
, VALS(direction_vals
), 0x0,
3525 "Frame direction (Sent or Received)", HFILL
3528 { &hf_catapult_dct2000_encap
,
3529 { "Wireshark encapsulation",
3530 "dct2000.encapsulation", FT_UINT8
, BASE_DEC
, VALS(encap_vals
), 0x0,
3531 "Wireshark frame encapsulation used", HFILL
3534 { &hf_catapult_dct2000_unparsed_data
,
3535 { "Unparsed protocol data",
3536 "dct2000.unparsed_data", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
3537 "Unparsed DCT2000 protocol data", HFILL
3540 { &hf_catapult_dct2000_comment
,
3542 "dct2000.comment", FT_STRING
, BASE_NONE
, NULL
, 0x0,
3546 { &hf_catapult_dct2000_sprint
,
3548 "dct2000.sprint", FT_STRING
, BASE_NONE
, NULL
, 0x0,
3552 { &hf_catapult_dct2000_error_comment
,
3554 "dct2000.error-comment", FT_NONE
, BASE_NONE
, NULL
, 0x0,
3558 { &hf_catapult_dct2000_dissected_length
,
3559 { "Dissected length",
3560 "dct2000.dissected-length", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3561 "Number of bytes dissected by subdissector(s)", HFILL
3565 { &hf_catapult_dct2000_ipprim_addresses
,
3566 { "IPPrim Addresses",
3567 "dct2000.ipprim", FT_STRING
, BASE_NONE
, NULL
, 0x0,
3571 { &hf_catapult_dct2000_ipprim_src_addr_v4
,
3573 "dct2000.ipprim.src", FT_IPv4
, BASE_NONE
, NULL
, 0x0,
3574 "IPPrim IPv4 Source Address", HFILL
3577 { &hf_catapult_dct2000_ipprim_src_addr_v6
,
3579 "dct2000.ipprim.srcv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0,
3580 "IPPrim IPv6 Source Address", HFILL
3583 { &hf_catapult_dct2000_ipprim_dst_addr_v4
,
3584 { "Destination Address",
3585 "dct2000.ipprim.dst", FT_IPv4
, BASE_NONE
, NULL
, 0x0,
3586 "IPPrim IPv4 Destination Address", HFILL
3589 { &hf_catapult_dct2000_ipprim_dst_addr_v6
,
3590 { "Destination Address",
3591 "dct2000.ipprim.dstv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0,
3592 "IPPrim IPv6 Destination Address", HFILL
3595 { &hf_catapult_dct2000_ipprim_addr_v4
,
3597 "dct2000.ipprim.addr", FT_IPv4
, BASE_NONE
, NULL
, 0x0,
3598 "IPPrim IPv4 Address", HFILL
3601 { &hf_catapult_dct2000_ipprim_addr_v6
,
3603 "dct2000.ipprim.addrv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0,
3604 "IPPrim IPv6 Address", HFILL
3607 { &hf_catapult_dct2000_ipprim_udp_src_port
,
3608 { "UDP Source Port",
3609 "dct2000.ipprim.udp.srcport", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3610 "IPPrim UDP Source Port", HFILL
3613 { &hf_catapult_dct2000_ipprim_udp_dst_port
,
3614 { "UDP Destination Port",
3615 "dct2000.ipprim.udp.dstport", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3616 "IPPrim UDP Destination Port", HFILL
3619 { &hf_catapult_dct2000_ipprim_udp_port
,
3621 "dct2000.ipprim.udp.port", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3622 "IPPrim UDP Port", HFILL
3625 { &hf_catapult_dct2000_ipprim_tcp_src_port
,
3626 { "TCP Source Port",
3627 "dct2000.ipprim.tcp.srcport", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3628 "IPPrim TCP Source Port", HFILL
3631 { &hf_catapult_dct2000_ipprim_tcp_dst_port
,
3632 { "TCP Destination Port",
3633 "dct2000.ipprim.tcp.dstport", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3634 "IPPrim TCP Destination Port", HFILL
3637 { &hf_catapult_dct2000_ipprim_tcp_port
,
3639 "dct2000.ipprim.tcp.port", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3640 "IPPrim TCP Port", HFILL
3643 { &hf_catapult_dct2000_ipprim_conn_id
,
3645 "dct2000.ipprim.conn-id", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3646 "IPPrim TCP Connection ID", HFILL
3650 { &hf_catapult_dct2000_sctpprim_addresses
,
3651 { "SCTPPrim Addresses",
3652 "dct2000.sctpprim", FT_STRING
, BASE_NONE
, NULL
, 0x0,
3656 { &hf_catapult_dct2000_sctpprim_dst_addr_v4
,
3657 { "Destination Address",
3658 "dct2000.sctpprim.dst", FT_IPv4
, BASE_NONE
, NULL
, 0x0,
3659 "SCTPPrim IPv4 Destination Address", HFILL
3662 { &hf_catapult_dct2000_sctpprim_dst_addr_v6
,
3663 { "Destination Address",
3664 "dct2000.sctpprim.dstv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0,
3665 "SCTPPrim IPv6 Destination Address", HFILL
3668 { &hf_catapult_dct2000_sctpprim_addr_v4
,
3670 "dct2000.sctpprim.addr", FT_IPv4
, BASE_NONE
, NULL
, 0x0,
3671 "SCTPPrim IPv4 Address", HFILL
3674 { &hf_catapult_dct2000_sctpprim_addr_v6
,
3676 "dct2000.sctpprim.addrv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0,
3677 "SCTPPrim IPv6 Address", HFILL
3680 { &hf_catapult_dct2000_sctpprim_dst_port
,
3681 { "UDP Destination Port",
3682 "dct2000.sctprim.dstport", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3683 "SCTPPrim Destination Port", HFILL
3687 { &hf_catapult_dct2000_tty
,
3689 "dct2000.tty", FT_NONE
, BASE_NONE
, NULL
, 0x0,
3693 { &hf_catapult_dct2000_tty_line
,
3695 "dct2000.tty-line", FT_STRING
, BASE_NONE
, NULL
, 0x0,
3700 { &hf_catapult_dct2000_ueid
,
3702 "dct2000.ueid", FT_UINT32
, BASE_DEC
, NULL
, 0x0,
3703 "User Equipment Identifier", HFILL
3706 { &hf_catapult_dct2000_srbid
,
3708 "dct2000.srbid", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3709 "Signalling Radio Bearer Identifier", HFILL
3712 { &hf_catapult_dct2000_drbid
,
3714 "dct2000.drbid", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3715 "Data Radio Bearer Identifier", HFILL
3718 { &hf_catapult_dct2000_cellid
,
3720 "dct2000.cellid", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3721 "Cell Identifier", HFILL
3724 { &hf_catapult_dct2000_bcch_transport
,
3726 "dct2000.bcch-transport", FT_UINT16
, BASE_DEC
, VALS(bcch_transport_vals
), 0x0,
3727 "BCCH Transport Channel", HFILL
3730 { &hf_catapult_dct2000_rlc_op
,
3732 "dct2000.rlc-op", FT_UINT8
, BASE_DEC
, VALS(rlc_op_vals
), 0x0,
3733 "RLC top-level op", HFILL
3736 { &hf_catapult_dct2000_rlc_channel_type
,
3737 { "RLC Logical Channel Type",
3738 "dct2000.rlc-logchan-type", FT_UINT8
, BASE_DEC
, VALS(rlc_logical_channel_vals
), 0x0,
3742 { &hf_catapult_dct2000_rlc_mui
,
3744 "dct2000.rlc-mui", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3748 { &hf_catapult_dct2000_rlc_cnf
,
3750 "dct2000.rlc-cnf", FT_BOOLEAN
, BASE_NONE
, TFS(&tfs_yes_no
), 0x0,
3754 { &hf_catapult_dct2000_rlc_discard_req
,
3756 "dct2000.rlc-discard-req", FT_BOOLEAN
, BASE_NONE
, TFS(&tfs_yes_no
), 0x0,
3757 "RLC Discard Req", HFILL
3760 { &hf_catapult_dct2000_carrier_type
,
3762 "dct2000.carrier-type", FT_UINT8
, BASE_DEC
, VALS(carrier_type_vals
), 0x0,
3766 { &hf_catapult_dct2000_cell_group
,
3768 "dct2000.cell-group", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3772 { &hf_catapult_dct2000_carrier_id
,
3774 "dct2000.carrier-id", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3779 { &hf_catapult_dct2000_security_mode_params
,
3780 { "Security Mode Params",
3781 "dct2000.security-mode-params", FT_NONE
, BASE_NONE
, NULL
, 0x0,
3785 { &hf_catapult_dct2000_uplink_sec_mode
,
3786 { "Uplink Security Mode",
3787 "dct2000.uplink-security-mode", FT_UINT8
, BASE_DEC
, VALS(security_mode_vals
), 0x0,
3791 { &hf_catapult_dct2000_downlink_sec_mode
,
3792 { "Downlink Security Mode",
3793 "dct2000.downlink-security-mode", FT_UINT8
, BASE_DEC
, VALS(security_mode_vals
), 0x0,
3797 { &hf_catapult_dct2000_ciphering_algorithm
,
3798 { "Ciphering Algorithm",
3799 "dct2000.ciphering-algorithm", FT_UINT8
, BASE_DEC
, VALS(ciphering_algorithm_vals
), 0x0,
3803 { &hf_catapult_dct2000_ciphering_key
,
3805 "dct2000.ciphering-key", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
3809 { &hf_catapult_dct2000_integrity_algorithm
,
3810 { "Integrity Algorithm",
3811 "dct2000.integrity-algorithm", FT_UINT8
, BASE_DEC
, VALS(integrity_algorithm_vals
), 0x0,
3815 { &hf_catapult_dct2000_integrity_key
,
3817 "dct2000.integrity-key", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
3822 { &hf_catapult_dct2000_lte_ccpri_opcode
,
3824 "dct2000.lte.ccpri.opcode", FT_UINT8
, BASE_DEC
, VALS(ccpri_opcode_vals
), 0x0,
3828 { &hf_catapult_dct2000_lte_ccpri_status
,
3830 "dct2000.lte.ccpri.status", FT_BOOLEAN
, BASE_NONE
, TFS(&tfs_error_ok
), 0x0,
3834 { &hf_catapult_dct2000_lte_ccpri_channel
,
3836 "dct2000.lte.ccpri.channel", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3841 { &hf_catapult_dct2000_lte_nas_rrc_opcode
,
3843 "dct2000.lte.nas-rrc.opcode", FT_UINT8
, BASE_DEC
, VALS(lte_nas_rrc_opcode_vals
), 0x0,
3847 { &hf_catapult_dct2000_lte_nas_rrc_establish_cause
,
3848 { "Establish Cause",
3849 "dct2000.lte.nas-rrc.establish-cause", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3853 { &hf_catapult_dct2000_lte_nas_rrc_priority
,
3855 "dct2000.lte.nas-rrc.priority", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3859 { &hf_catapult_dct2000_lte_nas_rrc_release_cause
,
3861 "dct2000.lte.nas-rrc.priority", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3865 { &hf_catapult_dct2000_nr_nas_s1ap_opcode
,
3866 { "NAS S1AP Opcode",
3867 "dct2000.nas-s1ap.opcode", FT_UINT8
, BASE_DEC
, VALS(nas_s1ap_opcode_vals
), 0x0,
3872 { &hf_catapult_dct2000_rbid
,
3874 "dct2000.rbid", FT_UINT8
, BASE_DEC
| BASE_EXT_STRING
, &rlc_rbid_vals_ext
, 0x0,
3875 "Channel (rbid)", HFILL
3878 { &hf_catapult_dct2000_ccch_id
,
3880 "dct2000.ccch-id", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3881 "CCCH Identifier", HFILL
3884 { &hf_catapult_dct2000_no_crc_error
,
3886 "dct2000.no-crc-error", FT_NONE
, BASE_NONE
, NULL
, 0x0,
3890 { &hf_catapult_dct2000_crc_error
,
3892 "dct2000.crc-error", FT_NONE
, BASE_NONE
, NULL
, 0x0,
3896 { &hf_catapult_dct2000_clear_tx_buffer
,
3897 { "Clear Tx Buffer",
3898 "dct2000.clear-tx-buffer", FT_NONE
, BASE_NONE
, NULL
, 0x0,
3902 { &hf_catapult_dct2000_buffer_occupancy
,
3903 { "Buffer Occupancy",
3904 "dct2000.buffer-occupancy", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3908 { &hf_catapult_dct2000_pdu_size
,
3910 "dct2000.pdu-size", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
3914 { &hf_catapult_dct2000_ueid_type
,
3916 "dct2000.ueid-type", FT_UINT8
, BASE_DEC
, VALS(ueid_type_vals
), 0x0,
3920 { &hf_catapult_dct2000_tx_priority
,
3922 "dct2000.tx-priority", FT_BOOLEAN
, BASE_NONE
, TFS(&tfs_high_normal
), 0x0,
3926 { &hf_catapult_dct2000_last_in_seg_set
,
3927 { "Last in seg set",
3928 "dct2000.last-in-seg-set", FT_BOOLEAN
, BASE_NONE
, TFS(&tfs_yes_no
), 0x0,
3932 { &hf_catapult_dct2000_rx_timing_deviation
,
3933 { "Tx Timing Deviation",
3934 "dct2000.rx-timing-deviation", FT_UINT32
, BASE_DEC
, NULL
, 0x0,
3938 { &hf_catapult_dct2000_transport_channel_type
,
3939 { "Transport Channel Type",
3940 "dct2000.transport_channel_type", FT_UINT8
, BASE_DEC
, VALS(transport_channel_type_vals
), 0x0,
3944 { &hf_catapult_dct2000_no_padding_bits
,
3945 { "Number of padding bits",
3946 "dct2000.number-of-padding-bits", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3951 { &hf_catapult_dct2000_rawtraffic_interface
,
3953 "dct2000.rawtraffic.interface", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
3957 { &hf_catapult_dct2000_rawtraffic_direction
,
3959 "dct2000.rawtraffic.direction", FT_UINT8
, BASE_DEC
, VALS(direction_vals
), 0x0,
3963 { &hf_catapult_dct2000_rawtraffic_pdu
,
3965 "dct2000.rawtraffic.pdu", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
3973 &ett_catapult_dct2000
,
3974 &ett_catapult_dct2000_ipprim
,
3975 &ett_catapult_dct2000_sctpprim
,
3976 &ett_catapult_dct2000_tty
,
3977 &ett_catapult_dct2000_security_mode_params
3980 static ei_register_info ei
[] = {
3981 { &ei_catapult_dct2000_lte_ccpri_status_error
, { "dct2000.lte.ccpri.status.error", PI_SEQUENCE
, PI_ERROR
, "CCPRI Indication has error status", EXPFILL
}},
3982 { &ei_catapult_dct2000_error_comment_expert
, { "dct2000.error-comment.expert", PI_SEQUENCE
, PI_ERROR
, "Formatted expert comment", EXPFILL
}},
3983 { &ei_catapult_dct2000_string_invalid
, { "dct2000.string.invalid", PI_MALFORMED
, PI_ERROR
, "String must contain an integer", EXPFILL
}}
3986 module_t
*catapult_dct2000_module
;
3987 expert_module_t
* expert_catapult_dct2000
;
3989 /* Register protocol. */
3990 proto_catapult_dct2000
= proto_register_protocol("Catapult DCT2000 packet",
3993 proto_register_field_array(proto_catapult_dct2000
, hf
, array_length(hf
));
3994 proto_register_subtree_array(ett
, array_length(ett
));
3995 expert_catapult_dct2000
= expert_register_protocol(proto_catapult_dct2000
);
3996 expert_register_field_array(expert_catapult_dct2000
, ei
, array_length(ei
));
3998 /* Allow dissector to find be found by name. */
3999 catapult_dct2000_handle
= register_dissector("dct2000", dissect_catapult_dct2000
, proto_catapult_dct2000
);
4002 catapult_dct2000_module
= prefs_register_protocol(proto_catapult_dct2000
, NULL
);
4004 /* This preference no longer supported (introduces linkage dependency between
4005 dissectors and wiretap) */
4006 prefs_register_obsolete_preference(catapult_dct2000_module
, "board_ports_only");
4007 prefs_register_obsolete_preference(catapult_dct2000_module
, "decode_lte_s1ap");
4009 /* Determines whether for not-handled protocols we should try to parse it if:
4010 - it looks like it's embedded in an ipprim message, AND
4011 - the DCT2000 protocol name can be matched to a Wireshark dissector name */
4012 prefs_register_bool_preference(catapult_dct2000_module
, "ipprim_heuristic",
4013 "Use IP Primitive heuristic",
4014 "If a payload looks like it's embedded in an "
4015 "IP primitive message, and there is a Wireshark "
4016 "dissector matching the DCT2000 protocol name, "
4017 "try parsing the payload using that dissector",
4018 &catapult_dct2000_try_ipprim_heuristic
);
4020 /* Determines whether for not-handled protocols we should try to parse it if:
4021 - it looks like it's embedded in an sctpprim message, AND
4022 - the DCT2000 protocol name can be matched to a Wireshark dissector name */
4023 prefs_register_bool_preference(catapult_dct2000_module
, "sctpprim_heuristic",
4024 "Use SCTP Primitive heuristic",
4025 "If a payload looks like it's embedded in an "
4026 "SCTP primitive message, and there is a Wireshark "
4027 "dissector matching the DCT2000 protocol name, "
4028 "try parsing the payload using that dissector",
4029 &catapult_dct2000_try_sctpprim_heuristic
);
4031 /* Determines whether LTE RRC messages should be dissected */
4032 prefs_register_bool_preference(catapult_dct2000_module
, "decode_lte_rrc",
4033 "Attempt to decode LTE RRC frames",
4034 "When set, attempt to decode LTE RRC frames. "
4035 "Note that this won't affect other protocols "
4036 "that also call the LTE RRC dissector",
4037 &catapult_dct2000_dissect_lte_rrc
);
4039 /* Determines whether out-of-band messages should dissected */
4040 prefs_register_bool_preference(catapult_dct2000_module
, "decode_mac_lte_oob_messages",
4041 "Look for out-of-band LTE MAC events messages in comments",
4042 "When set, look for formatted messages indicating "
4043 "specific events. This may be quite slow, so should "
4044 "be disabled if LTE MAC is not being analysed",
4045 &catapult_dct2000_dissect_mac_lte_oob_messages
);
4047 /* Whether old protocol names conversions should be checked */
4048 prefs_register_bool_preference(catapult_dct2000_module
, "convert_old_protocol_names",
4049 "Convert old protocol names to wireshark dissector names",
4050 "When set, look for some older protocol names so that"
4051 "they may be matched with wireshark dissectors.",
4052 &catapult_dct2000_dissect_old_protocol_names
);
4054 /* Determines if the protocol field in the DCT2000 shall be used to lookup for dissector */
4055 prefs_register_bool_preference(catapult_dct2000_module
, "use_protocol_name_as_dissector_name",
4056 "Look for a dissector using the protocol name in the "
4058 "When set, if there is a Wireshark dissector matching "
4059 "the protocol name, it will parse the PDU using "
4060 "that dissector. This may be slow, so should be "
4061 "disabled unless you are using this feature.",
4062 &catapult_dct2000_use_protocol_name_as_dissector_name
);
4066 * Editor modelines - https://www.wireshark.org/tools/modelines.html
4071 * indent-tabs-mode: nil
4074 * vi: set shiftwidth=4 tabstop=8 expandtab:
4075 * :indentSize=4:tabSize=8:noTabs=true: