1 /* Routines for LTE PDCP
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <epan/packet.h>
30 #include <epan/prefs.h>
31 #include <epan/expert.h>
32 #include <epan/addr_resolv.h>
33 #include <epan/wmem/wmem.h>
38 #include <wsutil/wsgcrypt.h>
39 #endif /* HAVE_LIBGCRYPT */
41 /* Define this symbol if you have a working implementation of SNOW3G f8() and f9() available.
42 Note that the use of this algorithm is restricted, and that an administrative charge
43 may be applicable if you use it (see e.g. http://www.gsma.com/technicalprojects/fraud-security/security-algorithms).
44 A version of Wireshark with this enabled would not be distributable. */
45 /* #define HAVE_SNOW3G */
47 #include "packet-rlc-lte.h"
48 #include "packet-pdcp-lte.h"
50 void proto_register_pdcp(void);
51 void proto_reg_handoff_pdcp_lte(void);
54 * 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA)
55 * Packet Data Convergence Protocol (PDCP) specification v11.0.0
60 - Decipher even if sequence analysis isn't 'OK'?
61 - know SN, but might be unsure about HFN.
62 - Speed up AES decryption by keeping the crypt handle around for the channel
63 (like ESP decryption in IPSEC dissector)
64 - Add Relay Node user plane data PDU dissection
68 /* Initialize the protocol and registered fields. */
69 int proto_pdcp_lte = -1;
71 extern int proto_rlc_lte;
73 /* Configuration (info known outside of PDU) */
74 static int hf_pdcp_lte_configuration = -1;
75 static int hf_pdcp_lte_direction = -1;
76 static int hf_pdcp_lte_ueid = -1;
77 static int hf_pdcp_lte_channel_type = -1;
78 static int hf_pdcp_lte_channel_id = -1;
80 static int hf_pdcp_lte_rohc_compression = -1;
81 static int hf_pdcp_lte_rohc_mode = -1;
82 static int hf_pdcp_lte_rohc_rnd = -1;
83 static int hf_pdcp_lte_rohc_udp_checksum_present = -1;
84 static int hf_pdcp_lte_rohc_profile = -1;
86 static int hf_pdcp_lte_no_header_pdu = -1;
87 static int hf_pdcp_lte_plane = -1;
88 static int hf_pdcp_lte_seqnum_length = -1;
89 static int hf_pdcp_lte_cid_inclusion_info = -1;
90 static int hf_pdcp_lte_large_cid_present = -1;
92 /* PDCP header fields */
93 static int hf_pdcp_lte_control_plane_reserved = -1;
94 static int hf_pdcp_lte_seq_num_5 = -1;
95 static int hf_pdcp_lte_seq_num_7 = -1;
96 static int hf_pdcp_lte_reserved3 = -1;
97 static int hf_pdcp_lte_seq_num_12 = -1;
98 static int hf_pdcp_lte_seq_num_15 = -1;
99 static int hf_pdcp_lte_signalling_data = -1;
100 static int hf_pdcp_lte_mac = -1;
101 static int hf_pdcp_lte_data_control = -1;
102 static int hf_pdcp_lte_user_plane_data = -1;
103 static int hf_pdcp_lte_control_pdu_type = -1;
104 static int hf_pdcp_lte_fms = -1;
105 static int hf_pdcp_lte_reserved4 = -1;
106 static int hf_pdcp_lte_fms2 = -1;
107 static int hf_pdcp_lte_bitmap = -1;
110 /* Sequence Analysis */
111 static int hf_pdcp_lte_sequence_analysis = -1;
112 static int hf_pdcp_lte_sequence_analysis_ok = -1;
113 static int hf_pdcp_lte_sequence_analysis_previous_frame = -1;
114 static int hf_pdcp_lte_sequence_analysis_next_frame = -1;
115 static int hf_pdcp_lte_sequence_analysis_expected_sn = -1;
117 static int hf_pdcp_lte_sequence_analysis_repeated = -1;
118 static int hf_pdcp_lte_sequence_analysis_skipped = -1;
120 /* Security Settings */
121 static int hf_pdcp_lte_security = -1;
122 static int hf_pdcp_lte_security_setup_frame = -1;
123 static int hf_pdcp_lte_security_integrity_algorithm = -1;
124 static int hf_pdcp_lte_security_ciphering_algorithm = -1;
126 static int hf_pdcp_lte_security_bearer = -1;
127 static int hf_pdcp_lte_security_direction = -1;
128 static int hf_pdcp_lte_security_count = -1;
129 static int hf_pdcp_lte_security_cipher_key = -1;
130 static int hf_pdcp_lte_security_integrity_key = -1;
134 /* Protocol subtree. */
135 static int ett_pdcp = -1;
136 static int ett_pdcp_configuration = -1;
137 static int ett_pdcp_packet = -1;
138 static int ett_pdcp_lte_sequence_analysis = -1;
139 static int ett_pdcp_report_bitmap = -1;
140 static int ett_pdcp_security = -1;
142 static expert_field ei_pdcp_lte_sequence_analysis_wrong_sequence_number = EI_INIT;
143 static expert_field ei_pdcp_lte_reserved_bits_not_zero = EI_INIT;
144 static expert_field ei_pdcp_lte_sequence_analysis_sn_repeated = EI_INIT;
145 static expert_field ei_pdcp_lte_sequence_analysis_sn_missing = EI_INIT;
146 static expert_field ei_pdcp_lte_digest_wrong = EI_INIT;
148 /*-------------------------------------
150 *-------------------------------------
152 /* UAT entry structure. */
155 gchar *rrcCipherKeyString;
156 gchar *upCipherKeyString;
157 gchar *rrcIntegrityKeyString;
159 guint8 rrcCipherBinaryKey[16];
160 gboolean rrcCipherKeyOK;
161 guint8 upCipherBinaryKey[16];
162 gboolean upCipherKeyOK;
163 guint8 rrcIntegrityBinaryKey[16];
164 gboolean rrcIntegrityKeyOK;
165 } uat_ue_keys_record_t;
167 static uat_ue_keys_record_t *uat_ue_keys_records = NULL;
169 /* Entries added by UAT */
170 static uat_t * ue_keys_uat = NULL;
171 static guint num_ue_keys_uat = 0;
173 /* Convert an ascii hex character into a digit. Should only be given valid
174 hex ascii characters */
175 static guchar hex_ascii_to_binary(gchar c)
177 if ((c >= '0') && (c <= '9')) {
180 else if ((c >= 'a') && (c <= 'f')) {
183 else if ((c >= 'A') && (c <= 'F')) {
190 static void* uat_ue_keys_record_copy_cb(void* n, const void* o, size_t siz _U_) {
191 uat_ue_keys_record_t* new_rec = (uat_ue_keys_record_t *)n;
192 const uat_ue_keys_record_t* old_rec = (const uat_ue_keys_record_t *)o;
194 new_rec->ueid = old_rec->ueid;
195 new_rec->rrcCipherKeyString = (old_rec->rrcCipherKeyString) ? g_strdup(old_rec->rrcCipherKeyString) : NULL;
196 new_rec->upCipherKeyString = (old_rec->upCipherKeyString) ? g_strdup(old_rec->upCipherKeyString) : NULL;
197 new_rec->rrcIntegrityKeyString = (old_rec->rrcIntegrityKeyString) ? g_strdup(old_rec->rrcIntegrityKeyString) : NULL;
202 /* If raw_string is a valid key, set check_string & return TRUE */
203 static gboolean check_valid_key_sring(const char* raw_string, char* checked_string)
207 guint length = (gint)strlen(raw_string);
209 /* Can't be valid if not long enough. */
214 for (n=0; (n < length) && (written < 32); n++) {
215 char c = raw_string[n];
217 /* Skipping past allowed 'padding' characters */
218 if ((c == ' ') || (c == '-')) {
222 /* Other characters must be hex digits, otherwise string is invalid */
223 if (((c >= '0') && (c <= '9')) ||
224 ((c >= 'a') && (c <= 'f')) ||
225 ((c >= 'A') && (c <= 'F'))) {
226 checked_string[written++] = c;
233 /* Must have found exactly 32 hex ascii chars for 16-byte key */
234 return (written == 32);
237 static void update_key_from_string(const char *stringKey, guint8 *binaryKey, gboolean *pKeyOK)
240 char cleanString[32];
242 if (!check_valid_key_sring(stringKey, cleanString)) {
246 for (n=0; n < 32; n += 2) {
247 binaryKey[n/2] = (hex_ascii_to_binary(cleanString[n]) << 4) +
248 hex_ascii_to_binary(cleanString[n+1]);
254 /* Update by checking whether the 3 key strings are valid or not, and storing result */
255 static void uat_ue_keys_record_update_cb(void* record, const char** error _U_) {
256 uat_ue_keys_record_t* rec = (uat_ue_keys_record_t *)record;
258 /* Check and convert RRC key */
259 update_key_from_string(rec->rrcCipherKeyString, rec->rrcCipherBinaryKey, &rec->rrcCipherKeyOK);
261 /* Check and convert User-plane key */
262 update_key_from_string(rec->upCipherKeyString, rec->upCipherBinaryKey, &rec->upCipherKeyOK);
264 /* Check and convert Integrity key */
265 update_key_from_string(rec->rrcIntegrityKeyString, rec->rrcIntegrityBinaryKey, &rec->rrcIntegrityKeyOK);
268 /* Free heap parts of record */
269 static void uat_ue_keys_record_free_cb(void*r) {
270 uat_ue_keys_record_t* rec = (uat_ue_keys_record_t*)r;
272 g_free(rec->rrcCipherKeyString);
273 g_free(rec->upCipherKeyString);
274 g_free(rec->rrcIntegrityKeyString);
277 UAT_DEC_CB_DEF(uat_ue_keys_records, ueid, uat_ue_keys_record_t)
278 UAT_CSTRING_CB_DEF(uat_ue_keys_records, rrcCipherKeyString, uat_ue_keys_record_t)
279 UAT_CSTRING_CB_DEF(uat_ue_keys_records, upCipherKeyString, uat_ue_keys_record_t)
280 UAT_CSTRING_CB_DEF(uat_ue_keys_records, rrcIntegrityKeyString, uat_ue_keys_record_t)
283 /* Also supporting a hash table with entries from these functions */
285 /* Table from ueid -> uat_ue_keys_record_t* */
286 static GHashTable *pdcp_security_key_hash = NULL;
289 void set_pdcp_lte_rrc_ciphering_key(guint16 ueid, const char *key)
291 /* Get or create struct for this UE */
292 uat_ue_keys_record_t *key_record = (uat_ue_keys_record_t*)g_hash_table_lookup(pdcp_security_key_hash,
293 GUINT_TO_POINTER((guint)ueid));
294 if (key_record == NULL) {
295 /* Create and add to table */
296 key_record = wmem_new0(wmem_file_scope(), uat_ue_keys_record_t);
297 key_record->ueid = ueid;
298 g_hash_table_insert(pdcp_security_key_hash, GUINT_TO_POINTER((guint)ueid), key_record);
301 /* Check and convert RRC key */
302 key_record->rrcCipherKeyString = g_strdup(key);
303 update_key_from_string(key_record->rrcCipherKeyString, key_record->rrcCipherBinaryKey, &key_record->rrcCipherKeyOK);}
305 void set_pdcp_lte_rrc_integrity_key(guint16 ueid, const char *key)
307 /* Get or create struct for this UE */
308 uat_ue_keys_record_t *key_record = (uat_ue_keys_record_t*)g_hash_table_lookup(pdcp_security_key_hash,
309 GUINT_TO_POINTER((guint)ueid));
310 if (key_record == NULL) {
311 /* Create and add to table */
312 key_record = wmem_new0(wmem_file_scope(), uat_ue_keys_record_t);
313 key_record->ueid = ueid;
314 g_hash_table_insert(pdcp_security_key_hash, GUINT_TO_POINTER((guint)ueid), key_record);
317 /* Check and convert RRC integrity key */
318 key_record->rrcIntegrityKeyString = g_strdup(key);
319 update_key_from_string(key_record->rrcIntegrityKeyString, key_record->rrcIntegrityBinaryKey, &key_record->rrcIntegrityKeyOK);
322 void set_pdcp_lte_up_ciphering_key(guint16 ueid, const char *key)
324 /* Get or create struct for this UE */
325 uat_ue_keys_record_t *key_record = (uat_ue_keys_record_t*)g_hash_table_lookup(pdcp_security_key_hash,
326 GUINT_TO_POINTER((guint)ueid));
327 if (key_record == NULL) {
328 /* Create and add to table */
329 key_record = wmem_new0(wmem_file_scope(), uat_ue_keys_record_t);
330 key_record->ueid = ueid;
331 g_hash_table_insert(pdcp_security_key_hash, GUINT_TO_POINTER((guint)ueid), key_record);
334 /* Check and convert UP key */
335 key_record->upCipherKeyString = g_strdup(key);
336 update_key_from_string(key_record->upCipherKeyString, key_record->upCipherBinaryKey, &key_record->upCipherKeyOK);
340 /* Preference settings for deciphering and integrity checking. Currently all default to off */
341 static gboolean global_pdcp_decipher_signalling = TRUE;
342 static gboolean global_pdcp_decipher_userplane = FALSE; /* Can be slow, so default to FALSE */
343 static gboolean global_pdcp_check_integrity = FALSE;
347 static const value_string direction_vals[] =
349 { DIRECTION_UPLINK, "Uplink"},
350 { DIRECTION_DOWNLINK, "Downlink"},
355 static const value_string pdcp_plane_vals[] = {
356 { SIGNALING_PLANE, "Signalling" },
357 { USER_PLANE, "User" },
361 static const value_string logical_channel_vals[] = {
362 { Channel_DCCH, "DCCH"},
363 { Channel_BCCH, "BCCH"},
364 { Channel_CCCH, "CCCH"},
365 { Channel_PCCH, "PCCH"},
369 static const value_string rohc_mode_vals[] = {
370 { UNIDIRECTIONAL, "Unidirectional" },
371 { OPTIMISTIC_BIDIRECTIONAL, "Optimistic Bidirectional" },
372 { RELIABLE_BIDIRECTIONAL, "Reliable Bidirectional" },
377 /* Values taken from:
378 http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.txt */
379 static const value_string rohc_profile_vals[] = {
380 { 0x0000, "ROHC uncompressed" }, /* [RFC5795] */
381 { 0x0001, "ROHC RTP" }, /* [RFC3095] */
382 { 0x0101, "ROHCv2 RTP" }, /* [RFC5225] */
383 { 0x0002, "ROHC UDP" }, /* [RFC3095] */
384 { 0x0102, "ROHCv2 UDP" }, /* [RFC5225] */
385 { 0x0003, "ROHC ESP" }, /* [RFC3095] */
386 { 0x0103, "ROHCv2 ESP" }, /* [RFC5225] */
387 { 0x0004, "ROHC IP" }, /* [RFC3843] */
388 { 0x0104, "ROHCv2 IP" }, /* [RFC5225] */
389 { 0x0005, "ROHC LLA" }, /* [RFC4362] */
390 { 0x0105, "ROHC LLA with R-mode" }, /* [RFC3408] */
391 { 0x0006, "ROHC TCP" }, /* [RFC4996] */
392 { 0x0007, "ROHC RTP/UDP-Lite" }, /* [RFC4019] */
393 { 0x0107, "ROHCv2 RTP/UDP-Lite" }, /* [RFC5225] */
394 { 0x0008, "ROHC UDP-Lite" }, /* [RFC4019] */
395 { 0x0108, "ROHCv2 UDP-Lite" }, /* [RFC5225] */
399 static const value_string pdu_type_vals[] = {
400 { 0, "Control PDU" },
405 static const value_string control_pdu_type_vals[] = {
406 { 0, "PDCP Status report" },
407 { 1, "Header Compression Feedback Information" },
411 static const value_string integrity_algorithm_vals[] = {
419 static const value_string ciphering_algorithm_vals[] = {
428 static dissector_handle_t ip_handle;
429 static dissector_handle_t ipv6_handle;
430 static dissector_handle_t rohc_handle;
431 static dissector_handle_t data_handle;
434 #define SEQUENCE_ANALYSIS_RLC_ONLY 1
435 #define SEQUENCE_ANALYSIS_PDCP_ONLY 2
437 /* Preference variables */
438 static gboolean global_pdcp_dissect_user_plane_as_ip = TRUE;
439 static gboolean global_pdcp_dissect_signalling_plane_as_rrc = TRUE;
440 static gint global_pdcp_check_sequence_numbers = TRUE;
441 static gboolean global_pdcp_dissect_rohc = FALSE;
443 /* Which layer info to show in the info column */
445 ShowRLCLayer, ShowPDCPLayer, ShowTrafficLayer
447 static gint global_pdcp_lte_layer_to_show = (gint)ShowRLCLayer;
451 /**************************************************/
452 /* Sequence number analysis */
457 /* Using bit fields to fit into 32 bits, so avoiding the need to allocate
458 heap memory for these structs */
464 } pdcp_channel_hash_key;
469 guint16 previousSequenceNumber;
470 guint32 previousFrameNum;
472 } pdcp_channel_status;
474 /* The sequence analysis channel hash table.
475 Maps key -> status */
476 static GHashTable *pdcp_sequence_analysis_channel_hash = NULL;
479 static gint pdcp_channel_equal(gconstpointer v, gconstpointer v2)
481 /* Key fits in 4 bytes, so just compare pointers! */
485 /* Compute a hash value for a given key. */
486 static guint pdcp_channel_hash_func(gconstpointer v)
488 /* Just use pointer, as the fields are all in this value */
489 return GPOINTER_TO_UINT(v);
493 /* Hash table types & functions for frame reports */
499 guint32 channelId: 5;
500 guint32 direction: 1;
502 } pdcp_result_hash_key;
504 static gint pdcp_result_hash_equal(gconstpointer v, gconstpointer v2)
506 const pdcp_result_hash_key* val1 = (const pdcp_result_hash_key *)v;
507 const pdcp_result_hash_key* val2 = (const pdcp_result_hash_key *)v2;
509 /* All fields must match */
510 return (memcmp(val1, val2, sizeof(pdcp_result_hash_key)) == 0);
513 /* Compute a hash value for a given key. */
514 static guint pdcp_result_hash_func(gconstpointer v)
516 const pdcp_result_hash_key* val1 = (const pdcp_result_hash_key *)v;
518 /* TODO: This is a bit random. */
519 return val1->frameNumber + (val1->channelId<<13) +
522 (val1->direction<<9);
525 /* pdcp_channel_hash_key fits into the pointer, so just copy the value into
526 a guint, cast to apointer and return that as the key */
527 static gpointer get_channel_hash_key(pdcp_channel_hash_key *key)
530 /* TODO: assert that sizeof(pdcp_channel_hash_key) <= sizeof(guint) ? */
531 memcpy(&asInt, key, sizeof(pdcp_channel_hash_key));
532 return GUINT_TO_POINTER(asInt);
535 /* Convenience function to get a pointer for the hash_func to work with */
536 static gpointer get_report_hash_key(guint16 SN, guint32 frameNumber,
537 pdcp_lte_info *p_pdcp_lte_info,
540 static pdcp_result_hash_key key;
541 pdcp_result_hash_key *p_key;
543 /* Only allocate a struct when will be adding entry */
545 p_key = wmem_new(wmem_file_scope(), pdcp_result_hash_key);
548 memset(&key, 0, sizeof(pdcp_result_hash_key));
552 /* Fill in details, and return pointer */
553 p_key->frameNumber = frameNumber;
555 p_key->plane = (guint8)p_pdcp_lte_info->plane;
556 p_key->channelId = p_pdcp_lte_info->channelId;
557 p_key->direction = p_pdcp_lte_info->direction;
564 /* Info to attach to frame when first read, recording what to show about sequence */
567 SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing
571 gboolean sequenceExpectedCorrect;
572 guint16 sequenceExpected;
573 guint32 previousFrameNum;
574 guint32 nextFrameNum;
580 sequence_state state;
581 } pdcp_sequence_report_in_frame;
583 /* The sequence analysis frame report hash table.
584 Maps pdcp_result_hash_key* -> pdcp_sequence_report_in_frame* */
585 static GHashTable *pdcp_lte_sequence_analysis_report_hash = NULL;
587 /* Gather together security settings in order to be able to do deciphering */
588 typedef struct pdu_security_settings_t
590 enum security_ciphering_algorithm_e ciphering;
591 enum security_integrity_algorithm_e integrity;
593 guint8* integrityKey;
594 gboolean cipherKeyValid;
595 gboolean integrityKeyValid;
599 } pdu_security_settings_t;
602 static uat_ue_keys_record_t* look_up_keys_record(guint16 ueid)
604 unsigned int record_id;
605 /* Try hash table first */
606 uat_ue_keys_record_t* key_record = (uat_ue_keys_record_t*)g_hash_table_lookup(pdcp_security_key_hash,
607 GUINT_TO_POINTER((guint)ueid));
608 if (key_record != NULL) {
612 /* Else look up UAT entries */
613 for (record_id=0; record_id < num_ue_keys_uat; record_id++) {
614 if (uat_ue_keys_records[record_id].ueid == ueid) {
615 return &uat_ue_keys_records[record_id];
619 /* No match at all - return NULL */
623 /* Add to the tree values associated with sequence analysis for this frame */
624 static void addChannelSequenceInfo(pdcp_sequence_report_in_frame *p,
625 pdcp_lte_info *p_pdcp_lte_info,
626 guint16 sequenceNumber,
627 packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb,
628 proto_tree *security_tree,
629 pdu_security_settings_t *pdu_security)
631 proto_tree *seqnum_tree;
632 proto_item *seqnum_ti;
633 proto_item *ti_expected_sn;
635 uat_ue_keys_record_t *keys_record;
638 seqnum_ti = proto_tree_add_string_format(tree,
639 hf_pdcp_lte_sequence_analysis,
641 "", "Sequence Analysis");
642 seqnum_tree = proto_item_add_subtree(seqnum_ti,
643 ett_pdcp_lte_sequence_analysis);
644 PROTO_ITEM_SET_GENERATED(seqnum_ti);
647 /* Previous channel frame */
648 if (p->previousFrameNum != 0) {
649 proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_previous_frame,
650 tvb, 0, 0, p->previousFrameNum);
653 /* Expected sequence number */
654 ti_expected_sn = proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_expected_sn,
655 tvb, 0, 0, p->sequenceExpected);
656 PROTO_ITEM_SET_GENERATED(ti_expected_sn);
658 /* Make sure we have recognised SN length */
659 switch (p_pdcp_lte_info->seqnum_length) {
660 case PDCP_SN_LENGTH_5_BITS:
661 case PDCP_SN_LENGTH_7_BITS:
662 case PDCP_SN_LENGTH_12_BITS:
663 case PDCP_SN_LENGTH_15_BITS:
666 DISSECTOR_ASSERT_NOT_REACHED();
672 PROTO_ITEM_SET_HIDDEN(ti_expected_sn);
673 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
675 PROTO_ITEM_SET_GENERATED(ti);
676 proto_item_append_text(seqnum_ti, " - OK");
678 /* Link to next SN in channel (if known) */
679 if (p->nextFrameNum != 0) {
680 proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_next_frame,
681 tvb, 0, 0, p->nextFrameNum);
684 /* May also be able to add key inputs to security tree here */
685 if ((pdu_security->ciphering != eea0) ||
686 (pdu_security->integrity != eia0)) {
687 guint32 hfn_multiplier;
689 gchar *cipher_key = NULL;
690 gchar *integrity_key = NULL;
693 ti = proto_tree_add_uint(security_tree, hf_pdcp_lte_security_bearer,
694 tvb, 0, 0, p_pdcp_lte_info->channelId-1);
695 PROTO_ITEM_SET_GENERATED(ti);
696 pdu_security->bearer = p_pdcp_lte_info->channelId-1;
699 ti = proto_tree_add_uint(security_tree, hf_pdcp_lte_security_direction,
700 tvb, 0, 0, p_pdcp_lte_info->direction);
701 PROTO_ITEM_SET_GENERATED(ti);
703 /* COUNT (HFN * snLength^2 + SN) */
704 switch (p_pdcp_lte_info->seqnum_length) {
705 case PDCP_SN_LENGTH_5_BITS:
708 case PDCP_SN_LENGTH_7_BITS:
709 hfn_multiplier = 128;
711 case PDCP_SN_LENGTH_12_BITS:
712 hfn_multiplier = 4096;
714 case PDCP_SN_LENGTH_15_BITS:
715 hfn_multiplier = 32768;
718 DISSECTOR_ASSERT_NOT_REACHED();
721 count = (p->hfn * hfn_multiplier) + sequenceNumber;
722 ti = proto_tree_add_uint(security_tree, hf_pdcp_lte_security_count,
724 PROTO_ITEM_SET_GENERATED(ti);
725 pdu_security->count = count;
727 /* KEY. Look this UE up among UEs that have keys configured */
728 keys_record = look_up_keys_record(p_pdcp_lte_info->ueid);
729 if (keys_record != NULL) {
730 if (p_pdcp_lte_info->plane == SIGNALING_PLANE) {
731 /* Get RRC ciphering key */
732 if (keys_record->rrcCipherKeyOK) {
733 cipher_key = keys_record->rrcCipherKeyString;
734 pdu_security->cipherKey = &(keys_record->rrcCipherBinaryKey[0]);
735 pdu_security->cipherKeyValid = TRUE;
737 /* Get RRC integrity key */
738 if (keys_record->rrcIntegrityKeyOK) {
739 integrity_key = keys_record->rrcIntegrityKeyString;
740 pdu_security->integrityKey = &(keys_record->rrcIntegrityBinaryKey[0]);
741 pdu_security->integrityKeyValid = TRUE;
745 /* Get userplane ciphering key */
746 if (keys_record->upCipherKeyOK) {
747 cipher_key = keys_record->upCipherKeyString;
748 pdu_security->cipherKey = &(keys_record->upCipherBinaryKey[0]);
749 pdu_security->cipherKeyValid = TRUE;
753 /* Show keys where known and valid */
754 if (cipher_key != NULL) {
755 ti = proto_tree_add_string(security_tree, hf_pdcp_lte_security_cipher_key,
756 tvb, 0, 0, cipher_key);
757 PROTO_ITEM_SET_GENERATED(ti);
759 if (integrity_key != NULL) {
760 ti = proto_tree_add_string(security_tree, hf_pdcp_lte_security_integrity_key,
761 tvb, 0, 0, integrity_key);
762 PROTO_ITEM_SET_GENERATED(ti);
765 pdu_security->direction = p_pdcp_lte_info->direction;
771 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
773 PROTO_ITEM_SET_GENERATED(ti);
774 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_skipped,
776 PROTO_ITEM_SET_GENERATED(ti);
777 if (p->lastSN != p->firstSN) {
778 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_sequence_analysis_sn_missing,
779 "PDCP SNs (%u to %u) missing for %s on UE %u (%s-%u)",
780 p->firstSN, p->lastSN,
781 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
782 p_pdcp_lte_info->ueid,
783 val_to_str_const(p_pdcp_lte_info->channelType, logical_channel_vals, "Unknown"),
784 p_pdcp_lte_info->channelId);
785 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
786 p->firstSN, p->lastSN);
789 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_sequence_analysis_sn_missing,
790 "PDCP SN (%u) missing for %s on UE %u (%s-%u)",
792 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
793 p_pdcp_lte_info->ueid,
794 val_to_str_const(p_pdcp_lte_info->channelType, logical_channel_vals, "Unknown"),
795 p_pdcp_lte_info->channelId);
796 proto_item_append_text(seqnum_ti, " - SN missing (%u)",
802 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
804 PROTO_ITEM_SET_GENERATED(ti);
805 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_repeated,
807 PROTO_ITEM_SET_GENERATED(ti);
808 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_sequence_analysis_sn_repeated,
809 "PDCP SN (%u) repeated for %s for UE %u (%s-%u)",
811 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
812 p_pdcp_lte_info->ueid,
813 val_to_str_const(p_pdcp_lte_info->channelType, logical_channel_vals, "Unknown"),
814 p_pdcp_lte_info->channelId);
815 proto_item_append_text(seqnum_ti, "- SN %u Repeated",
820 /* Incorrect sequence number */
821 expert_add_info_format(pinfo, ti_expected_sn, &ei_pdcp_lte_sequence_analysis_wrong_sequence_number,
822 "Wrong Sequence Number for %s on UE %u (%s-%u) - got %u, expected %u",
823 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
824 p_pdcp_lte_info->ueid,
825 val_to_str_const(p_pdcp_lte_info->channelType, logical_channel_vals, "Unknown"),
826 p_pdcp_lte_info->channelId,
827 sequenceNumber, p->sequenceExpected);
833 /* Update the channel status and set report for this frame */
834 static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
835 pdcp_lte_info *p_pdcp_lte_info,
836 guint16 sequenceNumber,
838 proto_tree *security_tree,
839 pdu_security_settings_t *pdu_security)
841 pdcp_channel_hash_key channel_key;
842 pdcp_channel_status *p_channel_status;
843 pdcp_sequence_report_in_frame *p_report_in_frame = NULL;
844 gboolean createdChannel = FALSE;
845 guint16 expectedSequenceNumber = 0;
848 /* If find stat_report_in_frame already, use that and get out */
849 if (pinfo->fd->flags.visited) {
851 (pdcp_sequence_report_in_frame*)g_hash_table_lookup(pdcp_lte_sequence_analysis_report_hash,
852 get_report_hash_key(sequenceNumber,
854 p_pdcp_lte_info, FALSE));
855 if (p_report_in_frame != NULL) {
856 addChannelSequenceInfo(p_report_in_frame, p_pdcp_lte_info,
858 pinfo, tree, tvb, security_tree, pdu_security);
862 /* Give up - we must have tried already... */
868 /**************************************************/
869 /* Create or find an entry for this channel state */
870 channel_key.ueId = p_pdcp_lte_info->ueid;
871 channel_key.plane = p_pdcp_lte_info->plane;
872 channel_key.channelId = p_pdcp_lte_info->channelId;
873 channel_key.direction = p_pdcp_lte_info->direction;
874 channel_key.notUsed = 0;
876 /* Do the table lookup */
877 p_channel_status = (pdcp_channel_status*)g_hash_table_lookup(pdcp_sequence_analysis_channel_hash,
878 get_channel_hash_key(&channel_key));
880 /* Create table entry if necessary */
881 if (p_channel_status == NULL) {
882 createdChannel = TRUE;
884 /* Allocate a new value and duplicate key contents */
885 p_channel_status = wmem_new0(wmem_file_scope(), pdcp_channel_status);
888 g_hash_table_insert(pdcp_sequence_analysis_channel_hash,
889 get_channel_hash_key(&channel_key), p_channel_status);
892 /* Create space for frame state_report */
893 p_report_in_frame = wmem_new(wmem_file_scope(), pdcp_sequence_report_in_frame);
894 p_report_in_frame->nextFrameNum = 0;
896 switch (p_pdcp_lte_info->seqnum_length) {
897 case PDCP_SN_LENGTH_5_BITS:
900 case PDCP_SN_LENGTH_7_BITS:
903 case PDCP_SN_LENGTH_12_BITS:
906 case PDCP_SN_LENGTH_15_BITS:
910 DISSECTOR_ASSERT_NOT_REACHED();
914 /* Work out expected sequence number */
915 if (!createdChannel) {
916 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
919 expectedSequenceNumber = sequenceNumber;
922 /* Set report for this frame */
923 /* For PDCP, sequence number is always expectedSequence number */
924 p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
925 p_report_in_frame->hfn = p_channel_status->hfn;
927 /* For wrong sequence number... */
928 if (!p_report_in_frame->sequenceExpectedCorrect) {
930 /* Frames are not missing if we get an earlier sequence number again */
931 if (((snLimit + expectedSequenceNumber - sequenceNumber) % snLimit) > 15) {
932 p_report_in_frame->state = SN_Missing;
933 p_report_in_frame->firstSN = expectedSequenceNumber;
934 p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
936 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
937 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
939 /* Update channel status to remember *this* frame */
940 p_channel_status->previousFrameNum = pinfo->fd->num;
941 p_channel_status->previousSequenceNumber = sequenceNumber;
944 /* An SN has been repeated */
945 p_report_in_frame->state = SN_Repeated;
946 p_report_in_frame->firstSN = sequenceNumber;
948 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
949 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
954 p_report_in_frame->state = SN_OK;
955 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
956 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
957 /* SN has rolled around, inc hfn! */
958 if (!createdChannel && (sequenceNumber == 0)) {
959 /* TODO: not worrying about HFN rolling over for now! */
960 p_channel_status->hfn++;
961 p_report_in_frame->hfn = p_channel_status->hfn;
964 /* Update channel status to remember *this* frame */
965 p_channel_status->previousFrameNum = pinfo->fd->num;
966 p_channel_status->previousSequenceNumber = sequenceNumber;
968 if (p_report_in_frame->previousFrameNum != 0) {
969 /* Get report for previous frame */
970 pdcp_sequence_report_in_frame *p_previous_report;
971 p_previous_report = (pdcp_sequence_report_in_frame*)g_hash_table_lookup(pdcp_lte_sequence_analysis_report_hash,
972 get_report_hash_key((sequenceNumber+32767) % 32768,
973 p_report_in_frame->previousFrameNum,
976 /* It really shouldn't be NULL... */
977 if (p_previous_report != NULL) {
978 /* Point it forward to this one */
979 p_previous_report->nextFrameNum = pinfo->fd->num;
984 /* Associate with this frame number */
985 g_hash_table_insert(pdcp_lte_sequence_analysis_report_hash,
986 get_report_hash_key(sequenceNumber, pinfo->fd->num,
987 p_pdcp_lte_info, TRUE),
990 /* Add state report for this frame into tree */
991 addChannelSequenceInfo(p_report_in_frame, p_pdcp_lte_info, sequenceNumber,
992 pinfo, tree, tvb, security_tree, pdu_security);
997 /* Hash table for security state for a UE
998 Maps UEId -> pdcp_security_info_t* */
999 static gint pdcp_lte_ueid_hash_equal(gconstpointer v, gconstpointer v2)
1003 static guint pdcp_lte_ueid_hash_func(gconstpointer v)
1005 return GPOINTER_TO_UINT(v);
1007 static GHashTable *pdcp_security_hash = NULL;
1009 /* Result is (ueid, framenum) -> pdcp_security_info_t* */
1010 typedef struct ueid_frame_t {
1015 /* Convenience function to get a pointer for the hash_func to work with */
1016 static gpointer get_ueid_frame_hash_key(guint16 ueid, guint32 frameNumber,
1017 gboolean do_persist)
1019 static ueid_frame_t key;
1020 ueid_frame_t *p_key;
1022 /* Only allocate a struct when will be adding entry */
1024 p_key = wmem_new(wmem_file_scope(), ueid_frame_t);
1027 memset(&key, 0, sizeof(ueid_frame_t));
1031 /* Fill in details, and return pointer */
1032 p_key->framenum = frameNumber;
1038 static gint pdcp_lte_ueid_frame_hash_equal(gconstpointer v, gconstpointer v2)
1040 const ueid_frame_t *ueid_frame_1 = (const ueid_frame_t *)v;
1041 const ueid_frame_t *ueid_frame_2 = (const ueid_frame_t *)v2;
1042 return ((ueid_frame_1->framenum == ueid_frame_2->framenum) && (ueid_frame_1->ueid == ueid_frame_2->ueid));
1044 static guint pdcp_lte_ueid_frame_hash_func(gconstpointer v)
1046 const ueid_frame_t *ueid_frame = (const ueid_frame_t *)v;
1047 return ueid_frame->framenum + 100*ueid_frame->ueid;
1049 static GHashTable *pdcp_security_result_hash = NULL;
1054 /* Write the given formatted text to:
1056 - the top-level RLC PDU item */
1057 static void write_pdu_label_and_info(proto_item *pdu_ti,
1058 packet_info *pinfo, const char *format, ...)
1060 #define MAX_INFO_BUFFER 256
1061 static char info_buffer[MAX_INFO_BUFFER];
1065 va_start(ap, format);
1066 g_vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
1069 /* Add to indicated places */
1070 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
1071 proto_item_append_text(pdu_ti, "%s", info_buffer);
1076 /***************************************************************/
1080 /* Show in the tree the config info attached to this frame, as generated fields */
1081 static void show_pdcp_config(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
1082 pdcp_lte_info *p_pdcp_info)
1085 proto_tree *configuration_tree;
1086 proto_item *configuration_ti = proto_tree_add_item(tree,
1087 hf_pdcp_lte_configuration,
1088 tvb, 0, 0, ENC_ASCII|ENC_NA);
1089 configuration_tree = proto_item_add_subtree(configuration_ti, ett_pdcp_configuration);
1092 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_direction, tvb, 0, 0,
1093 p_pdcp_info->direction);
1094 PROTO_ITEM_SET_GENERATED(ti);
1097 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_plane, tvb, 0, 0,
1098 p_pdcp_info->plane);
1099 PROTO_ITEM_SET_GENERATED(ti);
1102 if (p_pdcp_info->ueid != 0) {
1103 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_ueid, tvb, 0, 0,
1105 PROTO_ITEM_SET_GENERATED(ti);
1109 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_channel_type, tvb, 0, 0,
1110 p_pdcp_info->channelType);
1111 PROTO_ITEM_SET_GENERATED(ti);
1112 if (p_pdcp_info->channelId != 0) {
1114 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_channel_id, tvb, 0, 0,
1115 p_pdcp_info->channelId);
1116 PROTO_ITEM_SET_GENERATED(ti);
1120 /* User-plane-specific fields */
1121 if (p_pdcp_info->plane == USER_PLANE) {
1124 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_no_header_pdu, tvb, 0, 0,
1125 p_pdcp_info->no_header_pdu);
1126 PROTO_ITEM_SET_GENERATED(ti);
1128 if (!p_pdcp_info->no_header_pdu) {
1131 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_seqnum_length, tvb, 0, 0,
1132 p_pdcp_info->seqnum_length);
1133 PROTO_ITEM_SET_GENERATED(ti);
1137 /* ROHC compression */
1138 ti = proto_tree_add_boolean(configuration_tree, hf_pdcp_lte_rohc_compression, tvb, 0, 0,
1139 p_pdcp_info->rohc.rohc_compression);
1140 PROTO_ITEM_SET_GENERATED(ti);
1142 /* ROHC-specific settings */
1143 if (p_pdcp_info->rohc.rohc_compression) {
1145 /* Show ROHC mode */
1146 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_mode, tvb, 0, 0,
1147 p_pdcp_info->rohc.mode);
1148 PROTO_ITEM_SET_GENERATED(ti);
1151 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_rnd, tvb, 0, 0,
1152 p_pdcp_info->rohc.rnd);
1153 PROTO_ITEM_SET_GENERATED(ti);
1156 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_udp_checksum_present, tvb, 0, 0,
1157 p_pdcp_info->rohc.udp_checksum_present);
1158 PROTO_ITEM_SET_GENERATED(ti);
1161 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_profile, tvb, 0, 0,
1162 p_pdcp_info->rohc.profile);
1163 PROTO_ITEM_SET_GENERATED(ti);
1165 /* CID Inclusion Info */
1166 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_cid_inclusion_info, tvb, 0, 0,
1167 p_pdcp_info->rohc.cid_inclusion_info);
1168 PROTO_ITEM_SET_GENERATED(ti);
1171 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_large_cid_present, tvb, 0, 0,
1172 p_pdcp_info->rohc.large_cid_present);
1173 PROTO_ITEM_SET_GENERATED(ti);
1176 /* Append summary to configuration root */
1177 proto_item_append_text(configuration_ti, "(direction=%s, plane=%s",
1178 val_to_str_const(p_pdcp_info->direction, direction_vals, "Unknown"),
1179 val_to_str_const(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
1181 if (p_pdcp_info->rohc.rohc_compression) {
1182 const char *mode = val_to_str_const(p_pdcp_info->rohc.mode, rohc_mode_vals, "Error");
1183 proto_item_append_text(configuration_ti, ", mode=%c, profile=%s",
1185 val_to_str_const(p_pdcp_info->rohc.profile, rohc_profile_vals, "Unknown"));
1187 proto_item_append_text(configuration_ti, ")");
1188 PROTO_ITEM_SET_GENERATED(configuration_ti);
1190 /* Show plane in info column */
1191 col_append_fstr(pinfo->cinfo, COL_INFO, " %s: ",
1192 val_to_str_const(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
1197 /* Look for an RRC dissector for signalling data (using channel type and direction) */
1198 static dissector_handle_t lookup_rrc_dissector_handle(struct pdcp_lte_info *p_pdcp_info)
1200 dissector_handle_t rrc_handle = 0;
1202 switch (p_pdcp_info->channelType)
1205 if (p_pdcp_info->direction == DIRECTION_UPLINK) {
1206 rrc_handle = find_dissector("lte_rrc.ul_ccch");
1209 rrc_handle = find_dissector("lte_rrc.dl_ccch");
1213 rrc_handle = find_dissector("lte_rrc.pcch");
1216 switch (p_pdcp_info->BCCHTransport) {
1218 rrc_handle = find_dissector("lte_rrc.bcch_bch");
1220 case DLSCH_TRANSPORT:
1221 rrc_handle = find_dissector("lte_rrc.bcch_dl_sch");
1226 if (p_pdcp_info->direction == DIRECTION_UPLINK) {
1227 rrc_handle = find_dissector("lte_rrc.ul_dcch");
1230 rrc_handle = find_dissector("lte_rrc.dl_dcch");
1243 /* Forwad declarations */
1244 static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
1246 /* Heuristic dissection */
1247 static gboolean global_pdcp_lte_heur = FALSE;
1249 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
1250 static gboolean dissect_pdcp_lte_heur(tvbuff_t *tvb, packet_info *pinfo,
1251 proto_tree *tree, void *data _U_)
1254 struct pdcp_lte_info *p_pdcp_lte_info;
1257 gboolean infoAlreadySet = FALSE;
1258 gboolean seqnumLengthTagPresent = FALSE;
1260 /* This is a heuristic dissector, which means we get all the UDP
1261 * traffic not sent to a known dissector and not claimed by
1262 * a heuristic dissector called before us!
1265 if (!global_pdcp_lte_heur) {
1269 /* Do this again on re-dissection to re-discover offset of actual PDU */
1271 /* Needs to be at least as long as:
1272 - the signature string
1273 - fixed header bytes
1275 - at least one byte of PDCP PDU payload */
1276 if (tvb_captured_length_remaining(tvb, offset) < (gint)(strlen(PDCP_LTE_START_STRING)+3+2)) {
1280 /* OK, compare with signature string */
1281 if (tvb_strneql(tvb, offset, PDCP_LTE_START_STRING, strlen(PDCP_LTE_START_STRING)) != 0) {
1284 offset += (gint)strlen(PDCP_LTE_START_STRING);
1287 /* If redissecting, use previous info struct (if available) */
1288 p_pdcp_lte_info = (pdcp_lte_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pdcp_lte, 0);
1289 if (p_pdcp_lte_info == NULL) {
1290 /* Allocate new info struct for this frame */
1291 p_pdcp_lte_info = wmem_new0(wmem_file_scope(), pdcp_lte_info);
1292 infoAlreadySet = FALSE;
1295 infoAlreadySet = TRUE;
1299 /* Read fixed fields */
1300 p_pdcp_lte_info->no_header_pdu = (gboolean)tvb_get_guint8(tvb, offset++);
1301 p_pdcp_lte_info->plane = (enum pdcp_plane)tvb_get_guint8(tvb, offset++);
1302 if (p_pdcp_lte_info->plane == SIGNALING_PLANE) {
1303 p_pdcp_lte_info->seqnum_length = PDCP_SN_LENGTH_5_BITS;
1305 p_pdcp_lte_info->rohc.rohc_compression = (gboolean)tvb_get_guint8(tvb, offset++);
1307 /* Read optional fields */
1308 while (tag != PDCP_LTE_PAYLOAD_TAG) {
1309 /* Process next tag */
1310 tag = tvb_get_guint8(tvb, offset++);
1312 case PDCP_LTE_SEQNUM_LENGTH_TAG:
1313 p_pdcp_lte_info->seqnum_length = tvb_get_guint8(tvb, offset);
1315 seqnumLengthTagPresent = TRUE;
1317 case PDCP_LTE_DIRECTION_TAG:
1318 p_pdcp_lte_info->direction = tvb_get_guint8(tvb, offset);
1321 case PDCP_LTE_LOG_CHAN_TYPE_TAG:
1322 p_pdcp_lte_info->channelType = (LogicalChannelType)tvb_get_guint8(tvb, offset);
1325 case PDCP_LTE_BCCH_TRANSPORT_TYPE_TAG:
1326 p_pdcp_lte_info->BCCHTransport = (BCCHTransportType)tvb_get_guint8(tvb, offset);
1329 case PDCP_LTE_ROHC_IP_VERSION_TAG:
1330 p_pdcp_lte_info->rohc.rohc_ip_version = tvb_get_ntohs(tvb, offset);
1333 case PDCP_LTE_ROHC_CID_INC_INFO_TAG:
1334 p_pdcp_lte_info->rohc.cid_inclusion_info = tvb_get_guint8(tvb, offset);
1337 case PDCP_LTE_ROHC_LARGE_CID_PRES_TAG:
1338 p_pdcp_lte_info->rohc.large_cid_present = tvb_get_guint8(tvb, offset);
1341 case PDCP_LTE_ROHC_MODE_TAG:
1342 p_pdcp_lte_info->rohc.mode = (enum rohc_mode)tvb_get_guint8(tvb, offset);
1345 case PDCP_LTE_ROHC_RND_TAG:
1346 p_pdcp_lte_info->rohc.rnd = tvb_get_guint8(tvb, offset);
1349 case PDCP_LTE_ROHC_UDP_CHECKSUM_PRES_TAG:
1350 p_pdcp_lte_info->rohc.udp_checksum_present = tvb_get_guint8(tvb, offset);
1353 case PDCP_LTE_ROHC_PROFILE_TAG:
1354 p_pdcp_lte_info->rohc.profile = tvb_get_ntohs(tvb, offset);
1357 case PDCP_LTE_CHANNEL_ID_TAG:
1358 p_pdcp_lte_info->channelId = tvb_get_ntohs(tvb, offset);
1361 case PDCP_LTE_UEID_TAG:
1362 p_pdcp_lte_info->ueid = tvb_get_ntohs(tvb, offset);
1366 case PDCP_LTE_PAYLOAD_TAG:
1367 /* Have reached data, so get out of loop */
1371 /* It must be a recognised tag */
1376 if ((p_pdcp_lte_info->plane == USER_PLANE) && (seqnumLengthTagPresent == FALSE)) {
1377 /* Conditional field is not present */
1381 if (!infoAlreadySet) {
1382 /* Store info in packet */
1383 p_add_proto_data(wmem_file_scope(), pinfo, proto_pdcp_lte, 0, p_pdcp_lte_info);
1386 /**************************************/
1387 /* OK, now dissect as PDCP LTE */
1389 /* Create tvb that starts at actual PDCP PDU */
1390 pdcp_tvb = tvb_new_subset_remaining(tvb, offset);
1391 dissect_pdcp_lte(pdcp_tvb, pinfo, tree);
1395 /* Called from control protocol to configure security algorithms for the given UE */
1396 void set_pdcp_lte_security_algorithms(guint16 ueid, pdcp_security_info_t *security_info)
1398 /* Use for this frame so can check integrity on SecurityCommandRequest frame */
1399 /* N.B. won't work for internal, non-RRC signalling methods... */
1400 pdcp_security_info_t *p_frame_security;
1402 /* Create or update current settings, by UEID */
1403 pdcp_security_info_t* ue_security =
1404 (pdcp_security_info_t*)g_hash_table_lookup(pdcp_security_hash,
1405 GUINT_TO_POINTER((guint)ueid));
1406 if (ue_security == NULL) {
1407 /* Copy whole security struct */
1408 ue_security = wmem_new(wmem_file_scope(), pdcp_security_info_t);
1409 *ue_security = *security_info;
1411 /* And add into security table */
1412 g_hash_table_insert(pdcp_security_hash, GUINT_TO_POINTER((guint)ueid), ue_security);
1415 /* Just update existing entry already in table */
1416 ue_security->previous_configuration_frame = ue_security->configuration_frame;
1417 ue_security->previous_integrity = ue_security->integrity;
1418 ue_security->previous_ciphering = ue_security->ciphering;
1420 ue_security->configuration_frame = security_info->configuration_frame;
1421 ue_security->integrity = security_info->integrity;
1422 ue_security->ciphering = security_info->ciphering;
1423 ue_security->seen_next_ul_pdu = FALSE;
1426 /* Also add an entry for this PDU already to use these settings, as otherwise it won't be present
1427 when we query it on the first pass. */
1428 p_frame_security = wmem_new(wmem_file_scope(), pdcp_security_info_t);
1429 *p_frame_security = *ue_security;
1430 g_hash_table_insert(pdcp_security_result_hash,
1431 get_ueid_frame_hash_key(ueid, ue_security->configuration_frame, TRUE),
1435 /* UE failed to process SecurityModeCommand so go back to previous security settings */
1436 void set_pdcp_lte_security_algorithms_failed(guint16 ueid)
1438 /* Look up current state by UEID */
1439 pdcp_security_info_t* ue_security =
1440 (pdcp_security_info_t*)g_hash_table_lookup(pdcp_security_hash,
1441 GUINT_TO_POINTER((guint)ueid));
1442 if (ue_security != NULL) {
1443 /* TODO: could remove from table if previous_configuration_frame is 0 */
1444 /* Go back to previous state */
1445 ue_security->configuration_frame = ue_security->previous_configuration_frame;
1446 ue_security->integrity = ue_security->previous_integrity;
1447 ue_security->ciphering = ue_security->previous_ciphering;
1451 /* Decipher payload if algorithm is supported and plausible inputs are available */
1452 static tvbuff_t *decipher_payload(tvbuff_t *tvb, packet_info *pinfo, int *offset,
1453 pdu_security_settings_t *pdu_security_settings,
1454 enum pdcp_plane plane, gboolean will_be_deciphered,
1455 gboolean *deciphered)
1457 guint8* decrypted_data = NULL;
1458 gint payload_length = 0;
1459 tvbuff_t *decrypted_tvb;
1461 /* Nothing to do if NULL ciphering */
1462 if (pdu_security_settings->ciphering == eea0) {
1466 /* Nothing to do if don't have valid cipher key */
1467 if (!pdu_security_settings->cipherKeyValid) {
1471 /* Check whether algorithm supported (only drop through and process if we do) */
1472 if (pdu_security_settings->ciphering == eea1) {
1478 if (pdu_security_settings->ciphering == eea2) {
1479 #ifndef HAVE_LIBGCRYPT
1484 /* An algorithm we don't support at all! */
1488 /* Don't decipher if turned off in preferences */
1489 if (((plane == SIGNALING_PLANE) && !global_pdcp_decipher_signalling) ||
1490 ((plane == USER_PLANE) && !global_pdcp_decipher_userplane)) {
1494 /* Don't decipher control messages */
1495 if ((plane == USER_PLANE) && ((tvb_get_guint8(tvb, 0) & 0x80) == 0x00)) {
1499 /* Don't decipher if not yet past SecurityModeResponse */
1500 if (!will_be_deciphered) {
1504 #ifdef HAVE_LIBGCRYPT
1506 if (pdu_security_settings->ciphering == eea2) {
1507 unsigned char ctr_block[16];
1508 gcry_cipher_hd_t cypher_hd;
1512 memset(ctr_block, 0, 16);
1513 /* Only first 5 bytes set */
1514 ctr_block[0] = (pdu_security_settings->count & 0xff000000) >> 24;
1515 ctr_block[1] = (pdu_security_settings->count & 0x00ff0000) >> 16;
1516 ctr_block[2] = (pdu_security_settings->count & 0x0000ff00) >> 8;
1517 ctr_block[3] = (pdu_security_settings->count & 0x000000ff);
1518 ctr_block[4] = (pdu_security_settings->bearer << 3) + (pdu_security_settings->direction << 2);
1520 /* Open gcrypt handle */
1521 gcrypt_err = gcry_cipher_open(&cypher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0);
1522 if (gcrypt_err != 0) {
1527 gcrypt_err = gcry_cipher_setkey(cypher_hd, pdu_security_settings->cipherKey, 16);
1528 if (gcrypt_err != 0) {
1529 gcry_cipher_close(cypher_hd);
1534 gcrypt_err = gcry_cipher_setctr(cypher_hd, ctr_block, 16);
1535 if (gcrypt_err != 0) {
1536 gcry_cipher_close(cypher_hd);
1540 /* Extract the encrypted data into a buffer */
1541 payload_length = tvb_captured_length_remaining(tvb, *offset);
1542 decrypted_data = (guint8 *)g_malloc0(payload_length);
1543 tvb_memcpy(tvb, decrypted_data, *offset, payload_length);
1545 /* Decrypt the actual data */
1546 gcrypt_err = gcry_cipher_decrypt(cypher_hd,
1547 decrypted_data, payload_length,
1549 if (gcrypt_err != 0) {
1550 gcry_cipher_close(cypher_hd);
1551 g_free(decrypted_data);
1555 /* Close gcrypt handle */
1556 gcry_cipher_close(cypher_hd);
1562 if (pdu_security_settings->ciphering == eea1) {
1563 /* Extract the encrypted data into a buffer */
1564 payload_length = tvb_captured_length_remaining(tvb, *offset);
1565 decrypted_data = (guint8 *)g_malloc0(payload_length+4);
1566 tvb_memcpy(tvb, decrypted_data, *offset, payload_length);
1568 /* Do the algorithm */
1569 snow3g_f8(pdu_security_settings->cipherKey,
1570 pdu_security_settings->count,
1571 pdu_security_settings->bearer,
1572 pdu_security_settings->direction,
1573 decrypted_data, payload_length*8);
1577 /* Create tvb for resulting deciphered sdu */
1578 decrypted_tvb = tvb_new_child_real_data(tvb, decrypted_data, payload_length, payload_length);
1579 tvb_set_free_cb(decrypted_tvb, g_free);
1580 add_new_data_source(pinfo, decrypted_tvb, "Deciphered Payload");
1582 /* Return deciphered data, i.e. beginning of new tvb */
1585 return decrypted_tvb;
1589 /* Try to calculate digest to compare with that found in frame. */
1590 static guint32 calculate_digest(pdu_security_settings_t *pdu_security_settings, guint8 header _U_,
1591 tvbuff_t *tvb _U_, gint offset _U_, gboolean *calculated)
1593 *calculated = FALSE;
1595 if (pdu_security_settings->integrity == eia0) {
1596 /* Should be zero in this case */
1601 /* Can't calculate if don't have valid integrity key */
1602 if (!pdu_security_settings->integrityKeyValid) {
1606 /* Can only do if indicated in preferences */
1607 if (!global_pdcp_check_integrity) {
1611 switch (pdu_security_settings->integrity) {
1617 gint message_length = tvb_captured_length_remaining(tvb, offset) - 4;
1618 guint8 *message_data = (guint8 *)g_malloc0(message_length+5);
1619 message_data[0] = header;
1620 tvb_memcpy(tvb, message_data+1, offset, message_length);
1622 mac = (u8*)snow3g_f9(pdu_security_settings->integrityKey,
1623 pdu_security_settings->count,
1624 /* 'Fresh' is the bearer bits then zeros */
1625 pdu_security_settings->bearer << 27,
1626 pdu_security_settings->direction,
1628 (message_length+1)*8);
1631 g_free(message_data);
1632 return ((mac[0] << 24) | (mac[1] << 16) | (mac[2] << 8) | mac[3]);
1636 #if (defined GCRYPT_VERSION_NUMBER) && (GCRYPT_VERSION_NUMBER >= 0x010600)
1639 gcry_mac_hd_t mac_hd;
1641 gint message_length;
1642 guint8 *message_data;
1644 size_t read_digest_length = 4;
1646 /* Open gcrypt handle */
1647 /* N.B. Unfortunately GCRY_MAC_CMAC_AES is not available in currently used version of gcrypt! */
1648 gcrypt_err = gcry_mac_open(&mac_hd, GCRY_MAC_CMAC_AES, 0, NULL);
1649 if (gcrypt_err != 0) {
1654 gcrypt_err = gcry_mac_setkey(mac_hd, pdu_security_settings->integrityKey, 16);
1655 if (gcrypt_err != 0) {
1656 gcry_mac_close(mac_hd);
1660 /* Extract the encrypted data into a buffer */
1661 message_length = tvb_captured_length_remaining(tvb, offset) - 4;
1662 message_data = (guint8 *)g_malloc0(message_length+9);
1663 message_data[0] = (pdu_security_settings->count & 0xff000000) >> 24;
1664 message_data[1] = (pdu_security_settings->count & 0x00ff0000) >> 16;
1665 message_data[2] = (pdu_security_settings->count & 0x0000ff00) >> 8;
1666 message_data[3] = (pdu_security_settings->count & 0x000000ff);
1667 message_data[4] = (pdu_security_settings->bearer << 3) + (pdu_security_settings->direction << 2);
1668 /* rest of first 8 bytes are left as zeroes... */
1669 message_data[8] = header;
1670 tvb_memcpy(tvb, message_data+9, offset, message_length);
1672 /* Pass in the message */
1673 gcrypt_err = gcry_mac_write(mac_hd, message_data, message_length+9);
1674 if (gcrypt_err != 0) {
1675 gcry_mac_close(mac_hd);
1676 g_free(message_data);
1680 /* Read out the digest */
1681 gcrypt_err = gcry_mac_read(mac_hd, mac, &read_digest_length);
1682 if (gcrypt_err != 0) {
1683 gcry_mac_close(mac_hd);
1684 g_free(message_data);
1688 /* Now close the mac handle */
1689 gcry_mac_close(mac_hd);
1691 g_free(message_data);
1694 return ((mac[0] << 24) | (mac[1] << 16) | (mac[2] << 8) | mac[3]);
1699 /* Can't calculate */
1700 *calculated = FALSE;
1707 /******************************/
1708 /* Main dissection function. */
1709 static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1712 proto_tree *pdcp_tree = NULL;
1713 proto_item *root_ti = NULL;
1715 struct pdcp_lte_info *p_pdcp_info;
1716 tvbuff_t *rohc_tvb = NULL;
1718 pdcp_security_info_t *current_security = NULL; /* current security for this UE */
1719 pdcp_security_info_t *pdu_security; /* security in place for this PDU */
1720 proto_tree *security_tree = NULL;
1721 proto_item *security_ti;
1722 tvbuff_t *payload_tvb;
1723 pdu_security_settings_t pdu_security_settings;
1724 gboolean payload_deciphered = FALSE;
1726 /* Initialise security settings */
1727 memset(&pdu_security_settings, 0, sizeof(pdu_security_settings));
1729 /* Set protocol name. */
1730 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PDCP-LTE");
1732 /* Look for attached packet info! */
1733 p_pdcp_info = (struct pdcp_lte_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pdcp_lte, 0);
1734 /* Can't dissect anything without it... */
1735 if (p_pdcp_info == NULL) {
1739 /* Don't want to overwrite the RLC Info column if configured not to */
1740 if ((global_pdcp_lte_layer_to_show == ShowRLCLayer) &&
1741 (p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0) != NULL)) {
1743 col_set_writable(pinfo->cinfo, FALSE);
1746 /* TODO: won't help with multiple PDCP-or-traffic PDUs / frame... */
1747 col_clear(pinfo->cinfo, COL_INFO);
1748 col_set_writable(pinfo->cinfo, TRUE);
1751 /* Create pdcp tree. */
1753 root_ti = proto_tree_add_item(tree, proto_pdcp_lte, tvb, offset, -1, ENC_NA);
1754 pdcp_tree = proto_item_add_subtree(root_ti, ett_pdcp);
1757 /* Set mode string */
1758 mode = val_to_str_const(p_pdcp_info->rohc.mode, rohc_mode_vals, "Error");
1760 /*****************************************************/
1761 /* Show configuration (attached packet) info in tree */
1763 show_pdcp_config(pinfo, tvb, pdcp_tree, p_pdcp_info);
1766 /* Show ROHC mode */
1767 if (p_pdcp_info->rohc.rohc_compression) {
1768 col_append_fstr(pinfo->cinfo, COL_INFO, " (mode=%c)", mode[0]);
1771 /***************************************/
1772 /* UE security algorithms */
1773 if (!pinfo->fd->flags.visited) {
1774 /* Look up current state by UEID */
1775 current_security = (pdcp_security_info_t*)g_hash_table_lookup(pdcp_security_hash,
1776 GUINT_TO_POINTER((guint)p_pdcp_info->ueid));
1777 if (current_security != NULL) {
1778 /* Store any result for this frame in the result table */
1779 pdcp_security_info_t *security_to_store = wmem_new(wmem_file_scope(), pdcp_security_info_t);
1780 /* Take a deep copy of the settings */
1781 *security_to_store = *current_security;
1782 g_hash_table_insert(pdcp_security_result_hash,
1783 get_ueid_frame_hash_key(p_pdcp_info->ueid, pinfo->fd->num, TRUE),
1788 /* Show security settings for this PDU */
1789 pdu_security = (pdcp_security_info_t*)g_hash_table_lookup(pdcp_security_result_hash, get_ueid_frame_hash_key(p_pdcp_info->ueid, pinfo->fd->num, FALSE));
1790 if (pdu_security != NULL) {
1793 /* Create subtree */
1794 security_ti = proto_tree_add_string_format(pdcp_tree,
1795 hf_pdcp_lte_security,
1798 security_tree = proto_item_add_subtree(security_ti, ett_pdcp_security);
1799 PROTO_ITEM_SET_GENERATED(security_ti);
1802 ti = proto_tree_add_uint(security_tree, hf_pdcp_lte_security_setup_frame,
1803 tvb, 0, 0, pdu_security->configuration_frame);
1804 PROTO_ITEM_SET_GENERATED(ti);
1807 ti = proto_tree_add_uint(security_tree, hf_pdcp_lte_security_ciphering_algorithm,
1808 tvb, 0, 0, pdu_security->ciphering);
1809 PROTO_ITEM_SET_GENERATED(ti);
1812 ti = proto_tree_add_uint(security_tree, hf_pdcp_lte_security_integrity_algorithm,
1813 tvb, 0, 0, pdu_security->integrity);
1814 PROTO_ITEM_SET_GENERATED(ti);
1816 proto_item_append_text(security_ti, " (ciphering=%s, integrity=%s)",
1817 val_to_str_const(pdu_security->ciphering, ciphering_algorithm_vals, "Unknown"),
1818 val_to_str_const(pdu_security->integrity, integrity_algorithm_vals, "Unknown"));
1820 pdu_security_settings.ciphering = pdu_security->ciphering;
1821 pdu_security_settings.integrity = pdu_security->integrity;
1825 /***********************************/
1826 /* Handle PDCP header (if present) */
1827 if (!p_pdcp_info->no_header_pdu) {
1829 /* TODO: shouldn't need to initialise this one!! */
1831 gboolean seqnum_set = FALSE;
1833 guint8 first_byte = tvb_get_guint8(tvb, offset);
1835 /*****************************/
1836 /* Signalling plane messages */
1837 if (p_pdcp_info->plane == SIGNALING_PLANE) {
1838 /* Verify 3 reserved bits are 0 */
1839 guint8 reserved = (first_byte & 0xe0) >> 5;
1840 proto_item *ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_control_plane_reserved,
1841 tvb, offset, 1, ENC_BIG_ENDIAN);
1842 if (reserved != 0) {
1843 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_reserved_bits_not_zero,
1844 "PDCP signalling header reserved bits not zero");
1847 /* 5-bit sequence number */
1848 seqnum = first_byte & 0x1f;
1850 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_5, tvb, offset, 1, ENC_BIG_ENDIAN);
1851 write_pdu_label_and_info(root_ti, pinfo, " sn=%-2u ", seqnum);
1854 if (tvb_reported_length_remaining(tvb, offset) == 0) {
1855 /* Only PDCP header was captured, stop dissection here */
1859 else if (p_pdcp_info->plane == USER_PLANE) {
1861 /**********************************/
1862 /* User-plane messages */
1863 gboolean pdu_type = (first_byte & 0x80) >> 7;
1865 /* Data/Control flag */
1866 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_data_control, tvb, offset, 1, ENC_BIG_ENDIAN);
1868 if (pdu_type == 1) {
1869 /*****************************/
1870 /* Use-plane Data */
1872 /* Number of sequence number bits depends upon config */
1873 switch (p_pdcp_info->seqnum_length) {
1874 case PDCP_SN_LENGTH_7_BITS:
1875 seqnum = first_byte & 0x7f;
1877 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_7, tvb, offset, 1, ENC_BIG_ENDIAN);
1880 case PDCP_SN_LENGTH_12_BITS:
1883 guint8 reserved_value;
1885 /* 3 reserved bits */
1886 ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_reserved3, tvb, offset, 1, ENC_BIG_ENDIAN);
1887 reserved_value = (first_byte & 0x70) >> 4;
1889 /* Complain if not 0 */
1890 if (reserved_value != 0) {
1891 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_reserved_bits_not_zero,
1892 "Reserved bits have value 0x%x - should be 0x0",
1896 /* 12-bit sequence number */
1897 seqnum = tvb_get_ntohs(tvb, offset) & 0x0fff;
1899 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_12, tvb, offset, 2, ENC_BIG_ENDIAN);
1903 case PDCP_SN_LENGTH_15_BITS:
1904 seqnum = tvb_get_ntohs(tvb, offset) & 0x7fff;
1906 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_15, tvb, offset, 2, ENC_BIG_ENDIAN);
1910 /* Not a recognised data format!!!!! */
1914 write_pdu_label_and_info(root_ti, pinfo, " (SN=%u)", seqnum);
1917 /*******************************/
1918 /* User-plane Control messages */
1919 guint8 control_pdu_type = (first_byte & 0x70) >> 4;
1920 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_control_pdu_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1922 switch (control_pdu_type) {
1923 case 0: /* PDCP status report */
1928 guint not_received = 0;
1930 guint32 len, bit_offset;
1931 proto_tree *bitmap_tree;
1932 proto_item *bitmap_ti = NULL;
1934 #define BUFF_SIZE 49
1936 if (p_pdcp_info->seqnum_length == PDCP_SN_LENGTH_12_BITS) {
1937 /* First-Missing-Sequence SN */
1938 fms = tvb_get_ntohs(tvb, offset) & 0x0fff;
1939 sn = (fms + 1) % 4096;
1940 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_fms, tvb,
1941 offset, 2, ENC_BIG_ENDIAN);
1946 guint8 reserved_value;
1948 /* 5 reserved bits */
1949 ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_reserved4, tvb, offset, 2, ENC_BIG_ENDIAN);
1950 reserved_value = (tvb_get_ntohs(tvb, offset) & 0x0f80)>>7;
1953 /* Complain if not 0 */
1954 if (reserved_value != 0) {
1955 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_reserved_bits_not_zero,
1956 "Reserved bits have value 0x%x - should be 0x0",
1960 /* First-Missing-Sequence SN */
1961 fms = tvb_get_ntohs(tvb, offset) & 0x7fff;
1962 sn = (fms + 1) % 32768;
1963 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_fms2, tvb,
1964 offset, 2, ENC_BIG_ENDIAN);
1970 if (tvb_reported_length_remaining(tvb, offset) > 0) {
1971 bitmap_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_bitmap, tvb,
1972 offset, -1, ENC_NA);
1973 bitmap_tree = proto_item_add_subtree(bitmap_ti, ett_pdcp_report_bitmap);
1975 buff = (gchar *)wmem_alloc(wmem_packet_scope(), BUFF_SIZE);
1976 len = tvb_reported_length_remaining(tvb, offset);
1977 bit_offset = offset<<3;
1978 /* For each byte... */
1979 for (i=0; i<len; i++) {
1980 bits = tvb_get_bits8(tvb, bit_offset, 8);
1981 for (l=0, j=0; l<8; l++) {
1982 if ((bits << l) & 0x80) {
1983 j += g_snprintf(&buff[j], BUFF_SIZE-j, "%5u,", (unsigned)(sn+(8*i)+l)%modulo);
1985 j += g_snprintf(&buff[j], BUFF_SIZE-j, " ,");
1989 proto_tree_add_text(bitmap_tree, tvb, bit_offset/8, 1, "%s", buff);
1994 if (bitmap_ti != NULL) {
1995 proto_item_append_text(bitmap_ti, " (%u SNs not received)", not_received);
1997 write_pdu_label_and_info(root_ti, pinfo, " Status Report (fms=%u) not-received=%u",
2002 case 1: /* ROHC Feedback */
2004 break; /* Drop-through to dissect feedback */
2006 default: /* Reserved */
2012 /* Invalid plane setting...! */
2013 write_pdu_label_and_info(root_ti, pinfo, " - INVALID PLANE (%u)",
2014 p_pdcp_info->plane);
2018 /* Do sequence analysis if configured to. */
2020 gboolean do_analysis = FALSE;
2022 switch (global_pdcp_check_sequence_numbers) {
2025 case SEQUENCE_ANALYSIS_RLC_ONLY:
2026 if ((p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0) != NULL) &&
2027 !p_pdcp_info->is_retx) {
2031 case SEQUENCE_ANALYSIS_PDCP_ONLY:
2032 if (p_get_proto_data(wmem_file_scope(), pinfo, proto_rlc_lte, 0) == NULL) {
2039 checkChannelSequenceInfo(pinfo, tvb, p_pdcp_info,
2040 (guint16)seqnum, pdcp_tree, security_tree,
2041 &pdu_security_settings);
2046 /* Show that it's a no-header PDU */
2047 write_pdu_label_and_info(root_ti, pinfo, " No-Header ");
2050 /*******************************************************/
2051 /* Now deal with the payload */
2052 /*******************************************************/
2054 /* Check pdu_security_settings - may need to do deciphering before calling
2055 further dissectors on payload */
2056 payload_tvb = decipher_payload(tvb, pinfo, &offset, &pdu_security_settings, p_pdcp_info->plane,
2057 pdu_security ? pdu_security->seen_next_ul_pdu: FALSE, &payload_deciphered);
2059 if (p_pdcp_info->plane == SIGNALING_PLANE) {
2060 guint32 data_length;
2063 guint32 calculated_digest = 0;
2064 gboolean digest_was_calculated = FALSE;
2066 /* Try to calculate digest so we can check it */
2067 if (global_pdcp_check_integrity) {
2068 calculated_digest = calculate_digest(&pdu_security_settings, tvb_get_guint8(tvb, 0), payload_tvb,
2069 offset, &digest_was_calculated);
2072 /* RRC data is all but last 4 bytes.
2073 Call lte-rrc dissector (according to direction and channel type) if we have valid data */
2074 if ((global_pdcp_dissect_signalling_plane_as_rrc) &&
2075 ((pdu_security == NULL) || (pdu_security->ciphering == eea0) || payload_deciphered || !pdu_security->seen_next_ul_pdu)) {
2076 /* Get appropriate dissector handle */
2077 dissector_handle_t rrc_handle = lookup_rrc_dissector_handle(p_pdcp_info);
2079 if (rrc_handle != 0) {
2080 /* Call RRC dissector if have one */
2081 tvbuff_t *rrc_payload_tvb = tvb_new_subset(payload_tvb, offset,
2082 tvb_captured_length_remaining(payload_tvb, offset) - 4,
2083 tvb_reported_length_remaining(payload_tvb, offset) - 4);
2084 gboolean was_writable = col_get_writable(pinfo->cinfo);
2086 /* We always want to see this in the info column */
2087 col_set_writable(pinfo->cinfo, TRUE);
2089 call_dissector_only(rrc_handle, rrc_payload_tvb, pinfo, pdcp_tree, NULL);
2091 /* Restore to whatever it was */
2092 col_set_writable(pinfo->cinfo, was_writable);
2095 /* Just show data */
2096 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, payload_tvb, offset,
2097 tvb_reported_length_remaining(tvb, offset) - 4, ENC_NA);
2100 if (!pinfo->fd->flags.visited &&
2101 (current_security != NULL) && !current_security->seen_next_ul_pdu &&
2102 p_pdcp_info->direction == DIRECTION_UPLINK)
2104 /* i.e. we have already seen SecurityModeResponse! */
2105 current_security->seen_next_ul_pdu = TRUE;
2110 /* Just show as unparsed data */
2111 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, payload_tvb, offset,
2112 tvb_reported_length_remaining(tvb, offset) - 4, ENC_NA);
2115 data_length = tvb_reported_length_remaining(payload_tvb, offset) - 4;
2116 offset += data_length;
2118 /* Last 4 bytes are MAC */
2119 mac = tvb_get_ntohl(payload_tvb, offset);
2120 mac_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_mac, payload_tvb, offset, 4, ENC_BIG_ENDIAN);
2123 if (digest_was_calculated) {
2124 /* Compare what was found with calculated value! */
2125 if (mac != calculated_digest) {
2126 expert_add_info_format(pinfo, mac_ti, &ei_pdcp_lte_digest_wrong,
2127 "MAC-I Digest wrong expected %08x but found %08x",
2128 calculated_digest, mac);
2131 proto_item_append_text(mac_ti, " [Matches calculated result]");
2135 col_append_fstr(pinfo->cinfo, COL_INFO, " MAC=0x%08x (%u bytes data)",
2139 /* User-plane payload here */
2141 /* If not compressed with ROHC, show as user-plane data */
2142 if (!p_pdcp_info->rohc.rohc_compression) {
2143 gint payload_length = tvb_reported_length_remaining(payload_tvb, offset);
2144 if (payload_length > 0) {
2145 if (p_pdcp_info->plane == USER_PLANE) {
2147 /* Not attempting to decode payload if ciphering is enabled
2148 (and NULL ciphering is not being used) */
2149 if (global_pdcp_dissect_user_plane_as_ip &&
2150 ((pdu_security == NULL) || (pdu_security->ciphering == eea0) || payload_deciphered))
2152 tvbuff_t *ip_payload_tvb = tvb_new_subset_remaining(payload_tvb, offset);
2154 /* Don't update info column for ROHC unless configured to */
2155 if (global_pdcp_lte_layer_to_show != ShowTrafficLayer) {
2156 col_set_writable(pinfo->cinfo, FALSE);
2159 switch (tvb_get_guint8(ip_payload_tvb, 0) & 0xf0) {
2161 call_dissector_only(ip_handle, ip_payload_tvb, pinfo, pdcp_tree, NULL);
2164 call_dissector_only(ipv6_handle, ip_payload_tvb, pinfo, pdcp_tree, NULL);
2167 call_dissector_only(data_handle, ip_payload_tvb, pinfo, pdcp_tree, NULL);
2171 /* Freeze the columns again because we don't want other layers writing to info */
2172 if (global_pdcp_lte_layer_to_show == ShowTrafficLayer) {
2173 col_set_writable(pinfo->cinfo, FALSE);
2178 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_user_plane_data, payload_tvb, offset, -1, ENC_NA);
2182 write_pdu_label_and_info(root_ti, pinfo, "(%u bytes data)",
2186 /* (there will be no signalling data left at this point) */
2188 /* Let RLC write to columns again */
2189 col_set_writable(pinfo->cinfo, global_pdcp_lte_layer_to_show == ShowRLCLayer);
2191 /* DROPPING OUT HERE IF NOT DOING ROHC! */
2195 /***************************/
2197 /***************************/
2199 /* Only attempt ROHC if configured to */
2200 if (!global_pdcp_dissect_rohc) {
2201 col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "|ROHC(%s)",
2202 val_to_str_const(p_pdcp_info->rohc.profile, rohc_profile_vals, "Unknown"));
2206 rohc_tvb = tvb_new_subset_remaining(payload_tvb, offset);
2208 /* Only enable writing to column if configured to show ROHC */
2209 if (global_pdcp_lte_layer_to_show != ShowTrafficLayer) {
2210 col_set_writable(pinfo->cinfo, FALSE);
2213 col_clear(pinfo->cinfo, COL_INFO);
2216 /* Call the ROHC dissector */
2217 call_dissector_with_data(rohc_handle, rohc_tvb, pinfo, tree, &p_pdcp_info->rohc);
2219 /* Let RLC write to columns again */
2220 col_set_writable(pinfo->cinfo, global_pdcp_lte_layer_to_show == ShowRLCLayer);
2225 /* Initializes the hash tables each time a new
2226 * file is loaded or re-loaded in wireshark */
2227 static void pdcp_lte_init_protocol(void)
2229 /* Destroy any existing hashes. */
2230 if (pdcp_sequence_analysis_channel_hash) {
2231 g_hash_table_destroy(pdcp_sequence_analysis_channel_hash);
2233 if (pdcp_lte_sequence_analysis_report_hash) {
2234 g_hash_table_destroy(pdcp_lte_sequence_analysis_report_hash);
2236 if (pdcp_security_hash) {
2237 g_hash_table_destroy(pdcp_security_hash);
2239 if (pdcp_security_result_hash) {
2240 g_hash_table_destroy(pdcp_security_result_hash);
2242 if (pdcp_security_key_hash) {
2243 g_hash_table_destroy(pdcp_security_key_hash);
2247 /* Now create them over */
2248 pdcp_sequence_analysis_channel_hash = g_hash_table_new(pdcp_channel_hash_func, pdcp_channel_equal);
2249 pdcp_lte_sequence_analysis_report_hash = g_hash_table_new(pdcp_result_hash_func, pdcp_result_hash_equal);
2250 pdcp_security_hash = g_hash_table_new(pdcp_lte_ueid_hash_func, pdcp_lte_ueid_hash_equal);
2251 pdcp_security_result_hash = g_hash_table_new(pdcp_lte_ueid_frame_hash_func, pdcp_lte_ueid_frame_hash_equal);
2252 pdcp_security_key_hash = g_hash_table_new(pdcp_lte_ueid_hash_func, pdcp_lte_ueid_hash_equal);
2257 void proto_register_pdcp(void)
2259 static hf_register_info hf[] =
2261 { &hf_pdcp_lte_configuration,
2263 "pdcp-lte.configuration", FT_STRING, BASE_NONE, NULL, 0x0,
2264 "Configuration info passed into dissector", HFILL
2268 { &hf_pdcp_lte_rohc_compression,
2269 { "ROHC Compression",
2270 "pdcp-lte.rohc.compression", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2274 { &hf_pdcp_lte_rohc_mode,
2276 "pdcp-lte.rohc.mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x0,
2280 { &hf_pdcp_lte_rohc_rnd,
2282 "pdcp-lte.rohc.rnd", FT_UINT8, BASE_DEC, NULL, 0x0,
2283 "RND of outer ip header", HFILL
2286 { &hf_pdcp_lte_rohc_udp_checksum_present,
2288 "pdcp-lte.rohc.checksum-present", FT_UINT8, BASE_DEC, NULL, 0x0,
2289 "UDP Checksum present", HFILL
2292 { &hf_pdcp_lte_direction,
2294 "pdcp-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
2295 "Direction of message", HFILL
2298 { &hf_pdcp_lte_ueid,
2300 "pdcp-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
2301 "UE Identifier", HFILL
2304 { &hf_pdcp_lte_channel_type,
2306 "pdcp-lte.channel-type", FT_UINT8, BASE_DEC, VALS(logical_channel_vals), 0x0,
2310 { &hf_pdcp_lte_channel_id,
2312 "pdcp-lte.channel-id", FT_UINT8, BASE_DEC, 0, 0x0,
2316 { &hf_pdcp_lte_rohc_profile,
2318 "pdcp-lte.rohc.profile", FT_UINT8, BASE_DEC, VALS(rohc_profile_vals), 0x0,
2322 { &hf_pdcp_lte_no_header_pdu,
2324 "pdcp-lte.no-header_pdu", FT_UINT8, BASE_DEC, NULL, 0x0,
2328 { &hf_pdcp_lte_plane,
2330 "pdcp-lte.plane", FT_UINT8, BASE_DEC, VALS(pdcp_plane_vals), 0x0,
2334 { &hf_pdcp_lte_seqnum_length,
2336 "pdcp-lte.seqnum_length", FT_UINT8, BASE_DEC, NULL, 0x0,
2337 "Sequence Number Length", HFILL
2342 { &hf_pdcp_lte_cid_inclusion_info,
2343 { "CID Inclusion Info",
2344 "pdcp-lte.cid-inclusion-info", FT_UINT8, BASE_DEC, NULL, 0x0,
2348 { &hf_pdcp_lte_large_cid_present,
2349 { "Large CID Present",
2350 "pdcp-lte.large-cid-present", FT_UINT8, BASE_DEC, NULL, 0x0,
2355 { &hf_pdcp_lte_control_plane_reserved,
2357 "pdcp-lte.reserved", FT_UINT8, BASE_DEC, NULL, 0xe0,
2361 { &hf_pdcp_lte_seq_num_5,
2363 "pdcp-lte.seq-num", FT_UINT8, BASE_DEC, NULL, 0x1f,
2364 "PDCP Seq num", HFILL
2367 { &hf_pdcp_lte_seq_num_7,
2369 "pdcp-lte.seq-num", FT_UINT8, BASE_DEC, NULL, 0x7f,
2370 "PDCP Seq num", HFILL
2373 { &hf_pdcp_lte_reserved3,
2375 "pdcp-lte.reserved3", FT_UINT8, BASE_HEX, NULL, 0x70,
2376 "3 reserved bits", HFILL
2379 { &hf_pdcp_lte_seq_num_12,
2381 "pdcp-lte.seq-num", FT_UINT16, BASE_DEC, NULL, 0x0fff,
2382 "PDCP Seq num", HFILL
2385 { &hf_pdcp_lte_seq_num_15,
2387 "pdcp-lte.seq-num", FT_UINT16, BASE_DEC, NULL, 0x7fff,
2388 "PDCP Seq num", HFILL
2391 { &hf_pdcp_lte_signalling_data,
2392 { "Signalling Data",
2393 "pdcp-lte.signalling-data", FT_BYTES, BASE_NONE, NULL, 0x0,
2399 "pdcp-lte.mac", FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
2403 { &hf_pdcp_lte_data_control,
2405 "pdcp-lte.pdu-type", FT_UINT8, BASE_HEX, VALS(pdu_type_vals), 0x80,
2409 { &hf_pdcp_lte_user_plane_data,
2410 { "User-Plane Data",
2411 "pdcp-lte.user-data", FT_BYTES, BASE_NONE, NULL, 0x0,
2415 { &hf_pdcp_lte_control_pdu_type,
2416 { "Control PDU Type",
2417 "pdcp-lte.control-pdu-type", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
2422 { "First Missing Sequence Number",
2423 "pdcp-lte.fms", FT_UINT16, BASE_DEC, NULL, 0x0fff,
2424 "First Missing PDCP Sequence Number", HFILL
2427 { &hf_pdcp_lte_reserved4,
2429 "pdcp-lte.reserved4", FT_UINT16, BASE_HEX, NULL, 0x0f80,
2430 "5 reserved bits", HFILL
2433 { &hf_pdcp_lte_fms2,
2434 { "First Missing Sequence Number",
2435 "pdcp-lte.fms", FT_UINT16, BASE_DEC, NULL, 0x07fff,
2436 "First Missing PDCP Sequence Number", HFILL
2439 { &hf_pdcp_lte_bitmap,
2441 "pdcp-lte.bitmap", FT_NONE, BASE_NONE, NULL, 0x0,
2442 "Status report bitmap (0=error, 1=OK)", HFILL
2447 { &hf_pdcp_lte_sequence_analysis,
2448 { "Sequence Analysis",
2449 "pdcp-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
2453 { &hf_pdcp_lte_sequence_analysis_ok,
2455 "pdcp-lte.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
2459 { &hf_pdcp_lte_sequence_analysis_previous_frame,
2460 { "Previous frame for channel",
2461 "pdcp-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
2465 { &hf_pdcp_lte_sequence_analysis_next_frame,
2466 { "Next frame for channel",
2467 "pdcp-lte.sequence-analysis.next-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
2471 { &hf_pdcp_lte_sequence_analysis_expected_sn,
2473 "pdcp-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
2477 { &hf_pdcp_lte_sequence_analysis_skipped,
2479 "pdcp-lte.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
2483 { &hf_pdcp_lte_sequence_analysis_repeated,
2485 "pdcp-lte.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
2490 { &hf_pdcp_lte_security,
2491 { "Security Config",
2492 "pdcp-lte.security-cofig", FT_STRING, BASE_NONE, 0, 0x0,
2496 { &hf_pdcp_lte_security_setup_frame,
2497 { "Configuration frame",
2498 "pdcp-lte.security-config.setup-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
2502 { &hf_pdcp_lte_security_integrity_algorithm,
2503 { "Integrity Algorithm",
2504 "pdcp-lte.security-config.integrity", FT_UINT16, BASE_DEC, VALS(integrity_algorithm_vals), 0x0,
2508 { &hf_pdcp_lte_security_ciphering_algorithm,
2509 { "Ciphering Algorithm",
2510 "pdcp-lte.security-config.ciphering", FT_UINT16, BASE_DEC, VALS(ciphering_algorithm_vals), 0x0,
2514 { &hf_pdcp_lte_security_bearer,
2516 "pdcp-lte.security-config.bearer", FT_UINT8, BASE_DEC, NULL, 0x0,
2520 { &hf_pdcp_lte_security_direction,
2522 "pdcp-lte.security-config.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
2526 { &hf_pdcp_lte_security_count,
2528 "pdcp-lte.security-config.count", FT_UINT32, BASE_DEC, NULL, 0x0,
2532 { &hf_pdcp_lte_security_cipher_key,
2534 "pdcp-lte.security-config.cipher-key", FT_STRING, BASE_NONE, NULL, 0x0,
2538 { &hf_pdcp_lte_security_integrity_key,
2540 "pdcp-lte.security-config.integrity-key", FT_STRING, BASE_NONE, NULL, 0x0,
2546 static gint *ett[] =
2549 &ett_pdcp_configuration,
2551 &ett_pdcp_lte_sequence_analysis,
2552 &ett_pdcp_report_bitmap,
2556 static ei_register_info ei[] = {
2557 { &ei_pdcp_lte_sequence_analysis_sn_missing, { "pdcp-lte.sequence-analysis.sn-missing", PI_SEQUENCE, PI_WARN, "PDCP SN missing", EXPFILL }},
2558 { &ei_pdcp_lte_sequence_analysis_sn_repeated, { "pdcp-lte.sequence-analysis.sn-repeated", PI_SEQUENCE, PI_WARN, "PDCP SN repeated", EXPFILL }},
2559 { &ei_pdcp_lte_sequence_analysis_wrong_sequence_number, { "pdcp-lte.sequence-analysis.wrong-sequence-number", PI_SEQUENCE, PI_WARN, "Wrong Sequence Number", EXPFILL }},
2560 { &ei_pdcp_lte_reserved_bits_not_zero, { "pdcp-lte.reserved-bits-not-zero", PI_MALFORMED, PI_ERROR, "Reserved bits not zero", EXPFILL }},
2561 { &ei_pdcp_lte_digest_wrong, { "pdcp-lte.maci-wrong", PI_SEQUENCE, PI_ERROR, "MAC-I doesn't match expected value", EXPFILL }}
2564 static const enum_val_t sequence_analysis_vals[] = {
2565 {"no-analysis", "No-Analysis", FALSE},
2566 {"rlc-only", "Only-RLC-frames", SEQUENCE_ANALYSIS_RLC_ONLY},
2567 {"pdcp-only", "Only-PDCP-frames", SEQUENCE_ANALYSIS_PDCP_ONLY},
2571 static const enum_val_t show_info_col_vals[] = {
2572 {"show-rlc", "RLC Info", ShowRLCLayer},
2573 {"show-pdcp", "PDCP Info", ShowPDCPLayer},
2574 {"show-traffic", "Traffic Info", ShowTrafficLayer},
2578 static uat_field_t ue_keys_uat_flds[] = {
2579 UAT_FLD_DEC(uat_ue_keys_records, ueid, "UEId", "UE Identifier of UE associated with keys"),
2580 UAT_FLD_CSTRING(uat_ue_keys_records, rrcCipherKeyString, "RRC Cipher Key", "Key for deciphering signalling messages"),
2581 UAT_FLD_CSTRING(uat_ue_keys_records, upCipherKeyString, "User-Plane Cipher Key", "Key for deciphering user-plane messages"),
2582 UAT_FLD_CSTRING(uat_ue_keys_records, rrcIntegrityKeyString, "RRC Integrity Key", "Key for deciphering user-plane messages"),
2586 module_t *pdcp_lte_module;
2587 expert_module_t* expert_pdcp_lte;
2589 /* Register protocol. */
2590 proto_pdcp_lte = proto_register_protocol("PDCP-LTE", "PDCP-LTE", "pdcp-lte");
2591 proto_register_field_array(proto_pdcp_lte, hf, array_length(hf));
2592 proto_register_subtree_array(ett, array_length(ett));
2593 expert_pdcp_lte = expert_register_protocol(proto_pdcp_lte);
2594 expert_register_field_array(expert_pdcp_lte, ei, array_length(ei));
2596 /* Allow other dissectors to find this one by name. */
2597 register_dissector("pdcp-lte", dissect_pdcp_lte, proto_pdcp_lte);
2599 pdcp_lte_module = prefs_register_protocol(proto_pdcp_lte, NULL);
2601 /* Obsolete preferences */
2602 prefs_register_obsolete_preference(pdcp_lte_module, "show_feedback_option_tag_length");
2605 /* Dissect uncompressed user-plane data as IP */
2606 prefs_register_bool_preference(pdcp_lte_module, "show_user_plane_as_ip",
2607 "Show uncompressed User-Plane data as IP",
2608 "Show uncompressed User-Plane data as IP",
2609 &global_pdcp_dissect_user_plane_as_ip);
2611 /* Dissect unciphered signalling data as RRC */
2612 prefs_register_bool_preference(pdcp_lte_module, "show_signalling_plane_as_rrc",
2613 "Show unciphered Signalling-Plane data as RRC",
2614 "Show unciphered Signalling-Plane data as RRC",
2615 &global_pdcp_dissect_signalling_plane_as_rrc);
2617 /* Check for missing sequence numbers */
2618 prefs_register_enum_preference(pdcp_lte_module, "check_sequence_numbers",
2619 "Do sequence number analysis",
2620 "Do sequence number analysis",
2621 &global_pdcp_check_sequence_numbers, sequence_analysis_vals, FALSE);
2623 /* Attempt to dissect ROHC messages */
2624 prefs_register_bool_preference(pdcp_lte_module, "dissect_rohc",
2625 "Attempt to decode ROHC data",
2626 "Attempt to decode ROHC data",
2627 &global_pdcp_dissect_rohc);
2629 prefs_register_bool_preference(pdcp_lte_module, "heuristic_pdcp_lte_over_udp",
2630 "Try Heuristic LTE-PDCP over UDP framing",
2631 "When enabled, use heuristic dissector to find PDCP-LTE frames sent with "
2633 &global_pdcp_lte_heur);
2635 prefs_register_enum_preference(pdcp_lte_module, "layer_to_show",
2636 "Which layer info to show in Info column",
2637 "Can show RLC, PDCP or Traffic layer info in Info column",
2638 &global_pdcp_lte_layer_to_show, show_info_col_vals, FALSE);
2640 ue_keys_uat = uat_new("PDCP UE security keys",
2641 sizeof(uat_ue_keys_record_t), /* record size */
2642 "pdcp_lte_ue_keys", /* filename */
2643 TRUE, /* from_profile */
2644 &uat_ue_keys_records, /* data_ptr */
2645 &num_ue_keys_uat, /* numitems_ptr */
2646 UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
2648 uat_ue_keys_record_copy_cb, /* copy callback */
2649 uat_ue_keys_record_update_cb, /* update callback */
2650 uat_ue_keys_record_free_cb, /* free callback */
2651 NULL, /* post update callback */
2652 ue_keys_uat_flds); /* UAT field definitions */
2654 prefs_register_uat_preference(pdcp_lte_module,
2657 "Preconfigured PDCP keys",
2660 /* Attempt to decipher RRC messages */
2661 prefs_register_bool_preference(pdcp_lte_module, "decipher_signalling",
2662 "Attempt to decipher Signalling (RRC) SDUs",
2663 "N.B. only possible if build with algorithm support, and have key available and configured",
2664 &global_pdcp_decipher_signalling);
2666 /* Attempt to decipher user-plane messages */
2667 prefs_register_bool_preference(pdcp_lte_module, "decipher_userplane",
2668 "Attempt to decipher User-plane (IP) SDUs",
2669 "N.B. only possible if build with algorithm support, and have key available and configured",
2670 &global_pdcp_decipher_userplane);
2672 /* Attempt to verify RRC integrity/authentication digest */
2673 prefs_register_bool_preference(pdcp_lte_module, "verify_integrity",
2674 "Attempt to check integrity calculation",
2675 "N.B. only possible if build with algorithm support, and have key available and configured",
2676 &global_pdcp_check_integrity);
2678 register_init_routine(&pdcp_lte_init_protocol);
2681 void proto_reg_handoff_pdcp_lte(void)
2683 /* Add as a heuristic UDP dissector */
2684 heur_dissector_add("udp", dissect_pdcp_lte_heur, proto_pdcp_lte);
2686 ip_handle = find_dissector("ip");
2687 ipv6_handle = find_dissector("ipv6");
2688 rohc_handle = find_dissector("rohc");
2689 data_handle = find_dissector("data");
2698 * indent-tabs-mode: nil
2701 * ex: set shiftwidth=4 tabstop=8 expandtab:
2702 * :indentSize=4:tabSize=8:noTabs=true: