Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-catapult-dct2000.c
blobffbf5cce8b5777f9eb232bbf01e02225c64779d9
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
9 */
11 #include "config.h"
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>
20 #include <epan/tfs.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[] = {
152 { 0, "Sent" },
153 { 1, "Received" },
154 { 0, NULL },
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" },
168 { 0, NULL },
171 static const value_string bcch_transport_vals[] = {
172 { BCH_TRANSPORT, "BCH" },
173 { DLSCH_TRANSPORT, "DLSCH" },
174 { 0, NULL },
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]"},
196 { 0, NULL }
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"},
205 { 0, NULL}
209 #define CCPRI_REQ 1
210 #define CCPRI_IND 2
212 static const value_string ccpri_opcode_vals[] = {
213 { CCPRI_REQ, "REQUEST"},
214 { CCPRI_IND, "INDICATION"},
215 { 0, NULL}
218 static const value_string rlc_rbid_vals[] = {
219 { 1, "DCH1"},
220 { 2, "DCH2"},
221 { 3, "DCH3"},
222 { 4, "DCH4"},
223 { 5, "DCH5"},
224 { 6, "DCH6"},
225 { 7, "DCH7"},
226 { 8, "DCH8"},
227 { 9, "DCH9"},
228 { 10, "DCH10"},
229 { 11, "DCH11"},
230 { 12, "DCH12"},
231 { 13, "DCH13"},
232 { 14, "DCH14"},
233 { 15, "DCH15"},
234 { 17, "BCCH"},
235 { 18, "CCCH"},
236 { 19, "PCCH"},
237 { 20, "SHCCH"},
238 { 21, "CTCH"},
239 { 23, "MCCH"},
240 { 24, "MSCH"},
241 { 25, "MTCH"},
242 { 0, NULL}
244 static value_string_ext rlc_rbid_vals_ext = VALUE_STRING_EXT_INIT(rlc_rbid_vals);
246 static const value_string ueid_type_vals[] = {
247 { 0, "URNTI"},
248 { 1, "CRNTI"},
249 { 0, NULL}
252 static const value_string transport_channel_type_vals[] = {
253 { 1, "RACH"},
254 { 2, "FACH"},
255 { 3, "BCH"},
256 { 4, "PCH"},
257 { 6, "USCH"},
258 { 7, "DSCH"},
259 { 8, "DCH"},
260 { 9, "HSDSCH"},
261 { 10, "EDCH"},
262 { 0, NULL}
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"},
275 { 0, NULL}
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"},
285 { 0, NULL}
289 /* Distinguish between similar 4G or 5G protocols */
290 enum LTE_or_NR {
291 LTE,
295 static const value_string carrier_type_vals[] = {
296 { 0, "LTE"},
297 { 1, "CatM"},
298 { 2, "NBIoT"},
299 { 3, "NR"},
300 { 0, NULL}
304 static const value_string security_mode_vals[] = {
305 { 0, "None"},
306 { 1, "Integrity only"},
307 { 2, "Ciphering and Integrity"},
308 { 0, NULL}
311 static const value_string ciphering_algorithm_vals[] = {
312 { 0, "EEA0"},
313 { 1, "EEA1"},
314 { 2, "EEA2"},
315 { 3, "EEA3"},
316 { 0, NULL}
319 static const value_string integrity_algorithm_vals[] = {
320 { 0, "EIA0"},
321 { 1, "EIA1"},
322 { 2, "EIA2"},
323 { 3, "EIA3"},
324 { 0, NULL}
328 #define MAX_OUTHDR_VALUES 32
330 extern int proto_fp;
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)
371 return 1;
373 else
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)
389 uint8_t length;
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 */
396 switch (tag) {
397 case 0x23: /* UDP data request */
398 case 0x24: /* UDP data indication */
399 *type_of_port = PT_UDP;
400 break;
401 case 0x45: /* TCP data request */
402 case 0x46: /* TCP data indication */
403 *type_of_port = PT_TCP;
404 break;
405 default:
406 return false;
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;
419 return true;
421 else {
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;
432 else {
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;
442 else {
443 *source_port_offset = offset + *source_addr_length;
447 else
448 if (tag == 0x32) {
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;
456 else {
457 *dest_addr_offset = offset;
458 *dest_addr_length = length;
462 else
463 if (tag == 0x33 && length == 2) {
464 /* Get local port */
465 if (direction == 0) {
466 /* Sent from local, so source */
467 *source_port_offset = offset;
469 else {
470 *dest_port_offset = offset;
473 else
474 if (tag == 0x36 && length == 2) {
475 /* Get conn_id */
476 *conn_id_offset = offset;
479 /* Skip the length of the indicated value */
480 offset += length;
484 /* No data found... */
485 return false;
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++);
501 uint8_t tag;
502 uint8_t first_length_byte;
504 /* Only accept interested in data requests or indications */
505 switch (first_tag) {
506 case 0x04: /* data request */
507 case 0x62: /* data indication */
508 break;
509 default:
510 return false;
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? */
522 if (tag == 0x19) {
523 *data_offset = offset;
524 return true;
526 else {
527 /* Skip length field */
528 offset++;
529 switch (tag) {
530 case 0x0a: /* destPort */
531 *dest_port_offset = offset;
532 offset += 2;
533 break;
535 case 0x01: /* sctpInstanceNum */
536 case 0x1e: /* strseqnum */
537 case 0x0d: /* streamnum */
538 offset += 2;
539 continue;
541 case 0x09: /* ipv4Address */
542 *dest_addr_offset = offset;
543 *dest_addr_length = 4;
544 offset += 4;
545 break;
547 case 0x1d:
548 case 0x0c: /* payloadType */
549 offset += 4;
550 continue;
552 default:
553 /* Fail if not a known header field */
554 return false;
559 /* No data found... */
560 return false;
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)
571 uint16_t tag = 0;
572 uint16_t length = 0;
573 int offset = *data_offset;
575 /* Get the sctpprim (2 byte) command code. */
576 uint16_t top_tag = tvb_get_ntohs(tvb, offset);
577 offset += 2;
579 /* Only interested in data requests or indications */
580 if ((top_tag != 0x0400) && /* SendDataReq */
581 (top_tag != 0x6200)) { /* DataInd */
582 return false;
585 /* Overall length field is next 2 bytes */
586 offset += 2;
588 /* Rx/Tx ops have different formats */
590 /*****************/
591 /* DataInd */
592 if (top_tag == 0x6200) {
593 /* Next 2 bytes are associate ID */
594 offset += 2;
596 /* Next 2 bytes are destination port */
597 *dest_port_offset = offset;
598 offset += 2;
600 /* Destination address should follow - check tag */
601 tag = tvb_get_ntohs(tvb, offset);
602 if (tag != 0x0900) {
603 return false;
605 else {
606 /* Skip tag */
607 offset += 2;
609 /* Length field */
610 length = tvb_get_ntohs(tvb, offset) / 2;
611 if ((length != 4) && (length != 16))
613 return false;
615 offset += 2;
617 /* Address data is here */
618 *dest_addr_offset = offset;
619 *dest_addr_length = length;
621 offset += 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);
628 else {
629 return false;
632 /* Data should now be here */
633 tag = tvb_get_ntohs(tvb, offset);
634 offset += 2;
635 if (tag == 0x1900) {
636 /* 2-byte length field */
637 offset += 2;
639 /* Data is here!!! */
640 *data_offset = offset;
641 return true;
643 else {
644 return false;
648 /***********************************/
649 /* SendDataReq (top_tag == 0x0400) */
650 else {
651 /* AssociateId should follow - check tag */
652 tag = tvb_get_ntohs(tvb, offset);
653 if (tag != 0x2400) {
654 return false;
656 else {
657 /* Skip tag */
658 offset += 2;
660 /* Skip 2-byte value */
661 offset += 2;
664 /* Get tag */
665 tag = tvb_get_ntohs(tvb, offset);
666 offset += 2;
668 /* Some optional params */
669 while ((tag != 0x0c00) && (tvb_reported_length_remaining(tvb, offset) > 4)) {
670 switch (tag) {
671 case 0x0900: /* Dest address */
672 /* Length field */
673 length = tvb_get_ntohs(tvb, offset) / 2;
674 if ((length != 4) && (length != 16)) {
675 return false;
677 offset += 2;
679 /* Address data is here */
680 *dest_addr_offset = offset;
681 *dest_addr_length = length;
683 offset += length;
684 break;
686 case 0x0a00: /* Dest port number */
687 *dest_port_offset = offset;
688 offset += 2;
689 break;
691 case 0x0d00: /* StreamNum */
692 offset += 2;
693 break;
696 default:
697 return false;
700 /* Get the next tag */
701 tag = tvb_get_ntohs(tvb, offset);
702 offset += 2;
706 /* Mandatory payload type */
707 if (tag != 0x0c00) {
708 return false;
710 length = tvb_get_ntohs(tvb, offset) / 2;
711 offset += 2;
712 offset += length;
715 /* Optional options */
716 tag = tvb_get_ntohs(tvb, offset);
717 offset += 2;
718 if (tag == 0x0b00) {
719 length = tvb_get_ntohs(tvb, offset) / 2;
720 offset += 2;
722 offset += length;
724 /* Get next tag */
725 tag = tvb_get_ntohs(tvb, offset);
726 offset += 2;
730 /* Data should now be here!! */
731 if (tag == 0x1900) {
732 /* 2-byte length field */
733 offset += 2;
735 /* Data is here!!! */
736 *data_offset = offset;
737 return true;
739 else {
740 return false;
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)
755 uint8_t tag;
756 bool ueid_set = false, rbid_set=false;
757 uint32_t ueid = 0;
758 uint8_t rbid = 0;
759 uint8_t length;
760 tvbuff_t *rlc_tvb;
761 dissector_handle_t rlc_umts_handle = 0;
763 /* Top-level opcode */
764 tag = tvb_get_uint8(tvb, offset++);
765 switch (tag) {
766 case 0xc0: /* mac data request */
767 case 0xc1: /* mac data indication */
768 break;
770 default:
771 /* No data to dissect */
772 return;
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++);
778 switch (tag) {
779 case 0x72: /* UE Id */
780 ueid = tvb_get_ntohl(tvb, offset);
781 offset += 2;
782 proto_tree_add_item(tree, hf_catapult_dct2000_ueid, tvb, offset, 2, ENC_BIG_ENDIAN);
783 offset += 2;
784 ueid_set = true;
785 break;
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);
790 offset++;
791 rbid_set = true;
792 break;
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);
796 offset++;
797 rbid = 18;
798 break;
799 case 0xc4: /* No CRC error */
800 proto_tree_add_item(tree, hf_catapult_dct2000_no_crc_error, tvb, offset-1, 1, ENC_NA);
801 break;
802 case 0xc5: /* CRC error */
803 proto_tree_add_item(tree, hf_catapult_dct2000_crc_error, tvb, offset-1, 1, ENC_NA);
804 break;
805 case 0xf7: /* Clear Tx Buffer */
806 proto_tree_add_item(tree, hf_catapult_dct2000_clear_tx_buffer, tvb, offset-1, 1, ENC_NA);
807 break;
809 case 0x41: /* Data !!! */
810 offset += skipASNLength(tvb_get_uint8(tvb, offset));
811 break;
813 default:
814 /* For other fields, just skip length and following data */
815 length = tvb_get_uint8(tvb, offset++);
816 switch (tag) {
817 case 0x42: /* Buffer Occupancy */
818 proto_tree_add_item(tree, hf_catapult_dct2000_buffer_occupancy, tvb, offset, length, ENC_BIG_ENDIAN);
819 break;
820 case 0x49: /* PDU Size */
821 proto_tree_add_item(tree, hf_catapult_dct2000_pdu_size, tvb, offset, 2, ENC_LITTLE_ENDIAN);
822 break;
823 case 0x47: /* UEId type */
824 proto_tree_add_item(tree, hf_catapult_dct2000_ueid_type, tvb, offset, 1, ENC_BIG_ENDIAN);
825 break;
826 case 0x4e: /* Tx Priority */
827 proto_tree_add_item(tree, hf_catapult_dct2000_tx_priority, tvb, offset, 1, ENC_BIG_ENDIAN);
828 break;
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);
831 break;
832 case 0x43: /* Rx timing deviation */
833 proto_tree_add_item(tree, hf_catapult_dct2000_rx_timing_deviation, tvb, offset, 1, ENC_BIG_ENDIAN);
834 break;
835 case 0x46: /* Transport channel type */
836 proto_tree_add_item(tree, hf_catapult_dct2000_transport_channel_type, tvb, offset, 1, ENC_BIG_ENDIAN);
837 break;
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);
840 break;
842 default:
843 break;
847 offset += length;
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 */
857 switch (rbid) {
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:
861 /* DCH channels. */
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");
865 break;
866 case 18:
867 rlc_umts_handle = find_dissector("rlc.ccch");
868 break;
869 case 21:
870 rlc_umts_handle = find_dissector("rlc.ctch");
871 break;
873 default:
874 /* Give up here */
875 return;
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)
888 static char key[33];
889 for (int n=0; n < 16; n++) {
890 snprintf(&key[n*2], 33-(n*2), "%02x", tvb_get_uint8(tvb, offset+n));
892 return key;
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)
902 uint8_t opcode, tag;
903 dissector_handle_t protocol_handle = 0;
904 bool isUplink = false;
905 LogicalChannelType logicalChannelType;
906 uint16_t cell_id;
907 uint8_t bcch_transport = 0;
908 uint32_t ueid = 0;
909 tvbuff_t *rrc_tvb;
911 /* Top-level opcode */
912 opcode = tvb_get_uint8(tvb, offset++);
913 switch (opcode) {
914 case 0x00: /* Data_Req_UE */
915 case 0x05: /* Data_Req_UE_SM */
916 case 0x04: /* Data_Ind_eNodeB */
917 isUplink = true;
918 break;
920 case 0x02: /* Data_Req_eNodeB */
921 case 0x03: /* Data_Ind_UE */
922 case 0x07: /* Data_Ind_UE_SM */
923 isUplink = false;
924 break;
926 default:
927 /* Unexpected opcode tag! */
928 return;
931 /* Skip length */
932 offset += skipASNLength(tvb_get_uint8(tvb, offset));
934 /* Get next tag */
935 tag = tvb_get_uint8(tvb, offset++);
936 switch (tag) {
937 case 0x12: /* UE_Id_LCId */
939 /* Dedicated channel info */
941 /* Skip length */
942 offset++;
944 logicalChannelType = Channel_DCCH;
946 /* UEId */
947 proto_tree_add_item_ret_uint(tree, hf_catapult_dct2000_ueid, tvb, offset, 2, ENC_BIG_ENDIAN, &ueid);
948 offset += 2;
950 /* Get tag of channel type */
951 tag = tvb_get_uint8(tvb, offset++);
953 switch (tag) {
954 case 0:
955 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);
960 offset++;
961 break;
962 case 1:
963 offset++;
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);
968 offset++;
969 break;
971 default:
972 /* Unexpected channel type */
973 return;
976 break;
979 case 0x1a: /* Cell_LCId */
981 /* Common channel info */
983 /* Skip length */
984 offset++;
986 /* Cell-id */
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);
990 offset += 2;
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);
996 offset++;
998 /* Won't be seen if RRC decoder is called... */
999 col_append_fstr(pinfo->cinfo, COL_INFO, " cell-id=%u %s",
1000 cell_id,
1001 val_to_str_const(logicalChannelType, rlc_logical_channel_vals,
1002 "UNKNOWN-CHANNEL"));
1005 switch (logicalChannelType) {
1006 case Channel_BCCH:
1007 /* Skip length */
1008 offset++;
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);
1014 offset++;
1015 break;
1017 case Channel_CCCH:
1018 /* Skip length */
1019 offset++;
1021 /* UEId */
1022 proto_tree_add_item(tree, hf_catapult_dct2000_ueid,
1023 tvb, offset, 2, ENC_BIG_ENDIAN);
1024 offset += 2;
1025 break;
1027 default:
1028 break;
1030 break;
1032 default:
1033 /* Unexpected tag */
1034 return;
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);
1042 offset++;
1045 /* Optional Carrier Type */
1046 if (tvb_get_uint8(tvb, offset)==0x20) {
1047 offset += 2;
1048 proto_tree_add_item(tree, hf_catapult_dct2000_carrier_type,
1049 tvb, offset, 1, ENC_BIG_ENDIAN);
1050 offset++;
1053 /* Optional Cell Group */
1054 if (tvb_get_uint8(tvb, offset)==0x22) {
1055 offset += 2;
1056 proto_tree_add_item(tree, hf_catapult_dct2000_cell_group,
1057 tvb, offset, 1, ENC_BIG_ENDIAN);
1058 offset++;
1061 if (opcode == 0x07) {
1062 /* Data_Ind_UE_SM - 1 byte MAC */
1063 offset++;
1065 else if (opcode == 0x05) {
1066 /* Data_Req_UE_SM - SecurityMode Params */
1067 /* N.B. DRB keys do not get configured here.. */
1068 offset++; /* tag */
1069 uint8_t len = tvb_get_uint8(tvb, offset++); /* length */
1071 /* Uplink Sec Mode */
1072 proto_item *sc_ti;
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);
1086 if (len > 2) {
1087 offset++; /* tag Should be 0x21 */
1088 offset++; /* len */
1090 tag = tvb_get_uint8(tvb, offset++);
1091 if (tag == 0x25) {
1092 /* Cell Group Id */
1093 offset++;
1094 proto_tree_add_item(sc_tree, hf_catapult_dct2000_cell_group,
1095 tvb, offset, 1, ENC_BIG_ENDIAN);
1098 /* Optional cryptParams */
1099 if (tag == 0x2) {
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) */
1110 if (len > 3) {
1111 /* Skip tag and length */
1112 offset += 2;
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);
1121 else {
1122 set_pdcp_lte_rrc_ciphering_key(ueid, key, pinfo->num);
1125 offset += 16;
1128 else {
1129 offset--;
1132 /* Now should be Auth params (required) */
1133 uint32_t integrity_algorithm;
1134 /* Skip tag */
1135 offset++;
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 */
1145 if (len > 3) {
1146 /* Skip tag and length */
1147 offset += 2;
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);
1156 else {
1157 set_pdcp_lte_rrc_integrity_key(ueid, key, pinfo->num);
1160 offset += 16;
1165 /* Optional data tag may follow */
1166 if (!tvb_reported_length_remaining(tvb, offset)) {
1167 return;
1169 tag = tvb_get_uint8(tvb, offset++);
1170 if (tag != 0xaa) {
1171 return;
1174 /* Skip length */
1175 offset += skipASNLength(tvb_get_uint8(tvb, offset));
1177 /* Look up dissector handle corresponding to direction and channel type */
1178 if (isUplink) {
1180 /* Uplink channel types */
1181 switch (logicalChannelType) {
1182 case Channel_DCCH:
1183 if (lte_or_nr == LTE) {
1184 protocol_handle = find_dissector("lte_rrc.ul_dcch");
1186 else {
1187 protocol_handle = find_dissector("nr-rrc.ul.dcch");
1189 break;
1190 case Channel_CCCH:
1191 if (lte_or_nr == LTE) {
1192 protocol_handle = find_dissector("lte_rrc.ul_ccch");
1194 else {
1195 if (tvb_captured_length_remaining(tvb, offset) == 6) {
1196 protocol_handle = find_dissector("nr-rrc.ul.ccch");
1198 else {
1199 /* Should be 8 bytes.. */
1200 protocol_handle = find_dissector("nr-rrc.ul.ccch1");
1203 break;
1205 default:
1206 /* Unknown Uplink channel type */
1207 break;
1209 } else {
1211 /* Downlink channel types */
1212 switch (logicalChannelType) {
1213 case Channel_DCCH:
1214 if (lte_or_nr == LTE) {
1215 protocol_handle = find_dissector("lte_rrc.dl_dcch");
1217 else {
1218 protocol_handle = find_dissector("nr-rrc.dl.dcch");
1220 break;
1221 case Channel_CCCH:
1222 if (lte_or_nr == LTE) {
1223 protocol_handle = find_dissector("lte_rrc.dl_ccch");
1225 else {
1226 protocol_handle = find_dissector("nr-rrc.dl.ccch");
1228 break;
1229 case Channel_PCCH:
1230 if (lte_or_nr == LTE) {
1231 protocol_handle = find_dissector("lte_rrc.pcch");
1233 else {
1234 protocol_handle = find_dissector("nr-rrc.pcch");
1236 break;
1237 case Channel_BCCH:
1238 if (bcch_transport == 1) {
1239 if (lte_or_nr == LTE) {
1240 protocol_handle = find_dissector("lte_rrc.bcch_bch");
1242 else {
1243 protocol_handle = find_dissector("nr-rrc.bcch.bch");
1246 else {
1247 if (lte_or_nr == LTE) {
1248 protocol_handle = find_dissector("lte_rrc.bcch_dl_sch");
1250 else {
1251 protocol_handle = find_dissector("nr-rrc.bcch.dl.sch");
1254 break;
1256 default:
1257 /* Unknown Downlink channel type */
1258 break;
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 */
1267 if (ueid) {
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)
1292 uint8_t opcode;
1293 uint8_t tag;
1294 tvbuff_t *ccpri_tvb;
1295 dissector_handle_t protocol_handle = 0;
1296 uint16_t length;
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 */
1303 offset += 2;
1305 /* Cell-id */
1306 proto_tree_add_item(tree, hf_catapult_dct2000_cellid,
1307 tvb, offset, 2, ENC_BIG_ENDIAN);
1308 offset += 2;
1310 /* Status (ind only) */
1311 if (opcode == 2) {
1312 proto_item *ti;
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);
1316 offset++;
1318 if (status != 0) {
1319 expert_add_info(pinfo, ti, &ei_catapult_dct2000_lte_ccpri_status_error);
1324 /* Channel ID */
1325 proto_tree_add_item(tree, hf_catapult_dct2000_lte_ccpri_channel,
1326 tvb, offset, 1, ENC_BIG_ENDIAN);
1327 offset++;
1329 /* Data tag must follow */
1330 tag = tvb_get_uint8(tvb, offset++);
1331 if (tag != 2) {
1332 return;
1335 /* Skip length */
1336 length = tvb_get_ntohs(tvb, offset);
1337 offset += 2;
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)
1359 uint8_t opcode;
1360 uint8_t tag;
1361 struct pdcp_lte_info *p_pdcp_lte_info;
1362 tvbuff_t *pdcp_lte_tvb;
1363 uint16_t ueid;
1364 uint8_t channelId;
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 */
1370 return;
1373 /* Top-level opcode */
1374 opcode = tvb_get_uint8(tvb, offset);
1375 if (tree) {
1376 proto_tree_add_item(tree, hf_catapult_dct2000_rlc_op, tvb, offset, 1, ENC_BIG_ENDIAN);
1378 offset++;
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 */
1383 switch (opcode) {
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;
1388 break;
1390 default:
1391 p_pdcp_lte_info->direction = DIRECTION_DOWNLINK;
1394 /* Parse header */
1395 switch (opcode) {
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:
1403 /* Get next tag */
1404 tag = tvb_get_uint8(tvb, offset++);
1405 switch (tag) {
1406 case 0x10: /* UE_Id_LCId */
1408 /* Dedicated channel info */
1410 /* Length will fit in one byte here */
1411 offset++;
1413 p_pdcp_lte_info->channelType = Channel_DCCH;
1415 /* UEId */
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,
1419 " UEId=%u", ueid);
1420 p_pdcp_lte_info->ueid = ueid;
1421 offset += 2;
1423 /* Get tag of channel type */
1424 tag = tvb_get_uint8(tvb, offset++);
1426 switch (tag) {
1427 case 0:
1428 offset++;
1429 channelId = tvb_get_uint8(tvb, offset);
1430 col_append_fstr(pinfo->cinfo, COL_INFO, " SRB:%u",
1431 channelId);
1432 proto_tree_add_item(tree, hf_catapult_dct2000_srbid,
1433 tvb, offset++, 1, ENC_BIG_ENDIAN);
1434 p_pdcp_lte_info->channelId = channelId;
1435 break;
1436 case 1:
1437 offset++;
1438 channelId = tvb_get_uint8(tvb, offset);
1439 col_append_fstr(pinfo->cinfo, COL_INFO, " DRB:%u",
1440 channelId);
1441 proto_tree_add_item(tree, hf_catapult_dct2000_drbid,
1442 tvb, offset++, 1, ENC_BIG_ENDIAN);
1443 p_pdcp_lte_info->channelId = channelId;
1444 break;
1446 default:
1447 /* Unexpected channel type */
1448 return;
1450 break;
1452 case 0x1a: /* Cell_LCId */
1454 /* Common channel info */
1456 /* Skip length */
1457 offset++;
1459 /* Cell-id */
1460 proto_tree_add_item(tree, hf_catapult_dct2000_cellid,
1461 tvb, offset, 2, ENC_BIG_ENDIAN);
1462 offset += 2;
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) {
1473 case Channel_BCCH:
1474 /* Skip length */
1475 offset++;
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);
1481 offset++;
1482 break;
1484 case Channel_CCCH:
1485 /* Skip length */
1486 offset++;
1488 /* UEId */
1489 proto_tree_add_item(tree, hf_catapult_dct2000_ueid,
1490 tvb, offset, 2, ENC_BIG_ENDIAN);
1491 ueid = tvb_get_ntohs(tvb, offset);
1492 offset += 2;
1494 col_append_fstr(pinfo->cinfo, COL_INFO, " UEId=%u", ueid);
1495 break;
1497 default:
1498 break;
1500 break;
1502 default:
1503 /* Unexpected tag */
1504 return;
1507 /* Other optional fields may follow */
1508 tag = tvb_get_uint8(tvb, offset++);
1509 while ((tag != 0x41) && (tvb_reported_length_remaining(tvb, offset) > 2)) {
1511 if (tag == 0x35) {
1512 /* This is MUI */
1513 offset++;
1514 proto_tree_add_item(tree, hf_catapult_dct2000_rlc_mui,
1515 tvb, offset, 2, ENC_BIG_ENDIAN);
1516 offset += 2;
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);
1522 offset++;
1525 else if (tag == 0x45) {
1526 /* Discard Req */
1527 offset++;
1528 proto_tree_add_item(tree, hf_catapult_dct2000_rlc_discard_req,
1529 tvb, offset, 1, ENC_NA);
1530 offset++;
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);
1544 break;
1546 default:
1547 return;
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");
1562 else
1563 if (strncmp(protocol_name, "gtpv2_r", 7) == 0) {
1564 return find_dissector("gtpv2");
1566 else
1567 if (strncmp(protocol_name, "s1ap", 4) == 0) {
1568 return find_dissector("s1ap");
1570 else
1571 if (strncmp(protocol_name, "x2ap_r", 6) == 0) {
1572 return find_dissector("x2ap");
1574 else
1575 if (strncmp(protocol_name, "xnap_r1", 7) == 0) {
1576 return find_dissector("xnap");
1578 else
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");
1589 else
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");
1598 else
1599 if ((strncmp(protocol_name, "fp_r", 4) == 0) ||
1600 (strcmp(protocol_name, "fpiur_r5") == 0)) {
1602 return find_dissector("fp");
1604 else
1605 if (strncmp(protocol_name, "iuup_rtp_r", strlen("iuup_rtp_r")) == 0) {
1606 return find_dissector("rtp");
1608 else
1609 if (strcmp(protocol_name, "sipt") == 0) {
1610 return find_dissector("sip");
1612 else
1613 if (strncmp(protocol_name, "nbap_sctp", strlen("nbap_sctp")) == 0) {
1614 return find_dissector("nbap");
1616 else
1617 if (strcmp(protocol_name, "dhcpv4") == 0) {
1618 return find_dissector("dhcp");
1620 else
1621 if (strcmp(protocol_name, "wimax") == 0) {
1622 return find_dissector("wimaxasncp");
1624 else
1625 if (strncmp(protocol_name, "sabp", strlen("sabp")) == 0) {
1626 return find_dissector("sabp");
1628 else
1629 if (strcmp(protocol_name, "wtp") == 0) {
1630 return find_dissector("wtp-udp");
1632 else
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)
1646 int n = 0;
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;
1657 unsigned d;
1659 /* Find digits */
1660 for ( ; (n < outhdr_string_len) && (number_digits < MAX_OUTHDR_VALUES); n++) {
1661 if (!g_ascii_isdigit(outhdr_string[n])) {
1662 break;
1664 else {
1665 digit_array[number_digits++] = outhdr_string[n] - '0';
1669 if (number_digits == 0) {
1670 /* No more numbers left */
1671 break;
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);
1677 multiplier *= 10;
1679 outhdr_values[outhdr_values_found++] = number;
1681 /* Skip comma */
1682 n++;
1684 return outhdr_values_found;
1689 /* Fill in an FP packet info struct and attach it to the packet for the FP
1690 dissector to use */
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)
1695 unsigned i = 0;
1696 int chan;
1697 unsigned tf_start, num_chans_start;
1698 int node_type;
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) {
1704 return;
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)) {
1714 return;
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;
1739 else {
1740 /* Really shouldn't get here */
1741 DISSECTOR_ASSERT_NOT_REACHED();
1742 return;
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) {
1748 case 6:
1749 if (variant < 256) {
1750 calculated_variant = variant;
1752 else {
1753 calculated_variant = variant / 256;
1756 switch (calculated_variant) {
1757 case 1:
1758 p_fp_info->release_year = 2005;
1759 p_fp_info->release_month = 6;
1760 break;
1761 case 2:
1762 p_fp_info->release_year = 2005;
1763 p_fp_info->release_month = 9;
1764 break;
1765 case 3:
1766 default:
1767 p_fp_info->release_year = 2006;
1768 p_fp_info->release_month = 3;
1769 break;
1771 break;
1772 case 7:
1773 p_fp_info->release_year = 2008;
1774 p_fp_info->release_month = 3;
1775 break;
1777 case 8:
1778 p_fp_info->release_year = 2010;
1779 p_fp_info->release_month = 6;
1780 break;
1783 default:
1784 p_fp_info->release_year = 0;
1785 p_fp_info->release_month = 0;
1789 /* Channel type */
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;
1816 else {
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);
1828 return;
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 */
1855 tf_start = i;
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];
1859 } else {
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];
1869 } else {
1870 p_fp_info->chan_num_tbs[chan] = 0;
1874 /* EDCH info */
1875 else {
1876 int n;
1878 p_fp_info->no_ddi_entries = outhdr_values[i++];
1880 /* DDI values */
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++];
1884 } else {
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++];
1893 } else {
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];
1901 } else {
1902 p_fp_info->edch_type = 0;
1905 else {
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
1919 dissector to use */
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) {
1929 return;
1932 /* Check that the number of outhdr values looks correct */
1933 if (outhdr_values_found != 2) {
1934 return;
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;
1952 /* Mode. */
1953 switch (outhdr_values[1]) {
1954 case 1:
1955 p_rlc_info->mode[0] = RLC_TM;
1956 break;
1957 case 2:
1958 p_rlc_info->mode[0] = RLC_UM;
1959 break;
1960 case 3:
1961 p_rlc_info->mode[0] = RLC_AM;
1962 break;
1963 case 4:
1964 p_rlc_info->mode[0] = RLC_UM;
1965 p_rlc_info->ciphered[0] = true;
1966 break;
1967 case 5:
1968 p_rlc_info->mode[0] = RLC_AM;
1969 p_rlc_info->ciphered[0] = true;
1970 break;
1971 default:
1972 return;
1975 /* rbid. TODO: does this need conversion? */
1976 p_rlc_info->rbid[0] = rbid;
1978 /* li_size */
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
1995 dissector to use */
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;
1999 unsigned int i = 0;
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) {
2004 return;
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;
2020 else {
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
2040 else {
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
2069 else {
2070 /* Uplink */
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 */
2077 i++; // 15
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) {
2111 /* Carrier ID */
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) {
2121 /* UE Type */
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
2130 dissector to use */
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;
2135 unsigned int i = 0;
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) {
2140 return;
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
2160 dissector to use */
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;
2165 unsigned int i = 0;
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) {
2170 return;
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)
2202 int next_offset;
2203 proto_tree *tty_tree;
2204 proto_item *ti;
2205 int lines = 0;
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,
2221 tvb, offset,
2222 linelen, string,
2223 "%s", string);
2225 else {
2226 /* Otherwise show as $hex */
2227 int n, idx;
2228 char *hex_string;
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;
2242 lines++;
2244 /* Show first line in info column */
2245 if (lines == 1) {
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 */
2255 if (lines != 0) {
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,
2264 const char *string)
2266 unsigned number_of_ues;
2267 unsigned ueids[MAX_SRs];
2268 unsigned rntis[MAX_SRs];
2269 unsigned rapid;
2270 unsigned rach_attempt_number;
2271 unsigned temp;
2272 mac_lte_oob_event oob_event;
2273 struct mac_lte_info *p_mac_lte_info;
2274 uint16_t n;
2276 /* Current strings of interest begin with ">> ", so if don't see, avoid sscanf() calls. */
2277 if (strncmp(string, ">> ", 3) != 0) {
2278 return;
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;
2310 else {
2311 /* This is an error - shouldn't happen */
2312 return;
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 */
2318 number_of_ues = n;
2319 break;
2325 /* SR failures */
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 */
2332 else return;
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;
2348 break;
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;
2356 break;
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;
2361 break;
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);
2375 static uint8_t
2376 hex_from_char(char c)
2378 if ((c >= '0') && (c <= '9')) {
2379 return c - '0';
2382 if ((c >= 'a') && (c <= 'f')) {
2383 return 0x0a + (c - 'a');
2386 /* Not a valid hex string character */
2387 return 0xff;
2391 /*****************************************/
2392 /* Main dissection function. */
2393 /*****************************************/
2394 static int
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;
2399 int offset = 0;
2400 int context_length;
2401 const char *context_name;
2402 uint8_t port_number;
2403 int protocol_length;
2404 int timestamp_length;
2405 const char *timestamp_string;
2406 int variant_length;
2407 const char *variant_string;
2408 uint32_t variant;
2409 int outhdr_length;
2410 const char *outhdr_string;
2411 uint8_t direction;
2412 tvbuff_t *next_tvb;
2413 int encap;
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;
2423 /* Set Protocol */
2424 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCT2000");
2426 /* Clear Info */
2427 col_clear(pinfo->cinfo, COL_INFO);
2429 /* Create root (protocol) tree. */
2430 if (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 */
2439 /* Context Name */
2440 context_name = tvb_get_stringz_enc(pinfo->pool, tvb, offset, &context_length, ENC_ASCII);
2441 if (dct2000_tree) {
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);
2449 if (dct2000_tree) {
2450 proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_port_number, tvb,
2451 offset, 1, ENC_BIG_ENDIAN);
2453 offset++;
2455 /* Timestamp in file */
2456 timestamp_string = tvb_get_stringz_enc(pinfo->pool, tvb, offset, &timestamp_length, ENC_ASCII);
2457 if (dct2000_tree) {
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 */
2463 return offset;
2466 /* Seconds. */
2467 int seconds = 0;
2468 int multiplier = 1;
2469 for (int d=timestamp_length-7; d >= 0; d--) {
2470 seconds += ((timestamp_string[d]-'0') * multiplier);
2471 multiplier *= 10;
2474 /* Subseconds (4 digits). N.B. trailing zeros are written out by wiretap module. */
2475 int subseconds = 0;
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);
2490 if (dct2000_tree) {
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);
2495 if (!is_comment) {
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;
2518 /* Direction */
2519 direction = tvb_get_uint8(tvb, offset);
2520 if (dct2000_tree) {
2521 proto_tree_add_item(dct2000_tree, hf_catapult_dct2000_direction, tvb,
2522 offset, 1, ENC_BIG_ENDIAN);
2524 offset++;
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);
2531 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)",
2535 context_name,
2536 port_number,
2537 timestamp_string,
2538 (direction == 0) ? 'S' : 'R',
2539 protocol_name,
2540 variant_string);
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,
2552 outhdr_values);
2553 if (ws_strtou32(variant_string, NULL, &variant))
2554 attach_fp_info(pinfo, direction, protocol_name, variant,
2555 outhdr_values, outhdr_values_found);
2556 else
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,
2570 outhdr_values);
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,
2580 outhdr_values);
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,
2589 outhdr_values);
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,
2598 outhdr_values);
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 */
2614 switch (opcode) {
2615 case LTE_NAS_RRC_DATA_IND:
2616 case LTE_NAS_RRC_DATA_REQ:
2617 /* UEId */
2618 offset++; /* tag */
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);
2622 offset += 2;
2623 break;
2624 case LTE_NAS_RRC_ESTABLISH_REQ:
2625 /* UEId */
2626 offset++; /* tag */
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);
2630 offset += 2;
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);
2641 break;
2642 case LTE_NAS_RRC_RELEASE_IND:
2643 /* UEId */
2644 offset++; /* tag */
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);
2648 offset += 2;
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);
2654 break;
2656 default:
2657 nas_body_found = false;
2658 break;
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");
2667 else {
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 */
2685 offset += 2;
2686 proto_tree_add_item(tree, hf_catapult_dct2000_ueid,
2687 tvb, offset, 4, ENC_BIG_ENDIAN);
2688 offset += 4;
2690 /* NAS PDU tag is 2 bytes */
2691 uint16_t data_tag = tvb_get_ntohs(tvb, offset);
2692 if (data_tag == 0x0021) {
2693 offset += 2;
2694 /* Also skip length */
2695 offset += 2;
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...)
2716 switch (encap) {
2717 case WTAP_ENCAP_RAW_IP:
2718 protocol_handle = find_dissector("ip");
2719 #if 0
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)) {
2725 proto_item *ti;
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);
2735 #endif
2736 break;
2737 case WTAP_ENCAP_ETHERNET:
2738 protocol_handle = find_dissector("eth_withoutfcs");
2739 break;
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;
2749 break;
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;
2753 break;
2754 case WTAP_ENCAP_PPP:
2755 protocol_handle = find_dissector("ppp_hdlc");
2756 pinfo->p2p_dir = pinfo->pseudo_header->p2p.sent;
2757 break;
2758 case DCT2000_ENCAP_SSCOP:
2759 protocol_handle = find_dissector("sscop");
2760 break;
2761 case WTAP_ENCAP_FRELAY:
2762 protocol_handle = find_dissector("fr");
2763 break;
2764 case DCT2000_ENCAP_MTP2:
2765 protocol_handle = find_dissector("mtp2");
2766 break;
2767 case DCT2000_ENCAP_NBAP:
2768 protocol_handle = find_dissector("nbap");
2769 break;
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,
2782 "%s.%u",
2783 context_name,
2784 port_number);
2786 else
2787 if (direction == 1) {
2788 col_add_fstr(pinfo->cinfo, COL_DEF_DST,
2789 "%s.%u",
2790 context_name,
2791 port_number);
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);
2811 else
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;
2818 else
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;
2825 else
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. */
2836 else
2837 if (strcmp(protocol_name, "xml") == 0) {
2838 protocol_handle = find_dissector("xml");
2842 /* Attempt to show tty messages as raw text */
2843 else
2844 if (strcmp(protocol_name, "tty") == 0) {
2845 dissect_tty_lines(tvb, pinfo, dct2000_tree, offset);
2846 return tvb_captured_length(tvb);
2849 else
2850 if (strcmp(protocol_name, "sipprim") == 0) {
2851 protocol_handle = find_dissector("sipprim");
2854 else
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,
2876 "%s", string);
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 */
2903 switch (rntiType) {
2904 case 2:
2905 p_mac_nr_info->rntiType = P_RNTI;
2906 break;
2907 case 3:
2908 p_mac_nr_info->rntiType = RA_RNTI;
2909 break;
2910 case 4:
2911 p_mac_nr_info->rntiType = C_RNTI; /* temp C-RNTI */
2912 break;
2913 case 5:
2914 p_mac_nr_info->rntiType = C_RNTI;
2915 break;
2916 case 6:
2917 p_mac_nr_info->rntiType = MSGB_RNTI;
2918 break;
2919 default:
2920 p_mac_nr_info->rntiType = NO_RNTI;
2921 break;
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] == '$') {
2948 data_offset = n;
2949 break;
2953 /* Convert data to hex. */
2954 char *mac_data = (char *)wmem_alloc(pinfo->pool, 2 + (strlen(string)-data_offset)/2);
2955 int idx, m;
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]);
2960 /* Create tvb */
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);
2970 if (start) {
2971 int off = 0;
2973 while (start[off] && start[off] != '$') {
2974 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];
2983 int idx, m;
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);
3012 g_free(key);
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);
3017 g_free(key);
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);
3025 g_free(key);
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);
3030 g_free(key);
3034 /* 'raw' (ethernet) frames logged as text comments */
3035 int raw_interface;
3036 char raw_direction;
3037 if (sscanf(string, "RawTraffic: Interface: %d %c $",
3038 &raw_interface, &raw_direction) == 2)
3040 /* Interface */
3041 proto_tree_add_uint(tree, hf_catapult_dct2000_rawtraffic_interface,
3042 tvb, 0, 0, raw_interface);
3044 /* Direction */
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] == '$') {
3052 data_offset = n;
3053 break;
3057 /* Convert data to hex. */
3058 static uint8_t eth_data[36000];
3059 int idx, m;
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]);
3064 /* Create tvb */
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");
3068 /* PDU */
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);
3079 else
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);
3092 /* RRC (LTE or NR).
3093 Dissect proprietary header, then pass remainder
3094 to RRC dissector (depending upon direction and channel type) */
3095 else
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);
3118 else
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,
3145 &type_of_port,
3146 &conn_id_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)
3178 "0.0.0.0",
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)
3187 "0.0.0.0",
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,
3216 ENC_NA);
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,
3224 ENC_NA);
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,
3256 ENC_NA);
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,
3264 ENC_NA);
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,
3295 "(%s:%u)",
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,
3301 "(%s:%u)",
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,
3322 &dest_addr_offset,
3323 &dest_addr_length,
3324 &dest_port_offset) ||
3325 find_sctpprim_variant3_data_offset(tvb, &offset,
3326 &dest_addr_offset,
3327 &dest_addr_length,
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)) :
3342 "<ipv6-address>"
3344 "0.0.0.0",
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,
3365 ENC_NA);
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,
3373 ENC_NA);
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
3402 a dissector name */
3403 if ( !protocol_handle && catapult_dct2000_use_protocol_name_as_dissector_name) {
3404 protocol_handle = find_dissector(protocol_name);
3408 break;
3410 default:
3411 /* !! If get here, there is a mismatch between
3412 this dissector and the wiretap module catapult_dct2000.c !!
3414 DISSECTOR_ASSERT_NOT_REACHED();
3415 return 0;
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))",
3440 context_name,
3441 port_number,
3442 timestamp_string,
3443 (direction == 0) ? 'S' : 'R',
3444 protocol_name,
3445 variant_string);
3447 else {
3448 /* Show number of dissected bytes */
3449 if (dct2000_tree) {
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,
3487 { "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,
3495 NULL, HFILL
3498 { &hf_catapult_dct2000_timestamp,
3499 { "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,
3517 { "Out-header",
3518 "dct2000.outhdr", FT_STRING, BASE_NONE, NULL, 0x0,
3519 "DCT2000 protocol outhdr", HFILL
3522 { &hf_catapult_dct2000_direction,
3523 { "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,
3541 { "Comment",
3542 "dct2000.comment", FT_STRING, BASE_NONE, NULL, 0x0,
3543 NULL, HFILL
3546 { &hf_catapult_dct2000_sprint,
3547 { "Sprint text",
3548 "dct2000.sprint", FT_STRING, BASE_NONE, NULL, 0x0,
3549 NULL, HFILL
3552 { &hf_catapult_dct2000_error_comment,
3553 { "Error comment",
3554 "dct2000.error-comment", FT_NONE, BASE_NONE, NULL, 0x0,
3555 NULL, HFILL
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,
3568 NULL, HFILL
3571 { &hf_catapult_dct2000_ipprim_src_addr_v4,
3572 { "Source Address",
3573 "dct2000.ipprim.src", FT_IPv4, BASE_NONE, NULL, 0x0,
3574 "IPPrim IPv4 Source Address", HFILL
3577 { &hf_catapult_dct2000_ipprim_src_addr_v6,
3578 { "Source Address",
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,
3596 { "Address",
3597 "dct2000.ipprim.addr", FT_IPv4, BASE_NONE, NULL, 0x0,
3598 "IPPrim IPv4 Address", HFILL
3601 { &hf_catapult_dct2000_ipprim_addr_v6,
3602 { "Address",
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,
3620 { "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,
3638 { "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,
3644 { "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,
3653 NULL, HFILL
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,
3669 { "Address",
3670 "dct2000.sctpprim.addr", FT_IPv4, BASE_NONE, NULL, 0x0,
3671 "SCTPPrim IPv4 Address", HFILL
3674 { &hf_catapult_dct2000_sctpprim_addr_v6,
3675 { "Address",
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,
3688 { "tty contents",
3689 "dct2000.tty", FT_NONE, BASE_NONE, NULL, 0x0,
3690 NULL, HFILL
3693 { &hf_catapult_dct2000_tty_line,
3694 { "tty line",
3695 "dct2000.tty-line", FT_STRING, BASE_NONE, NULL, 0x0,
3696 NULL, HFILL
3700 { &hf_catapult_dct2000_ueid,
3701 { "UE Id",
3702 "dct2000.ueid", FT_UINT32, BASE_DEC, NULL, 0x0,
3703 "User Equipment Identifier", HFILL
3706 { &hf_catapult_dct2000_srbid,
3707 { "srbid",
3708 "dct2000.srbid", FT_UINT8, BASE_DEC, NULL, 0x0,
3709 "Signalling Radio Bearer Identifier", HFILL
3712 { &hf_catapult_dct2000_drbid,
3713 { "drbid",
3714 "dct2000.drbid", FT_UINT8, BASE_DEC, NULL, 0x0,
3715 "Data Radio Bearer Identifier", HFILL
3718 { &hf_catapult_dct2000_cellid,
3719 { "Cell-Id",
3720 "dct2000.cellid", FT_UINT16, BASE_DEC, NULL, 0x0,
3721 "Cell Identifier", HFILL
3724 { &hf_catapult_dct2000_bcch_transport,
3725 { "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,
3731 { "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,
3739 NULL, HFILL
3742 { &hf_catapult_dct2000_rlc_mui,
3743 { "MUI",
3744 "dct2000.rlc-mui", FT_UINT16, BASE_DEC, NULL, 0x0,
3745 "RLC MUI", HFILL
3748 { &hf_catapult_dct2000_rlc_cnf,
3749 { "CNF",
3750 "dct2000.rlc-cnf", FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0,
3751 "RLC CNF", HFILL
3754 { &hf_catapult_dct2000_rlc_discard_req,
3755 { "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,
3761 { "Carrier Type",
3762 "dct2000.carrier-type", FT_UINT8, BASE_DEC, VALS(carrier_type_vals), 0x0,
3763 NULL, HFILL
3766 { &hf_catapult_dct2000_cell_group,
3767 { "Cell Group",
3768 "dct2000.cell-group", FT_UINT8, BASE_DEC, NULL, 0x0,
3769 NULL, HFILL
3772 { &hf_catapult_dct2000_carrier_id,
3773 { "Carrier Id",
3774 "dct2000.carrier-id", FT_UINT8, BASE_DEC, NULL, 0x0,
3775 NULL, HFILL
3779 { &hf_catapult_dct2000_security_mode_params,
3780 { "Security Mode Params",
3781 "dct2000.security-mode-params", FT_NONE, BASE_NONE, NULL, 0x0,
3782 NULL, HFILL
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,
3788 NULL, HFILL
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,
3794 NULL, HFILL
3797 { &hf_catapult_dct2000_ciphering_algorithm,
3798 { "Ciphering Algorithm",
3799 "dct2000.ciphering-algorithm", FT_UINT8, BASE_DEC, VALS(ciphering_algorithm_vals), 0x0,
3800 NULL, HFILL
3803 { &hf_catapult_dct2000_ciphering_key,
3804 { "Ciphering Key",
3805 "dct2000.ciphering-key", FT_BYTES, BASE_NONE, NULL, 0x0,
3806 NULL, HFILL
3809 { &hf_catapult_dct2000_integrity_algorithm,
3810 { "Integrity Algorithm",
3811 "dct2000.integrity-algorithm", FT_UINT8, BASE_DEC, VALS(integrity_algorithm_vals), 0x0,
3812 NULL, HFILL
3815 { &hf_catapult_dct2000_integrity_key,
3816 { "Integrity Key",
3817 "dct2000.integrity-key", FT_BYTES, BASE_NONE, NULL, 0x0,
3818 NULL, HFILL
3822 { &hf_catapult_dct2000_lte_ccpri_opcode,
3823 { "CCPRI opcode",
3824 "dct2000.lte.ccpri.opcode", FT_UINT8, BASE_DEC, VALS(ccpri_opcode_vals), 0x0,
3825 NULL, HFILL
3828 { &hf_catapult_dct2000_lte_ccpri_status,
3829 { "Status",
3830 "dct2000.lte.ccpri.status", FT_BOOLEAN, BASE_NONE, TFS(&tfs_error_ok), 0x0,
3831 NULL, HFILL
3834 { &hf_catapult_dct2000_lte_ccpri_channel,
3835 { "Channel",
3836 "dct2000.lte.ccpri.channel", FT_UINT8, BASE_DEC, NULL, 0x0,
3837 NULL, HFILL
3841 { &hf_catapult_dct2000_lte_nas_rrc_opcode,
3842 { "NAS RRC Opcode",
3843 "dct2000.lte.nas-rrc.opcode", FT_UINT8, BASE_DEC, VALS(lte_nas_rrc_opcode_vals), 0x0,
3844 NULL, HFILL
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,
3850 NULL, HFILL
3853 { &hf_catapult_dct2000_lte_nas_rrc_priority,
3854 { "Priority",
3855 "dct2000.lte.nas-rrc.priority", FT_UINT8, BASE_DEC, NULL, 0x0,
3856 NULL, HFILL
3859 { &hf_catapult_dct2000_lte_nas_rrc_release_cause,
3860 { "Priority",
3861 "dct2000.lte.nas-rrc.priority", FT_UINT8, BASE_DEC, NULL, 0x0,
3862 NULL, HFILL
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,
3868 NULL, HFILL
3872 { &hf_catapult_dct2000_rbid,
3873 { "Channel",
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,
3879 { "CCCH Id",
3880 "dct2000.ccch-id", FT_UINT8, BASE_DEC, NULL, 0x0,
3881 "CCCH Identifier", HFILL
3884 { &hf_catapult_dct2000_no_crc_error,
3885 { "No CRC Error",
3886 "dct2000.no-crc-error", FT_NONE, BASE_NONE, NULL, 0x0,
3887 NULL, HFILL
3890 { &hf_catapult_dct2000_crc_error,
3891 { "CRC Error",
3892 "dct2000.crc-error", FT_NONE, BASE_NONE, NULL, 0x0,
3893 NULL, HFILL
3896 { &hf_catapult_dct2000_clear_tx_buffer,
3897 { "Clear Tx Buffer",
3898 "dct2000.clear-tx-buffer", FT_NONE, BASE_NONE, NULL, 0x0,
3899 NULL, HFILL
3902 { &hf_catapult_dct2000_buffer_occupancy,
3903 { "Buffer Occupancy",
3904 "dct2000.buffer-occupancy", FT_UINT8, BASE_DEC, NULL, 0x0,
3905 NULL, HFILL
3908 { &hf_catapult_dct2000_pdu_size,
3909 { "PDU Size",
3910 "dct2000.pdu-size", FT_UINT16, BASE_DEC, NULL, 0x0,
3911 NULL, HFILL
3914 { &hf_catapult_dct2000_ueid_type,
3915 { "UEId Type",
3916 "dct2000.ueid-type", FT_UINT8, BASE_DEC, VALS(ueid_type_vals), 0x0,
3917 NULL, HFILL
3920 { &hf_catapult_dct2000_tx_priority,
3921 { "Tx Priority",
3922 "dct2000.tx-priority", FT_BOOLEAN, BASE_NONE, TFS(&tfs_high_normal), 0x0,
3923 NULL, HFILL
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,
3929 NULL, HFILL
3932 { &hf_catapult_dct2000_rx_timing_deviation,
3933 { "Tx Timing Deviation",
3934 "dct2000.rx-timing-deviation", FT_UINT32, BASE_DEC, NULL, 0x0,
3935 NULL, HFILL
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,
3941 NULL, HFILL
3944 { &hf_catapult_dct2000_no_padding_bits,
3945 { "Number of padding bits",
3946 "dct2000.number-of-padding-bits", FT_UINT8, BASE_DEC, NULL, 0x0,
3947 NULL, HFILL
3951 { &hf_catapult_dct2000_rawtraffic_interface,
3952 { "Interface",
3953 "dct2000.rawtraffic.interface", FT_UINT8, BASE_DEC, NULL, 0x0,
3954 NULL, HFILL
3957 { &hf_catapult_dct2000_rawtraffic_direction,
3958 { "Direction",
3959 "dct2000.rawtraffic.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
3960 NULL, HFILL
3963 { &hf_catapult_dct2000_rawtraffic_pdu,
3964 { "PDU",
3965 "dct2000.rawtraffic.pdu", FT_BYTES, BASE_NONE, NULL, 0x0,
3966 NULL, HFILL
3971 static int *ett[] =
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",
3991 "DCT2000",
3992 "dct2000");
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);
4001 /* Preferences */
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 "
4057 "DCT2000 record",
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
4068 * Local variables:
4069 * c-basic-offset: 4
4070 * tab-width: 8
4071 * indent-tabs-mode: nil
4072 * End:
4074 * vi: set shiftwidth=4 tabstop=8 expandtab:
4075 * :indentSize=4:tabSize=8:noTabs=true: