HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-pdcp-lte.c
blob8a8b51c84277a9b13a40f8edc353c1ac555f6bb5
1 /* Routines for LTE PDCP
3 * Martin Mathieson
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "config.h"
28 #include <string.h>
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/prefs.h>
33 #include <epan/expert.h>
34 #include <epan/addr_resolv.h>
35 #include <epan/wmem/wmem.h>
37 #include "packet-rlc-lte.h"
38 #include "packet-pdcp-lte.h"
40 /* Described in:
41 * 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA)
42 * Packet Data Convergence Protocol (PDCP) specification v11.0.0
46 /* TODO:
47 - Support for deciphering
48 - Verify MAC authentication bytes
49 - Add Relay Node user plane data PDU dissection
53 /* Initialize the protocol and registered fields. */
54 int proto_pdcp_lte = -1;
56 extern int proto_rlc_lte;
58 /* Configuration (info known outside of PDU) */
59 static int hf_pdcp_lte_configuration = -1;
60 static int hf_pdcp_lte_direction = -1;
61 static int hf_pdcp_lte_ueid = -1;
62 static int hf_pdcp_lte_channel_type = -1;
63 static int hf_pdcp_lte_channel_id = -1;
65 static int hf_pdcp_lte_rohc_compression = -1;
66 static int hf_pdcp_lte_rohc_mode = -1;
67 static int hf_pdcp_lte_rohc_rnd = -1;
68 static int hf_pdcp_lte_rohc_udp_checksum_present = -1;
69 static int hf_pdcp_lte_rohc_profile = -1;
71 static int hf_pdcp_lte_no_header_pdu = -1;
72 static int hf_pdcp_lte_plane = -1;
73 static int hf_pdcp_lte_seqnum_length = -1;
74 static int hf_pdcp_lte_cid_inclusion_info = -1;
75 static int hf_pdcp_lte_large_cid_present = -1;
77 /* PDCP header fields */
78 static int hf_pdcp_lte_control_plane_reserved = -1;
79 static int hf_pdcp_lte_seq_num_5 = -1;
80 static int hf_pdcp_lte_seq_num_7 = -1;
81 static int hf_pdcp_lte_reserved3 = -1;
82 static int hf_pdcp_lte_seq_num_12 = -1;
83 static int hf_pdcp_lte_seq_num_15 = -1;
84 static int hf_pdcp_lte_signalling_data = -1;
85 static int hf_pdcp_lte_mac = -1;
86 static int hf_pdcp_lte_data_control = -1;
87 static int hf_pdcp_lte_user_plane_data = -1;
88 static int hf_pdcp_lte_control_pdu_type = -1;
89 static int hf_pdcp_lte_fms = -1;
90 static int hf_pdcp_lte_reserved4 = -1;
91 static int hf_pdcp_lte_fms2 = -1;
92 static int hf_pdcp_lte_bitmap = -1;
95 /* Sequence Analysis */
96 static int hf_pdcp_lte_sequence_analysis = -1;
97 static int hf_pdcp_lte_sequence_analysis_ok = -1;
98 static int hf_pdcp_lte_sequence_analysis_previous_frame = -1;
99 static int hf_pdcp_lte_sequence_analysis_next_frame = -1;
100 static int hf_pdcp_lte_sequence_analysis_expected_sn = -1;
102 static int hf_pdcp_lte_sequence_analysis_repeated = -1;
103 static int hf_pdcp_lte_sequence_analysis_skipped = -1;
105 /* Security Settings */
106 static int hf_pdcp_lte_security = -1;
107 static int hf_pdcp_lte_security_setup_frame = -1;
108 static int hf_pdcp_lte_security_integrity_algorithm = -1;
109 static int hf_pdcp_lte_security_ciphering_algorithm = -1;
112 /* Protocol subtree. */
113 static int ett_pdcp = -1;
114 static int ett_pdcp_configuration = -1;
115 static int ett_pdcp_packet = -1;
116 static int ett_pdcp_lte_sequence_analysis = -1;
117 static int ett_pdcp_report_bitmap = -1;
118 static int ett_pdcp_security = -1;
120 static expert_field ei_pdcp_lte_sequence_analysis_wrong_sequence_number = EI_INIT;
121 static expert_field ei_pdcp_lte_reserved_bits_not_zero = EI_INIT;
122 static expert_field ei_pdcp_lte_sequence_analysis_sn_repeated = EI_INIT;
123 static expert_field ei_pdcp_lte_sequence_analysis_sn_missing = EI_INIT;
125 static const value_string direction_vals[] =
127 { DIRECTION_UPLINK, "Uplink"},
128 { DIRECTION_DOWNLINK, "Downlink"},
129 { 0, NULL }
133 static const value_string pdcp_plane_vals[] = {
134 { SIGNALING_PLANE, "Signalling" },
135 { USER_PLANE, "User" },
136 { 0, NULL }
139 static const value_string logical_channel_vals[] = {
140 { Channel_DCCH, "DCCH"},
141 { Channel_BCCH, "BCCH"},
142 { Channel_CCCH, "CCCH"},
143 { Channel_PCCH, "PCCH"},
144 { 0, NULL}
147 static const value_string rohc_mode_vals[] = {
148 { UNIDIRECTIONAL, "Unidirectional" },
149 { OPTIMISTIC_BIDIRECTIONAL, "Optimistic Bidirectional" },
150 { RELIABLE_BIDIRECTIONAL, "Reliable Bidirectional" },
151 { 0, NULL }
155 /* Values taken from:
156 http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.txt */
157 static const value_string rohc_profile_vals[] = {
158 { 0x0000, "ROHC uncompressed" }, /* [RFC5795] */
159 { 0x0001, "ROHC RTP" }, /* [RFC3095] */
160 { 0x0101, "ROHCv2 RTP" }, /* [RFC5225] */
161 { 0x0002, "ROHC UDP" }, /* [RFC3095] */
162 { 0x0102, "ROHCv2 UDP" }, /* [RFC5225] */
163 { 0x0003, "ROHC ESP" }, /* [RFC3095] */
164 { 0x0103, "ROHCv2 ESP" }, /* [RFC5225] */
165 { 0x0004, "ROHC IP" }, /* [RFC3843] */
166 { 0x0104, "ROHCv2 IP" }, /* [RFC5225] */
167 { 0x0005, "ROHC LLA" }, /* [RFC4362] */
168 { 0x0105, "ROHC LLA with R-mode" }, /* [RFC3408] */
169 { 0x0006, "ROHC TCP" }, /* [RFC4996] */
170 { 0x0007, "ROHC RTP/UDP-Lite" }, /* [RFC4019] */
171 { 0x0107, "ROHCv2 RTP/UDP-Lite" }, /* [RFC5225] */
172 { 0x0008, "ROHC UDP-Lite" }, /* [RFC4019] */
173 { 0x0108, "ROHCv2 UDP-Lite" }, /* [RFC5225] */
174 { 0, NULL }
177 static const value_string pdu_type_vals[] = {
178 { 0, "Control PDU" },
179 { 1, "Data PDU" },
180 { 0, NULL }
183 static const value_string control_pdu_type_vals[] = {
184 { 0, "PDCP Status report" },
185 { 1, "Header Compression Feedback Information" },
186 { 0, NULL }
189 static const value_string integrity_algorithm_vals[] = {
190 { 0, "EIA0" },
191 { 1, "EIA1" },
192 { 2, "EIA2" },
193 { 0, NULL }
196 static const value_string ciphering_algorithm_vals[] = {
197 { 0, "EEA0" },
198 { 1, "EEA1" },
199 { 2, "EEA2" },
200 { 0, NULL }
204 static dissector_handle_t ip_handle;
205 static dissector_handle_t ipv6_handle;
206 static dissector_handle_t rohc_handle;
207 static dissector_handle_t data_handle;
210 #define SEQUENCE_ANALYSIS_RLC_ONLY 1
211 #define SEQUENCE_ANALYSIS_PDCP_ONLY 2
213 /* Preference variables */
214 static gboolean global_pdcp_dissect_user_plane_as_ip = TRUE;
215 static gboolean global_pdcp_dissect_signalling_plane_as_rrc = TRUE;
216 static gint global_pdcp_check_sequence_numbers = TRUE;
217 static gboolean global_pdcp_dissect_rohc = FALSE;
219 /* Which layer info to show in the info column */
220 enum layer_to_show {
221 ShowRLCLayer, ShowPDCPLayer, ShowTrafficLayer
223 static gint global_pdcp_lte_layer_to_show = (gint)ShowRLCLayer;
227 /**************************************************/
228 /* Sequence number analysis */
230 /* Channel key */
231 typedef struct
233 /* Using bit fields to fit into 32 bits, so avoiding the need to allocate
234 heap memory for these structs */
235 guint ueId : 16;
236 guint plane : 2;
237 guint channelId : 6;
238 guint direction : 1;
239 guint notUsed : 7;
240 } pdcp_channel_hash_key;
242 /* Channel state */
243 typedef struct
245 guint16 previousSequenceNumber;
246 guint32 previousFrameNum;
247 } pdcp_channel_status;
249 /* The sequence analysis channel hash table.
250 Maps key -> status */
251 static GHashTable *pdcp_sequence_analysis_channel_hash = NULL;
253 /* Equal keys */
254 static gint pdcp_channel_equal(gconstpointer v, gconstpointer v2)
256 /* Key fits in 4 bytes, so just compare pointers! */
257 return (v == v2);
260 /* Compute a hash value for a given key. */
261 static guint pdcp_channel_hash_func(gconstpointer v)
263 /* Just use pointer, as the fields are all in this value */
264 return GPOINTER_TO_UINT(v);
268 /* Hash table types & functions for frame reports */
270 typedef struct {
271 guint32 frameNumber;
272 guint32 SN : 15;
273 guint32 plane : 2;
274 guint32 channelId: 5;
275 guint32 direction: 1;
276 guint32 notUsed : 9;
277 } pdcp_result_hash_key;
279 static gint pdcp_result_hash_equal(gconstpointer v, gconstpointer v2)
281 const pdcp_result_hash_key* val1 = (const pdcp_result_hash_key *)v;
282 const pdcp_result_hash_key* val2 = (const pdcp_result_hash_key *)v2;
284 /* All fields must match */
285 return (memcmp(val1, val2, sizeof(pdcp_result_hash_key)) == 0);
288 /* Compute a hash value for a given key. */
289 static guint pdcp_result_hash_func(gconstpointer v)
291 const pdcp_result_hash_key* val1 = (const pdcp_result_hash_key *)v;
293 /* TODO: check collision-rate / execution-time of these multipliers? */
294 return val1->frameNumber + (val1->channelId<<13) +
295 (val1->plane<<5) +
296 (val1->SN<<18) +
297 (val1->direction<<9);
300 /* pdcp_channel_hash_key fits into the pointer, so just copy the value into
301 a guint, cast to apointer and return that as the key */
302 static gpointer get_channel_hash_key(pdcp_channel_hash_key *key)
304 guint asInt = 0;
305 /* TODO: assert that sizeof(pdcp_channel_hash_key) <= sizeof(guint) ? */
306 memcpy(&asInt, key, sizeof(pdcp_channel_hash_key));
307 return GUINT_TO_POINTER(asInt);
310 /* Convenience function to get a pointer for the hash_func to work with */
311 static gpointer get_report_hash_key(guint16 SN, guint32 frameNumber,
312 pdcp_lte_info *p_pdcp_lte_info,
313 gboolean do_persist)
315 static pdcp_result_hash_key key;
316 pdcp_result_hash_key *p_key;
318 /* Only allocate a struct when will be adding entry */
319 if (do_persist) {
320 p_key = wmem_new(wmem_file_scope(), pdcp_result_hash_key);
322 else {
323 memset(&key, 0, sizeof(pdcp_result_hash_key));
324 p_key = &key;
327 /* Fill in details, and return pointer */
328 p_key->frameNumber = frameNumber;
329 p_key->SN = SN;
330 p_key->plane = (guint8)p_pdcp_lte_info->plane;
331 p_key->channelId = p_pdcp_lte_info->channelId;
332 p_key->direction = p_pdcp_lte_info->direction;
333 p_key->notUsed = 0;
335 return p_key;
339 /* Info to attach to frame when first read, recording what to show about sequence */
340 typedef enum
342 SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing
343 } sequence_state;
344 typedef struct
346 gboolean sequenceExpectedCorrect;
347 guint16 sequenceExpected;
348 guint32 previousFrameNum;
349 guint32 nextFrameNum;
351 guint16 firstSN;
352 guint16 lastSN;
354 sequence_state state;
355 } pdcp_sequence_report_in_frame;
357 /* The sequence analysis frame report hash table instance itself */
358 static GHashTable *pdcp_lte_sequence_analysis_report_hash = NULL;
362 /* Add to the tree values associated with sequence analysis for this frame */
363 static void addChannelSequenceInfo(pdcp_sequence_report_in_frame *p,
364 pdcp_lte_info *p_pdcp_lte_info,
365 guint16 sequenceNumber,
366 packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
368 proto_tree *seqnum_tree;
369 proto_item *seqnum_ti;
370 proto_item *ti_expected_sn;
371 proto_item *ti;
373 /* Create subtree */
374 seqnum_ti = proto_tree_add_string_format(tree,
375 hf_pdcp_lte_sequence_analysis,
376 tvb, 0, 0,
377 "", "Sequence Analysis");
378 seqnum_tree = proto_item_add_subtree(seqnum_ti,
379 ett_pdcp_lte_sequence_analysis);
380 PROTO_ITEM_SET_GENERATED(seqnum_ti);
383 /* Previous channel frame */
384 if (p->previousFrameNum != 0) {
385 proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_previous_frame,
386 tvb, 0, 0, p->previousFrameNum);
389 /* Expected sequence number */
390 ti_expected_sn = proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_expected_sn,
391 tvb, 0, 0, p->sequenceExpected);
392 PROTO_ITEM_SET_GENERATED(ti_expected_sn);
394 /* Make sure we have recognised SN length */
395 switch (p_pdcp_lte_info->seqnum_length) {
396 case PDCP_SN_LENGTH_5_BITS:
397 case PDCP_SN_LENGTH_7_BITS:
398 case PDCP_SN_LENGTH_12_BITS:
399 case PDCP_SN_LENGTH_15_BITS:
400 break;
401 default:
402 DISSECTOR_ASSERT_NOT_REACHED();
403 break;
406 switch (p->state) {
407 case SN_OK:
408 PROTO_ITEM_SET_HIDDEN(ti_expected_sn);
409 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
410 tvb, 0, 0, TRUE);
411 PROTO_ITEM_SET_GENERATED(ti);
412 proto_item_append_text(seqnum_ti, " - OK");
414 /* Link to next SN in channel (if known) */
415 if (p->nextFrameNum != 0) {
416 proto_tree_add_uint(seqnum_tree, hf_pdcp_lte_sequence_analysis_next_frame,
417 tvb, 0, 0, p->nextFrameNum);
419 break;
421 case SN_Missing:
422 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
423 tvb, 0, 0, FALSE);
424 PROTO_ITEM_SET_GENERATED(ti);
425 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_skipped,
426 tvb, 0, 0, TRUE);
427 PROTO_ITEM_SET_GENERATED(ti);
428 if (p->lastSN != p->firstSN) {
429 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_sequence_analysis_sn_missing,
430 "PDCP SNs (%u to %u) missing for %s on UE %u (%s-%u)",
431 p->firstSN, p->lastSN,
432 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
433 p_pdcp_lte_info->ueid,
434 val_to_str_const(p_pdcp_lte_info->channelType, logical_channel_vals, "Unknown"),
435 p_pdcp_lte_info->channelId);
436 proto_item_append_text(seqnum_ti, " - SNs missing (%u to %u)",
437 p->firstSN, p->lastSN);
439 else {
440 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_sequence_analysis_sn_missing,
441 "PDCP SN (%u) missing for %s on UE %u (%s-%u)",
442 p->firstSN,
443 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
444 p_pdcp_lte_info->ueid,
445 val_to_str_const(p_pdcp_lte_info->channelType, logical_channel_vals, "Unknown"),
446 p_pdcp_lte_info->channelId);
447 proto_item_append_text(seqnum_ti, " - SN missing (%u)",
448 p->firstSN);
450 break;
452 case SN_Repeated:
453 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_ok,
454 tvb, 0, 0, FALSE);
455 PROTO_ITEM_SET_GENERATED(ti);
456 ti = proto_tree_add_boolean(seqnum_tree, hf_pdcp_lte_sequence_analysis_repeated,
457 tvb, 0, 0, TRUE);
458 PROTO_ITEM_SET_GENERATED(ti);
459 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_sequence_analysis_sn_repeated,
460 "PDCP SN (%u) repeated for %s for UE %u (%s-%u)",
461 p->firstSN,
462 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
463 p_pdcp_lte_info->ueid,
464 val_to_str_const(p_pdcp_lte_info->channelType, logical_channel_vals, "Unknown"),
465 p_pdcp_lte_info->channelId);
466 proto_item_append_text(seqnum_ti, "- SN %u Repeated",
467 p->firstSN);
468 break;
470 default:
471 /* Incorrect sequence number */
472 expert_add_info_format(pinfo, ti_expected_sn, &ei_pdcp_lte_sequence_analysis_wrong_sequence_number,
473 "Wrong Sequence Number for %s on UE %u (%s-%u) - got %u, expected %u",
474 val_to_str_const(p_pdcp_lte_info->direction, direction_vals, "Unknown"),
475 p_pdcp_lte_info->ueid,
476 val_to_str_const(p_pdcp_lte_info->channelType, logical_channel_vals, "Unknown"),
477 p_pdcp_lte_info->channelId,
478 sequenceNumber, p->sequenceExpected);
479 break;
484 /* Update the channel status and set report for this frame */
485 static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
486 pdcp_lte_info *p_pdcp_lte_info,
487 guint16 sequenceNumber,
488 proto_tree *tree)
490 pdcp_channel_hash_key channel_key;
491 pdcp_channel_status *p_channel_status;
492 pdcp_sequence_report_in_frame *p_report_in_frame = NULL;
493 gboolean createdChannel = FALSE;
494 guint16 expectedSequenceNumber = 0;
495 guint16 snLimit = 0;
497 /* If find stat_report_in_frame already, use that and get out */
498 if (pinfo->fd->flags.visited) {
499 p_report_in_frame =
500 (pdcp_sequence_report_in_frame*)g_hash_table_lookup(pdcp_lte_sequence_analysis_report_hash,
501 get_report_hash_key(sequenceNumber,
502 pinfo->fd->num,
503 p_pdcp_lte_info, FALSE));
504 if (p_report_in_frame != NULL) {
505 addChannelSequenceInfo(p_report_in_frame, p_pdcp_lte_info,
506 sequenceNumber,
507 pinfo, tree, tvb);
508 return;
510 else {
511 /* Give up - we must have tried already... */
512 return;
517 /**************************************************/
518 /* Create or find an entry for this channel state */
519 channel_key.ueId = p_pdcp_lte_info->ueid;
520 channel_key.plane = p_pdcp_lte_info->plane;
521 channel_key.channelId = p_pdcp_lte_info->channelId;
522 channel_key.direction = p_pdcp_lte_info->direction;
523 channel_key.notUsed = 0;
525 /* Do the table lookup */
526 p_channel_status = (pdcp_channel_status*)g_hash_table_lookup(pdcp_sequence_analysis_channel_hash,
527 get_channel_hash_key(&channel_key));
529 /* Create table entry if necessary */
530 if (p_channel_status == NULL) {
531 createdChannel = TRUE;
533 /* Allocate a new value and duplicate key contents */
534 p_channel_status = wmem_new0(wmem_file_scope(), pdcp_channel_status);
536 /* Add entry */
537 g_hash_table_insert(pdcp_sequence_analysis_channel_hash,
538 get_channel_hash_key(&channel_key), p_channel_status);
541 /* Create space for frame state_report */
542 p_report_in_frame = wmem_new(wmem_file_scope(), pdcp_sequence_report_in_frame);
543 p_report_in_frame->nextFrameNum = 0;
545 switch (p_pdcp_lte_info->seqnum_length) {
546 case PDCP_SN_LENGTH_5_BITS:
547 snLimit = 32;
548 break;
549 case PDCP_SN_LENGTH_7_BITS:
550 snLimit = 128;
551 break;
552 case PDCP_SN_LENGTH_12_BITS:
553 snLimit = 4096;
554 break;
555 case PDCP_SN_LENGTH_15_BITS:
556 snLimit = 32768;
557 break;
558 default:
559 DISSECTOR_ASSERT_NOT_REACHED();
560 break;
563 /* Work out expected sequence number */
564 if (!createdChannel) {
565 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
567 else {
568 expectedSequenceNumber = sequenceNumber;
571 /* Set report for this frame */
572 /* For PDCP, sequence number is always expectedSequence number */
573 p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
575 /* For wrong sequence number... */
576 if (!p_report_in_frame->sequenceExpectedCorrect) {
578 /* Frames are not missing if we get an earlier sequence number again */
579 if (((snLimit + expectedSequenceNumber - sequenceNumber) % snLimit) > 15) {
580 p_report_in_frame->state = SN_Missing;
581 p_report_in_frame->firstSN = expectedSequenceNumber;
582 p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
584 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
585 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
587 /* Update channel status to remember *this* frame */
588 p_channel_status->previousFrameNum = pinfo->fd->num;
589 p_channel_status->previousSequenceNumber = sequenceNumber;
591 else {
592 /* An SN has been repeated */
593 p_report_in_frame->state = SN_Repeated;
594 p_report_in_frame->firstSN = sequenceNumber;
596 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
597 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
600 else {
601 /* SN was OK */
602 p_report_in_frame->state = SN_OK;
603 p_report_in_frame->sequenceExpected = expectedSequenceNumber;
604 p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
606 /* Update channel status to remember *this* frame */
607 p_channel_status->previousFrameNum = pinfo->fd->num;
608 p_channel_status->previousSequenceNumber = sequenceNumber;
610 if (p_report_in_frame->previousFrameNum != 0) {
611 /* Get report for previous frame */
612 pdcp_sequence_report_in_frame *p_previous_report;
613 p_previous_report = (pdcp_sequence_report_in_frame*)g_hash_table_lookup(pdcp_lte_sequence_analysis_report_hash,
614 get_report_hash_key((sequenceNumber+32767) % 32768,
615 p_report_in_frame->previousFrameNum,
616 p_pdcp_lte_info,
617 FALSE));
618 /* It really shouldn't be NULL... */
619 if (p_previous_report != NULL) {
620 /* Point it forward to this one */
621 p_previous_report->nextFrameNum = pinfo->fd->num;
626 /* Associate with this frame number */
627 g_hash_table_insert(pdcp_lte_sequence_analysis_report_hash,
628 get_report_hash_key(sequenceNumber, pinfo->fd->num,
629 p_pdcp_lte_info, TRUE),
630 p_report_in_frame);
632 /* Add state report for this frame into tree */
633 addChannelSequenceInfo(p_report_in_frame, p_pdcp_lte_info, sequenceNumber,
634 pinfo, tree, tvb);
639 /* Hash table for security state for a UE
640 Maps UEId -> pdcp_security_info_t* */
641 static gint pdcp_lte_ueid_hash_equal(gconstpointer v, gconstpointer v2)
643 return (v == v2);
645 static guint pdcp_lte_ueid_hash_func(gconstpointer v)
647 return GPOINTER_TO_UINT(v);
649 static GHashTable *pdcp_security_hash = NULL;
651 /* Result is (ueid, framenum) -> pdcp_security_info_t* */
652 typedef struct ueid_frame_t {
653 guint32 framenum;
654 guint16 ueid;
655 } ueid_frame_t;
657 /* Convenience function to get a pointer for the hash_func to work with */
658 static gpointer get_ueid_frame_hash_key(guint16 ueid, guint32 frameNumber,
659 gboolean do_persist)
661 static ueid_frame_t key;
662 ueid_frame_t *p_key;
664 /* Only allocate a struct when will be adding entry */
665 if (do_persist) {
666 p_key = wmem_new(wmem_file_scope(), ueid_frame_t);
668 else {
669 memset(&key, 0, sizeof(ueid_frame_t));
670 p_key = &key;
673 /* Fill in details, and return pointer */
674 p_key->framenum = frameNumber;
675 p_key->ueid = ueid;
677 return p_key;
680 static gint pdcp_lte_ueid_frame_hash_equal(gconstpointer v, gconstpointer v2)
682 ueid_frame_t *ueid_frame_1 = (ueid_frame_t *)v;
683 ueid_frame_t *ueid_frame_2 = (ueid_frame_t *)v2;
684 return ((ueid_frame_1->framenum == ueid_frame_2->framenum) && (ueid_frame_1->ueid == ueid_frame_2->ueid));
686 static guint pdcp_lte_ueid_frame_hash_func(gconstpointer v)
688 ueid_frame_t *ueid_frame = (ueid_frame_t *)v;
689 return ueid_frame->framenum + 100*ueid_frame->ueid;
691 static GHashTable *pdcp_security_result_hash = NULL;
696 /* Write the given formatted text to:
697 - the info column
698 - the top-level RLC PDU item */
699 static void write_pdu_label_and_info(proto_item *pdu_ti,
700 packet_info *pinfo, const char *format, ...)
702 #define MAX_INFO_BUFFER 256
703 static char info_buffer[MAX_INFO_BUFFER];
705 va_list ap;
707 va_start(ap, format);
708 g_vsnprintf(info_buffer, MAX_INFO_BUFFER, format, ap);
709 va_end(ap);
711 /* Add to indicated places */
712 col_append_str(pinfo->cinfo, COL_INFO, info_buffer);
713 proto_item_append_text(pdu_ti, "%s", info_buffer);
718 /***************************************************************/
722 /* Show in the tree the config info attached to this frame, as generated fields */
723 static void show_pdcp_config(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree,
724 pdcp_lte_info *p_pdcp_info)
726 proto_item *ti;
727 proto_tree *configuration_tree;
728 proto_item *configuration_ti = proto_tree_add_item(tree,
729 hf_pdcp_lte_configuration,
730 tvb, 0, 0, ENC_ASCII|ENC_NA);
731 configuration_tree = proto_item_add_subtree(configuration_ti, ett_pdcp_configuration);
733 /* Direction */
734 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_direction, tvb, 0, 0,
735 p_pdcp_info->direction);
736 PROTO_ITEM_SET_GENERATED(ti);
738 /* Plane */
739 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_plane, tvb, 0, 0,
740 p_pdcp_info->plane);
741 PROTO_ITEM_SET_GENERATED(ti);
743 /* UEId */
744 if (p_pdcp_info->ueid != 0) {
745 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_ueid, tvb, 0, 0,
746 p_pdcp_info->ueid);
747 PROTO_ITEM_SET_GENERATED(ti);
750 /* Channel type */
751 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_channel_type, tvb, 0, 0,
752 p_pdcp_info->channelType);
753 PROTO_ITEM_SET_GENERATED(ti);
754 if (p_pdcp_info->channelId != 0) {
755 /* Channel type */
756 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_channel_id, tvb, 0, 0,
757 p_pdcp_info->channelId);
758 PROTO_ITEM_SET_GENERATED(ti);
762 /* User-plane-specific fields */
763 if (p_pdcp_info->plane == USER_PLANE) {
765 /* No Header PDU */
766 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_no_header_pdu, tvb, 0, 0,
767 p_pdcp_info->no_header_pdu);
768 PROTO_ITEM_SET_GENERATED(ti);
770 if (!p_pdcp_info->no_header_pdu) {
772 /* Seqnum length */
773 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_seqnum_length, tvb, 0, 0,
774 p_pdcp_info->seqnum_length);
775 PROTO_ITEM_SET_GENERATED(ti);
779 /* ROHC compression */
780 ti = proto_tree_add_boolean(configuration_tree, hf_pdcp_lte_rohc_compression, tvb, 0, 0,
781 p_pdcp_info->rohc.rohc_compression);
782 PROTO_ITEM_SET_GENERATED(ti);
784 /* ROHC-specific settings */
785 if (p_pdcp_info->rohc.rohc_compression) {
787 /* Show ROHC mode */
788 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_mode, tvb, 0, 0,
789 p_pdcp_info->rohc.mode);
790 PROTO_ITEM_SET_GENERATED(ti);
792 /* Show RND */
793 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_rnd, tvb, 0, 0,
794 p_pdcp_info->rohc.rnd);
795 PROTO_ITEM_SET_GENERATED(ti);
797 /* UDP Checksum */
798 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_udp_checksum_present, tvb, 0, 0,
799 p_pdcp_info->rohc.udp_checksum_present);
800 PROTO_ITEM_SET_GENERATED(ti);
802 /* ROHC profile */
803 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_rohc_profile, tvb, 0, 0,
804 p_pdcp_info->rohc.profile);
805 PROTO_ITEM_SET_GENERATED(ti);
807 /* CID Inclusion Info */
808 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_cid_inclusion_info, tvb, 0, 0,
809 p_pdcp_info->rohc.cid_inclusion_info);
810 PROTO_ITEM_SET_GENERATED(ti);
812 /* Large CID */
813 ti = proto_tree_add_uint(configuration_tree, hf_pdcp_lte_large_cid_present, tvb, 0, 0,
814 p_pdcp_info->rohc.large_cid_present);
815 PROTO_ITEM_SET_GENERATED(ti);
818 /* Append summary to configuration root */
819 proto_item_append_text(configuration_ti, "(direction=%s, plane=%s",
820 val_to_str_const(p_pdcp_info->direction, direction_vals, "Unknown"),
821 val_to_str_const(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
823 if (p_pdcp_info->rohc.rohc_compression) {
824 const char *mode = val_to_str_const(p_pdcp_info->rohc.mode, rohc_mode_vals, "Error");
825 proto_item_append_text(configuration_ti, ", mode=%c, profile=%s",
826 mode[0],
827 val_to_str_const(p_pdcp_info->rohc.profile, rohc_profile_vals, "Unknown"));
829 proto_item_append_text(configuration_ti, ")");
830 PROTO_ITEM_SET_GENERATED(configuration_ti);
832 /* Show plane in info column */
833 col_append_fstr(pinfo->cinfo, COL_INFO, " %s: ",
834 val_to_str_const(p_pdcp_info->plane, pdcp_plane_vals, "Unknown"));
839 /* Look for an RRC dissector for signalling data (using channel type and direction) */
840 static dissector_handle_t lookup_rrc_dissector_handle(struct pdcp_lte_info *p_pdcp_info)
842 dissector_handle_t rrc_handle = 0;
844 switch (p_pdcp_info->channelType)
846 case Channel_CCCH:
847 if (p_pdcp_info->direction == DIRECTION_UPLINK) {
848 rrc_handle = find_dissector("lte_rrc.ul_ccch");
850 else {
851 rrc_handle = find_dissector("lte_rrc.dl_ccch");
853 break;
854 case Channel_PCCH:
855 rrc_handle = find_dissector("lte_rrc.pcch");
856 break;
857 case Channel_BCCH:
858 switch (p_pdcp_info->BCCHTransport) {
859 case BCH_TRANSPORT:
860 rrc_handle = find_dissector("lte_rrc.bcch_bch");
861 break;
862 case DLSCH_TRANSPORT:
863 rrc_handle = find_dissector("lte_rrc.bcch_dl_sch");
864 break;
866 break;
867 case Channel_DCCH:
868 if (p_pdcp_info->direction == DIRECTION_UPLINK) {
869 rrc_handle = find_dissector("lte_rrc.ul_dcch");
871 else {
872 rrc_handle = find_dissector("lte_rrc.dl_dcch");
874 break;
877 default:
878 break;
881 return rrc_handle;
885 /* Forwad declarations */
886 static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
888 /* Heuristic dissection */
889 static gboolean global_pdcp_lte_heur = FALSE;
891 /* Heuristic dissector looks for supported framing protocol (see wiki page) */
892 static gboolean dissect_pdcp_lte_heur(tvbuff_t *tvb, packet_info *pinfo,
893 proto_tree *tree, void *data _U_)
895 gint offset = 0;
896 struct pdcp_lte_info *p_pdcp_lte_info;
897 tvbuff_t *pdcp_tvb;
898 guint8 tag = 0;
899 gboolean infoAlreadySet = FALSE;
900 gboolean seqnumLengthTagPresent = FALSE;
902 /* This is a heuristic dissector, which means we get all the UDP
903 * traffic not sent to a known dissector and not claimed by
904 * a heuristic dissector called before us!
907 if (!global_pdcp_lte_heur) {
908 return FALSE;
911 /* Do this again on re-dissection to re-discover offset of actual PDU */
913 /* Needs to be at least as long as:
914 - the signature string
915 - fixed header bytes
916 - tag for data
917 - at least one byte of PDCP PDU payload */
918 if (tvb_length_remaining(tvb, offset) < (gint)(strlen(PDCP_LTE_START_STRING)+3+2)) {
919 return FALSE;
922 /* OK, compare with signature string */
923 if (tvb_strneql(tvb, offset, PDCP_LTE_START_STRING, strlen(PDCP_LTE_START_STRING)) != 0) {
924 return FALSE;
926 offset += (gint)strlen(PDCP_LTE_START_STRING);
929 /* If redissecting, use previous info struct (if available) */
930 p_pdcp_lte_info = (pdcp_lte_info *)p_get_proto_data(pinfo->fd, proto_pdcp_lte, 0);
931 if (p_pdcp_lte_info == NULL) {
932 /* Allocate new info struct for this frame */
933 p_pdcp_lte_info = wmem_new0(wmem_file_scope(), pdcp_lte_info);
934 infoAlreadySet = FALSE;
936 else {
937 infoAlreadySet = TRUE;
941 /* Read fixed fields */
942 p_pdcp_lte_info->no_header_pdu = (gboolean)tvb_get_guint8(tvb, offset++);
943 p_pdcp_lte_info->plane = (enum pdcp_plane)tvb_get_guint8(tvb, offset++);
944 p_pdcp_lte_info->rohc.rohc_compression = (gboolean)tvb_get_guint8(tvb, offset++);
946 /* Read optional fields */
947 while (tag != PDCP_LTE_PAYLOAD_TAG) {
948 /* Process next tag */
949 tag = tvb_get_guint8(tvb, offset++);
950 switch (tag) {
951 case PDCP_LTE_SEQNUM_LENGTH_TAG:
952 p_pdcp_lte_info->seqnum_length = tvb_get_guint8(tvb, offset);
953 offset++;
954 seqnumLengthTagPresent = TRUE;
955 break;
956 case PDCP_LTE_DIRECTION_TAG:
957 p_pdcp_lte_info->direction = tvb_get_guint8(tvb, offset);
958 offset++;
959 break;
960 case PDCP_LTE_LOG_CHAN_TYPE_TAG:
961 p_pdcp_lte_info->channelType = (LogicalChannelType)tvb_get_guint8(tvb, offset);
962 offset++;
963 break;
964 case PDCP_LTE_BCCH_TRANSPORT_TYPE_TAG:
965 p_pdcp_lte_info->BCCHTransport = (BCCHTransportType)tvb_get_guint8(tvb, offset);
966 offset++;
967 break;
968 case PDCP_LTE_ROHC_IP_VERSION_TAG:
969 p_pdcp_lte_info->rohc.rohc_ip_version = tvb_get_ntohs(tvb, offset);
970 offset += 2;
971 break;
972 case PDCP_LTE_ROHC_CID_INC_INFO_TAG:
973 p_pdcp_lte_info->rohc.cid_inclusion_info = tvb_get_guint8(tvb, offset);
974 offset++;
975 break;
976 case PDCP_LTE_ROHC_LARGE_CID_PRES_TAG:
977 p_pdcp_lte_info->rohc.large_cid_present = tvb_get_guint8(tvb, offset);
978 offset++;
979 break;
980 case PDCP_LTE_ROHC_MODE_TAG:
981 p_pdcp_lte_info->rohc.mode = (enum rohc_mode)tvb_get_guint8(tvb, offset);
982 offset++;
983 break;
984 case PDCP_LTE_ROHC_RND_TAG:
985 p_pdcp_lte_info->rohc.rnd = tvb_get_guint8(tvb, offset);
986 offset++;
987 break;
988 case PDCP_LTE_ROHC_UDP_CHECKSUM_PRES_TAG:
989 p_pdcp_lte_info->rohc.udp_checksum_present = tvb_get_guint8(tvb, offset);
990 offset++;
991 break;
992 case PDCP_LTE_ROHC_PROFILE_TAG:
993 p_pdcp_lte_info->rohc.profile = tvb_get_ntohs(tvb, offset);
994 offset += 2;
995 break;
996 case PDCP_LTE_CHANNEL_ID_TAG:
997 p_pdcp_lte_info->channelId = tvb_get_ntohs(tvb, offset);
998 offset += 2;
999 break;
1000 case PDCP_LTE_UEID_TAG:
1001 p_pdcp_lte_info->ueid = tvb_get_ntohs(tvb, offset);
1002 offset += 2;
1003 break;
1005 case PDCP_LTE_PAYLOAD_TAG:
1006 /* Have reached data, so get out of loop */
1007 continue;
1009 default:
1010 /* It must be a recognised tag */
1011 return FALSE;
1015 if ((p_pdcp_lte_info->plane == USER_PLANE) && (seqnumLengthTagPresent == FALSE)) {
1016 /* Conditional field is not present */
1017 return FALSE;
1020 if (!infoAlreadySet) {
1021 /* Store info in packet */
1022 p_add_proto_data(pinfo->fd, proto_pdcp_lte, 0, p_pdcp_lte_info);
1025 /**************************************/
1026 /* OK, now dissect as PDCP LTE */
1028 /* Create tvb that starts at actual PDCP PDU */
1029 pdcp_tvb = tvb_new_subset_remaining(tvb, offset);
1030 dissect_pdcp_lte(pdcp_tvb, pinfo, tree);
1031 return TRUE;
1034 /* Called from control protocol to configure security algorithms for the given UE */
1035 void set_pdcp_lte_security_algorithms(guint16 ueid, pdcp_security_info_t *security_info)
1037 /* Copy security struct */
1038 pdcp_security_info_t *p_security = wmem_new(wmem_file_scope(), pdcp_security_info_t);
1039 *p_security = *security_info;
1041 /* And add into security table */
1042 g_hash_table_insert(pdcp_security_hash, GUINT_TO_POINTER((guint)ueid), p_security);
1046 /******************************/
1047 /* Main dissection function. */
1048 static void dissect_pdcp_lte(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1050 const char *mode;
1051 proto_tree *pdcp_tree = NULL;
1052 proto_item *root_ti = NULL;
1053 gint offset = 0;
1054 gint rohc_offset;
1055 struct pdcp_lte_info *p_pdcp_info;
1056 rohc_info *p_rohc_info;
1057 tvbuff_t *rohc_tvb = NULL;
1058 pdcp_security_info_t *current_security = NULL; /* current security for this UE */
1059 pdcp_security_info_t *pdu_security; /* security in place for this PDU */
1062 /* Set protocol name. */
1063 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PDCP-LTE");
1065 /* Look for attached packet info! */
1066 p_pdcp_info = (struct pdcp_lte_info *)p_get_proto_data(pinfo->fd, proto_pdcp_lte, 0);
1067 /* Can't dissect anything without it... */
1068 if (p_pdcp_info == NULL) {
1069 return;
1072 /* Don't want to overwrite the RLC Info column if configured not to */
1073 if ((global_pdcp_lte_layer_to_show == ShowRLCLayer) &&
1074 (p_get_proto_data(pinfo->fd, proto_rlc_lte, 0) != NULL)) {
1076 col_set_writable(pinfo->cinfo, FALSE);
1078 else {
1079 /* TODO: won't help with multiple PDCP-or-traffic PDUs / frame... */
1080 col_clear(pinfo->cinfo, COL_INFO);
1081 col_set_writable(pinfo->cinfo, TRUE);
1084 /* Create pdcp tree. */
1085 if (tree) {
1086 root_ti = proto_tree_add_item(tree, proto_pdcp_lte, tvb, offset, -1, ENC_NA);
1087 pdcp_tree = proto_item_add_subtree(root_ti, ett_pdcp);
1090 /* Set mode string */
1091 mode = val_to_str_const(p_pdcp_info->rohc.mode, rohc_mode_vals, "Error");
1093 /*****************************************************/
1094 /* Show configuration (attached packet) info in tree */
1095 if (pdcp_tree) {
1096 show_pdcp_config(pinfo, tvb, pdcp_tree, p_pdcp_info);
1099 /* Show ROHC mode */
1100 if (p_pdcp_info->rohc.rohc_compression) {
1101 col_append_fstr(pinfo->cinfo, COL_INFO, " (mode=%c)", mode[0]);
1104 /***************************************/
1105 /* UE security algorithms */
1106 if (!pinfo->fd->flags.visited) {
1107 /* Look up current state by UEID */
1108 current_security = (pdcp_security_info_t*)g_hash_table_lookup(pdcp_security_hash,
1109 GUINT_TO_POINTER((guint)p_pdcp_info->ueid));
1110 if (current_security != NULL) {
1111 /* Store any result for this frame in the result table */
1112 pdcp_security_info_t *security_to_store = wmem_new(wmem_file_scope(), pdcp_security_info_t);
1113 *security_to_store = *current_security;
1114 g_hash_table_insert(pdcp_security_result_hash,
1115 get_ueid_frame_hash_key(p_pdcp_info->ueid, pinfo->fd->num, TRUE),
1116 security_to_store);
1119 /* Show security settings for this PDU */
1120 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));
1121 if (pdu_security != NULL) {
1122 proto_tree *security_tree;
1123 proto_item *security_ti, *ti;
1125 /* Create subtree */
1126 security_ti = proto_tree_add_string_format(pdcp_tree,
1127 hf_pdcp_lte_security,
1128 tvb, 0, 0,
1129 "", "UE Security");
1130 security_tree = proto_item_add_subtree(security_ti,
1131 ett_pdcp_security);
1132 PROTO_ITEM_SET_GENERATED(security_ti);
1134 /* Setup frame */
1135 ti = proto_tree_add_uint(security_tree, hf_pdcp_lte_security_setup_frame,
1136 tvb, 0, 0, pdu_security->configuration_frame);
1137 PROTO_ITEM_SET_GENERATED(ti);
1139 /* Ciphering */
1140 ti = proto_tree_add_uint(security_tree, hf_pdcp_lte_security_ciphering_algorithm,
1141 tvb, 0, 0, pdu_security->ciphering);
1142 PROTO_ITEM_SET_GENERATED(ti);
1144 /* Integrity */
1145 ti = proto_tree_add_uint(security_tree, hf_pdcp_lte_security_integrity_algorithm,
1146 tvb, 0, 0, pdu_security->integrity);
1147 PROTO_ITEM_SET_GENERATED(ti);
1149 proto_item_append_text(security_ti, " (ciphering=%s, integrity=%s)",
1150 val_to_str_const(pdu_security->ciphering, ciphering_algorithm_vals, "Unknown"),
1151 val_to_str_const(pdu_security->integrity, integrity_algorithm_vals, "Unknown"));
1155 /***********************************/
1156 /* Handle PDCP header (if present) */
1157 if (!p_pdcp_info->no_header_pdu) {
1159 /* TODO: shouldn't need to initialise this one!! */
1160 guint16 seqnum = 0;
1161 gboolean seqnum_set = FALSE;
1163 guint8 first_byte = tvb_get_guint8(tvb, offset);
1165 /*****************************/
1166 /* Signalling plane messages */
1167 if (p_pdcp_info->plane == SIGNALING_PLANE) {
1168 guint32 mac;
1169 guint32 data_length;
1171 /* Verify 3 reserved bits are 0 */
1172 guint8 reserved = (first_byte & 0xe0) >> 5;
1173 proto_item *ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_control_plane_reserved,
1174 tvb, offset, 1, ENC_BIG_ENDIAN);
1175 if (reserved != 0) {
1176 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_reserved_bits_not_zero,
1177 "PDCP signalling header reserved bits not zero");
1180 /* 5-bit sequence number */
1181 seqnum = first_byte & 0x1f;
1182 seqnum_set = TRUE;
1183 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_5, tvb, offset, 1, ENC_BIG_ENDIAN);
1184 write_pdu_label_and_info(root_ti, pinfo, " sn=%-2u ", seqnum);
1185 offset++;
1187 if (tvb_length_remaining(tvb, offset) == 0) {
1188 /* Only PDCP header was captured, stop dissection here */
1189 return;
1192 /* RRC data is all but last 4 bytes.
1193 Call lte-rrc dissector (according to direction and channel type) */
1194 if ((global_pdcp_dissect_signalling_plane_as_rrc) &&
1195 ((pdu_security == NULL) || (pdu_security->ciphering == 0) || !pdu_security->seen_next_ul_pdu)){
1196 /* Get appropriate dissector handle */
1197 dissector_handle_t rrc_handle = lookup_rrc_dissector_handle(p_pdcp_info);
1199 if (rrc_handle != 0) {
1200 /* Call RRC dissector if have one */
1201 tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset,
1202 tvb_length_remaining(tvb, offset) - 4,
1203 tvb_length_remaining(tvb, offset) - 4);
1204 gboolean was_writable = col_get_writable(pinfo->cinfo);
1206 /* We always want to see this in the info column */
1207 col_set_writable(pinfo->cinfo, TRUE);
1209 call_dissector_only(rrc_handle, payload_tvb, pinfo, pdcp_tree, NULL);
1211 /* Restore to whatever it was */
1212 col_set_writable(pinfo->cinfo, was_writable);
1214 else {
1215 /* Just show data */
1216 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
1217 tvb_length_remaining(tvb, offset) - 4, ENC_NA);
1220 if (!pinfo->fd->flags.visited &&
1221 (current_security != NULL) && !current_security->seen_next_ul_pdu &&
1222 p_pdcp_info->direction == DIRECTION_UPLINK)
1224 /* i.e. we have already seen SecurityModeResponse! */
1225 current_security->seen_next_ul_pdu = TRUE;
1229 else {
1230 /* Just show as unparsed data */
1231 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_signalling_data, tvb, offset,
1232 tvb_length_remaining(tvb, offset) - 4, ENC_NA);
1235 data_length = tvb_length_remaining(tvb, offset) - 4;
1236 offset += data_length;
1238 /* Last 4 bytes are MAC */
1239 mac = tvb_get_ntohl(tvb, offset);
1240 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_mac, tvb, offset, 4, ENC_BIG_ENDIAN);
1241 offset += 4;
1243 col_append_fstr(pinfo->cinfo, COL_INFO, " MAC=0x%08x (%u bytes data)",
1244 mac, data_length);
1246 else if (p_pdcp_info->plane == USER_PLANE) {
1248 /**********************************/
1249 /* User-plane messages */
1250 gboolean pdu_type = (first_byte & 0x80) >> 7;
1252 /* Data/Control flag */
1253 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_data_control, tvb, offset, 1, ENC_BIG_ENDIAN);
1255 if (pdu_type == 1) {
1256 /*****************************/
1257 /* Use-plane Data */
1259 /* Number of sequence number bits depends upon config */
1260 switch (p_pdcp_info->seqnum_length) {
1261 case PDCP_SN_LENGTH_7_BITS:
1262 seqnum = first_byte & 0x7f;
1263 seqnum_set = TRUE;
1264 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_7, tvb, offset, 1, ENC_BIG_ENDIAN);
1265 offset++;
1266 break;
1267 case PDCP_SN_LENGTH_12_BITS:
1269 proto_item *ti;
1270 guint8 reserved_value;
1272 /* 3 reserved bits */
1273 ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_reserved3, tvb, offset, 1, ENC_BIG_ENDIAN);
1274 reserved_value = (first_byte & 0x70) >> 4;
1276 /* Complain if not 0 */
1277 if (reserved_value != 0) {
1278 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_reserved_bits_not_zero,
1279 "Reserved bits have value 0x%x - should be 0x0",
1280 reserved_value);
1283 /* 12-bit sequence number */
1284 seqnum = tvb_get_ntohs(tvb, offset) & 0x0fff;
1285 seqnum_set = TRUE;
1286 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_12, tvb, offset, 2, ENC_BIG_ENDIAN);
1287 offset += 2;
1289 break;
1290 case PDCP_SN_LENGTH_15_BITS:
1291 seqnum = tvb_get_ntohs(tvb, offset) & 0x7fff;
1292 seqnum_set = TRUE;
1293 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_seq_num_15, tvb, offset, 2, ENC_BIG_ENDIAN);
1294 offset += 2;
1295 break;
1296 default:
1297 /* Not a recognised data format!!!!! */
1298 return;
1301 write_pdu_label_and_info(root_ti, pinfo, " (SN=%u)", seqnum);
1303 else {
1304 /*******************************/
1305 /* User-plane Control messages */
1306 guint8 control_pdu_type = (first_byte & 0x70) >> 4;
1307 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_control_pdu_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1309 switch (control_pdu_type) {
1310 case 0: /* PDCP status report */
1312 guint8 bits;
1313 guint16 fms;
1314 guint16 modulo;
1315 guint not_received = 0;
1316 guint sn, i, j, l;
1317 guint32 len, bit_offset;
1318 proto_tree *bitmap_tree;
1319 proto_item *bitmap_ti = NULL;
1320 gchar *buff = NULL;
1321 #define BUFF_SIZE 49
1323 if (p_pdcp_info->seqnum_length == PDCP_SN_LENGTH_12_BITS) {
1324 /* First-Missing-Sequence SN */
1325 fms = tvb_get_ntohs(tvb, offset) & 0x0fff;
1326 sn = (fms + 1) % 4096;
1327 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_fms, tvb,
1328 offset, 2, ENC_BIG_ENDIAN);
1329 offset += 2;
1330 modulo = 4096;
1331 } else {
1332 proto_item *ti;
1333 guint8 reserved_value;
1335 /* 5 reserved bits */
1336 ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_reserved4, tvb, offset, 2, ENC_BIG_ENDIAN);
1337 reserved_value = (tvb_get_ntohs(tvb, offset) & 0x0f80)>>7;
1338 offset++;
1340 /* Complain if not 0 */
1341 if (reserved_value != 0) {
1342 expert_add_info_format(pinfo, ti, &ei_pdcp_lte_reserved_bits_not_zero,
1343 "Reserved bits have value 0x%x - should be 0x0",
1344 reserved_value);
1347 /* First-Missing-Sequence SN */
1348 fms = tvb_get_ntohs(tvb, offset) & 0x7fff;
1349 sn = (fms + 1) % 32768;
1350 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_fms2, tvb,
1351 offset, 2, ENC_BIG_ENDIAN);
1352 offset += 2;
1353 modulo = 32768;
1356 /* Bitmap tree */
1357 if (tvb_length_remaining(tvb, offset) > 0) {
1358 bitmap_ti = proto_tree_add_item(pdcp_tree, hf_pdcp_lte_bitmap, tvb,
1359 offset, -1, ENC_NA);
1360 bitmap_tree = proto_item_add_subtree(bitmap_ti, ett_pdcp_report_bitmap);
1362 buff = (gchar *)wmem_alloc(wmem_packet_scope(), BUFF_SIZE);
1363 len = tvb_length_remaining(tvb, offset);
1364 bit_offset = offset<<3;
1365 /* For each byte... */
1366 for (i=0; i<len; i++) {
1367 bits = tvb_get_bits8(tvb, bit_offset, 8);
1368 for (l=0, j=0; l<8; l++) {
1369 if ((bits << l) & 0x80) {
1370 j += g_snprintf(&buff[j], BUFF_SIZE-j, "%5u,", (unsigned)(sn+(8*i)+l)%modulo);
1371 } else {
1372 j += g_snprintf(&buff[j], BUFF_SIZE-j, " ,");
1373 not_received++;
1376 proto_tree_add_text(bitmap_tree, tvb, bit_offset/8, 1, "%s", buff);
1377 bit_offset += 8;
1381 if (bitmap_ti != NULL) {
1382 proto_item_append_text(bitmap_ti, " (%u SNs not received)", not_received);
1384 write_pdu_label_and_info(root_ti, pinfo, " Status Report (fms=%u) not-received=%u",
1385 fms, not_received);
1387 return;
1389 case 1: /* ROHC Feedback */
1390 offset++;
1391 break; /* Drop-through to dissect feedback */
1393 default: /* Reserved */
1394 return;
1398 else {
1399 /* Invalid plane setting...! */
1400 write_pdu_label_and_info(root_ti, pinfo, " - INVALID PLANE (%u)",
1401 p_pdcp_info->plane);
1402 return;
1405 /* Do sequence analysis if configured to. */
1406 if (seqnum_set) {
1407 gboolean do_analysis = FALSE;
1409 switch (global_pdcp_check_sequence_numbers) {
1410 case FALSE:
1411 break;
1412 case SEQUENCE_ANALYSIS_RLC_ONLY:
1413 if ((p_get_proto_data(pinfo->fd, proto_rlc_lte, 0) != NULL) &&
1414 !p_pdcp_info->is_retx) {
1415 do_analysis = TRUE;
1417 break;
1418 case SEQUENCE_ANALYSIS_PDCP_ONLY:
1419 if (p_get_proto_data(pinfo->fd, proto_rlc_lte, 0) == NULL) {
1420 do_analysis = TRUE;
1422 break;
1425 if (do_analysis) {
1426 checkChannelSequenceInfo(pinfo, tvb, p_pdcp_info,
1427 (guint16)seqnum, pdcp_tree);
1431 else {
1432 /* Show that it's a no-header PDU */
1433 write_pdu_label_and_info(root_ti, pinfo, " No-Header ");
1436 /* If not compressed with ROHC, show as user-plane data */
1437 if (!p_pdcp_info->rohc.rohc_compression) {
1438 gint payload_length = tvb_length_remaining(tvb, offset);
1439 if (payload_length > 0) {
1440 if (p_pdcp_info->plane == USER_PLANE) {
1442 /* Not attempting to decode payload if ciphering is enabled
1443 (and NULL ciphering is not being used) */
1444 if (global_pdcp_dissect_user_plane_as_ip &&
1445 ((pdu_security == NULL) || (pdu_security->ciphering == 0)))
1447 tvbuff_t *payload_tvb = tvb_new_subset_remaining(tvb, offset);
1449 /* Don't update info column for ROHC unless configured to */
1450 if (global_pdcp_lte_layer_to_show != ShowTrafficLayer) {
1451 col_set_writable(pinfo->cinfo, FALSE);
1454 switch (tvb_get_guint8(tvb, offset) & 0xf0) {
1455 case 0x40:
1456 call_dissector_only(ip_handle, payload_tvb, pinfo, pdcp_tree, NULL);
1457 break;
1458 case 0x60:
1459 call_dissector_only(ipv6_handle, payload_tvb, pinfo, pdcp_tree, NULL);
1460 break;
1461 default:
1462 call_dissector_only(data_handle, payload_tvb, pinfo, pdcp_tree, NULL);
1463 break;
1466 /* Freeze the columns again because we don't want other layers writing to info */
1467 if (global_pdcp_lte_layer_to_show == ShowTrafficLayer) {
1468 col_set_writable(pinfo->cinfo, FALSE);
1472 else {
1473 proto_tree_add_item(pdcp_tree, hf_pdcp_lte_user_plane_data, tvb, offset, -1, ENC_NA);
1477 write_pdu_label_and_info(root_ti, pinfo, "(%u bytes data)",
1478 payload_length);
1481 /* (there will be no signalling data left at this point) */
1483 /* Let RLC write to columns again */
1484 col_set_writable(pinfo->cinfo, global_pdcp_lte_layer_to_show == ShowRLCLayer);
1486 /* DROPPING OUT HERE IF NOT DOING ROHC! */
1487 return;
1491 /***************************/
1492 /* ROHC packets */
1493 /***************************/
1496 /* Only attempt ROHC if configured to */
1497 if (!global_pdcp_dissect_rohc) {
1498 col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "|ROHC(%s)",
1499 val_to_str_const(p_pdcp_info->rohc.profile, rohc_profile_vals, "Unknown"));
1500 return;
1503 rohc_offset = offset;
1504 rohc_tvb = tvb_new_subset_remaining(tvb, rohc_offset);
1506 /* RoHC settings */
1507 p_rohc_info = wmem_new(wmem_packet_scope(), rohc_info);
1509 /* Copy struct. TODO: could just pass pdcp_info->rohc ?? */
1510 *p_rohc_info = p_pdcp_info->rohc;
1512 /* Only enable writing to column if configured to show ROHC */
1513 if (global_pdcp_lte_layer_to_show != ShowTrafficLayer) {
1514 col_set_writable(pinfo->cinfo, FALSE);
1516 else {
1517 col_clear(pinfo->cinfo, COL_INFO);
1520 /* Call the ROHC dissector */
1521 call_dissector_with_data(rohc_handle, rohc_tvb, pinfo, tree, p_rohc_info);
1523 /* Let RLC write to columns again */
1524 col_set_writable(pinfo->cinfo, global_pdcp_lte_layer_to_show == ShowRLCLayer);
1527 /* Initializes the hash tables each time a new
1528 * file is loaded or re-loaded in wireshark */
1529 static void pdcp_lte_init_protocol(void)
1531 /* Destroy any existing hashes. */
1532 if (pdcp_sequence_analysis_channel_hash) {
1533 g_hash_table_destroy(pdcp_sequence_analysis_channel_hash);
1535 if (pdcp_lte_sequence_analysis_report_hash) {
1536 g_hash_table_destroy(pdcp_lte_sequence_analysis_report_hash);
1538 if (pdcp_security_hash) {
1539 g_hash_table_destroy(pdcp_security_hash);
1541 if (pdcp_security_result_hash) {
1542 g_hash_table_destroy(pdcp_security_result_hash);
1545 /* Now create them over */
1546 pdcp_sequence_analysis_channel_hash = g_hash_table_new(pdcp_channel_hash_func, pdcp_channel_equal);
1547 pdcp_lte_sequence_analysis_report_hash = g_hash_table_new(pdcp_result_hash_func, pdcp_result_hash_equal);
1548 pdcp_security_hash = g_hash_table_new(pdcp_lte_ueid_hash_func, pdcp_lte_ueid_hash_equal);
1549 pdcp_security_result_hash = g_hash_table_new(pdcp_lte_ueid_frame_hash_func, pdcp_lte_ueid_frame_hash_equal);
1554 void proto_register_pdcp(void)
1556 static hf_register_info hf[] =
1558 { &hf_pdcp_lte_configuration,
1559 { "Configuration",
1560 "pdcp-lte.configuration", FT_STRING, BASE_NONE, NULL, 0x0,
1561 "Configuration info passed into dissector", HFILL
1565 { &hf_pdcp_lte_rohc_compression,
1566 { "ROHC Compression",
1567 "pdcp-lte.rohc.compression", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1568 NULL, HFILL
1571 { &hf_pdcp_lte_rohc_mode,
1572 { "ROHC Mode",
1573 "pdcp-lte.rohc.mode", FT_UINT8, BASE_DEC, VALS(rohc_mode_vals), 0x0,
1574 NULL, HFILL
1577 { &hf_pdcp_lte_rohc_rnd,
1578 { "RND", /* TODO: true/false vals? */
1579 "pdcp-lte.rohc.rnd", FT_UINT8, BASE_DEC, NULL, 0x0,
1580 "RND of outer ip header", HFILL
1583 { &hf_pdcp_lte_rohc_udp_checksum_present,
1584 { "UDP Checksum", /* TODO: true/false vals? */
1585 "pdcp-lte.rohc.checksum-present", FT_UINT8, BASE_DEC, NULL, 0x0,
1586 "UDP Checksum present", HFILL
1589 { &hf_pdcp_lte_direction,
1590 { "Direction",
1591 "pdcp-lte.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
1592 "Direction of message", HFILL
1595 { &hf_pdcp_lte_ueid,
1596 { "UE",
1597 "pdcp-lte.ueid", FT_UINT16, BASE_DEC, 0, 0x0,
1598 "UE Identifier", HFILL
1601 { &hf_pdcp_lte_channel_type,
1602 { "Channel type",
1603 "pdcp-lte.channel-type", FT_UINT8, BASE_DEC, VALS(logical_channel_vals), 0x0,
1604 NULL, HFILL
1607 { &hf_pdcp_lte_channel_id,
1608 { "Channel Id",
1609 "pdcp-lte.channel-id", FT_UINT8, BASE_DEC, 0, 0x0,
1610 NULL, HFILL
1613 { &hf_pdcp_lte_rohc_profile,
1614 { "ROHC profile",
1615 "pdcp-lte.rohc.profile", FT_UINT8, BASE_DEC, VALS(rohc_profile_vals), 0x0,
1616 "ROHC Mode", HFILL
1619 { &hf_pdcp_lte_no_header_pdu,
1620 { "No Header PDU",
1621 "pdcp-lte.no-header_pdu", FT_UINT8, BASE_DEC, NULL, 0x0,
1622 NULL, HFILL
1625 { &hf_pdcp_lte_plane,
1626 { "Plane",
1627 "pdcp-lte.plane", FT_UINT8, BASE_DEC, VALS(pdcp_plane_vals), 0x0,
1628 NULL, HFILL
1631 { &hf_pdcp_lte_seqnum_length,
1632 { "Seqnum length",
1633 "pdcp-lte.seqnum_length", FT_UINT8, BASE_DEC, NULL, 0x0,
1634 "Sequence Number Length", HFILL
1639 { &hf_pdcp_lte_cid_inclusion_info,
1640 { "CID Inclusion Info",
1641 "pdcp-lte.cid-inclusion-info", FT_UINT8, BASE_DEC, NULL, 0x0,
1642 NULL, HFILL
1645 { &hf_pdcp_lte_large_cid_present,
1646 { "Large CID Present",
1647 "pdcp-lte.large-cid-present", FT_UINT8, BASE_DEC, NULL, 0x0,
1648 NULL, HFILL
1652 { &hf_pdcp_lte_control_plane_reserved,
1653 { "Reserved",
1654 "pdcp-lte.reserved", FT_UINT8, BASE_DEC, NULL, 0xe0,
1655 NULL, HFILL
1658 { &hf_pdcp_lte_seq_num_5,
1659 { "Seq Num",
1660 "pdcp-lte.seq-num", FT_UINT8, BASE_DEC, NULL, 0x1f,
1661 "PDCP Seq num", HFILL
1664 { &hf_pdcp_lte_seq_num_7,
1665 { "Seq Num",
1666 "pdcp-lte.seq-num", FT_UINT8, BASE_DEC, NULL, 0x7f,
1667 "PDCP Seq num", HFILL
1670 { &hf_pdcp_lte_reserved3,
1671 { "Reserved",
1672 "pdcp-lte.reserved3", FT_UINT8, BASE_HEX, NULL, 0x70,
1673 "3 reserved bits", HFILL
1676 { &hf_pdcp_lte_seq_num_12,
1677 { "Seq Num",
1678 "pdcp-lte.seq-num", FT_UINT16, BASE_DEC, NULL, 0x0fff,
1679 "PDCP Seq num", HFILL
1682 { &hf_pdcp_lte_seq_num_15,
1683 { "Seq Num",
1684 "pdcp-lte.seq-num", FT_UINT16, BASE_DEC, NULL, 0x7fff,
1685 "PDCP Seq num", HFILL
1688 { &hf_pdcp_lte_signalling_data,
1689 { "Signalling Data",
1690 "pdcp-lte.signalling-data", FT_BYTES, BASE_NONE, NULL, 0x0,
1691 NULL, HFILL
1694 { &hf_pdcp_lte_mac,
1695 { "MAC",
1696 "pdcp-lte.mac", FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
1697 NULL, HFILL
1700 { &hf_pdcp_lte_data_control,
1701 { "PDU Type",
1702 "pdcp-lte.pdu-type", FT_UINT8, BASE_HEX, VALS(pdu_type_vals), 0x80,
1703 NULL, HFILL
1706 { &hf_pdcp_lte_user_plane_data,
1707 { "User-Plane Data",
1708 "pdcp-lte.user-data", FT_BYTES, BASE_NONE, NULL, 0x0,
1709 NULL, HFILL
1712 { &hf_pdcp_lte_control_pdu_type,
1713 { "Control PDU Type",
1714 "pdcp-lte.control-pdu-type", FT_UINT8, BASE_HEX, VALS(control_pdu_type_vals), 0x70,
1715 NULL, HFILL
1718 { &hf_pdcp_lte_fms,
1719 { "First Missing Sequence Number",
1720 "pdcp-lte.fms", FT_UINT16, BASE_DEC, NULL, 0x0fff,
1721 "First Missing PDCP Sequence Number", HFILL
1724 { &hf_pdcp_lte_reserved4,
1725 { "Reserved",
1726 "pdcp-lte.reserved4", FT_UINT16, BASE_HEX, NULL, 0x0f80,
1727 "5 reserved bits", HFILL
1730 { &hf_pdcp_lte_fms2,
1731 { "First Missing Sequence Number",
1732 "pdcp-lte.fms", FT_UINT16, BASE_DEC, NULL, 0x07fff,
1733 "First Missing PDCP Sequence Number", HFILL
1736 { &hf_pdcp_lte_bitmap,
1737 { "Bitmap",
1738 "pdcp-lte.bitmap", FT_NONE, BASE_NONE, NULL, 0x0,
1739 "Status report bitmap (0=error, 1=OK)", HFILL
1744 { &hf_pdcp_lte_sequence_analysis,
1745 { "Sequence Analysis",
1746 "pdcp-lte.sequence-analysis", FT_STRING, BASE_NONE, 0, 0x0,
1747 NULL, HFILL
1750 { &hf_pdcp_lte_sequence_analysis_ok,
1751 { "OK",
1752 "pdcp-lte.sequence-analysis.ok", FT_BOOLEAN, BASE_NONE, 0, 0x0,
1753 NULL, HFILL
1756 { &hf_pdcp_lte_sequence_analysis_previous_frame,
1757 { "Previous frame for channel",
1758 "pdcp-lte.sequence-analysis.previous-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
1759 NULL, HFILL
1762 { &hf_pdcp_lte_sequence_analysis_next_frame,
1763 { "Next frame for channel",
1764 "pdcp-lte.sequence-analysis.next-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
1765 NULL, HFILL
1768 { &hf_pdcp_lte_sequence_analysis_expected_sn,
1769 { "Expected SN",
1770 "pdcp-lte.sequence-analysis.expected-sn", FT_UINT16, BASE_DEC, 0, 0x0,
1771 NULL, HFILL
1774 { &hf_pdcp_lte_sequence_analysis_skipped,
1775 { "Skipped frames",
1776 "pdcp-lte.sequence-analysis.skipped-frames", FT_BOOLEAN, BASE_NONE, 0, 0x0,
1777 NULL, HFILL
1780 { &hf_pdcp_lte_sequence_analysis_repeated,
1781 { "Repeated frame",
1782 "pdcp-lte.sequence-analysis.repeated-frame", FT_BOOLEAN, BASE_NONE, 0, 0x0,
1783 NULL, HFILL
1787 { &hf_pdcp_lte_security,
1788 { "Security Config",
1789 "pdcp-lte.security-cofig", FT_STRING, BASE_NONE, 0, 0x0,
1790 NULL, HFILL
1793 { &hf_pdcp_lte_security_setup_frame,
1794 { "Configuration frame",
1795 "pdcp-lte.security-config.setup-frame", FT_FRAMENUM, BASE_NONE, 0, 0x0,
1796 NULL, HFILL
1799 { &hf_pdcp_lte_security_integrity_algorithm,
1800 { "Integrity Algorithm",
1801 "pdcp-lte.security-config.integrity", FT_UINT16, BASE_DEC, VALS(integrity_algorithm_vals), 0x0,
1802 NULL, HFILL
1805 { &hf_pdcp_lte_security_ciphering_algorithm,
1806 { "Ciphering Algorithm",
1807 "pdcp-lte.security-config.ciphering", FT_UINT16, BASE_DEC, VALS(ciphering_algorithm_vals), 0x0,
1808 NULL, HFILL
1813 static gint *ett[] =
1815 &ett_pdcp,
1816 &ett_pdcp_configuration,
1817 &ett_pdcp_packet,
1818 &ett_pdcp_lte_sequence_analysis,
1819 &ett_pdcp_report_bitmap,
1820 &ett_pdcp_security
1823 static ei_register_info ei[] = {
1824 { &ei_pdcp_lte_sequence_analysis_sn_missing, { "pdcp-lte.sequence-analysis.sn_missing", PI_SEQUENCE, PI_WARN, "PDCP SN missing", EXPFILL }},
1825 { &ei_pdcp_lte_sequence_analysis_sn_repeated, { "pdcp-lte.sequence-analysis.sn_repeated", PI_SEQUENCE, PI_WARN, "PDCP SN repeated", EXPFILL }},
1826 { &ei_pdcp_lte_sequence_analysis_wrong_sequence_number, { "pdcp-lte.sequence-analysis.wrong_sequence_number", PI_SEQUENCE, PI_WARN, "Wrong Sequence Number", EXPFILL }},
1827 { &ei_pdcp_lte_reserved_bits_not_zero, { "pdcp_lte.reserved_bits_not_zero", PI_MALFORMED, PI_ERROR, "Reserved bits not zero", EXPFILL }},
1830 static const enum_val_t sequence_analysis_vals[] = {
1831 {"no-analysis", "No-Analysis", FALSE},
1832 {"rlc-only", "Only-RLC-frames", SEQUENCE_ANALYSIS_RLC_ONLY},
1833 {"pdcp-only", "Only-PDCP-frames", SEQUENCE_ANALYSIS_PDCP_ONLY},
1834 {NULL, NULL, -1}
1837 static const enum_val_t show_info_col_vals[] = {
1838 {"show-rlc", "RLC Info", ShowRLCLayer},
1839 {"show-pdcp", "PDCP Info", ShowPDCPLayer},
1840 {"show-traffic", "Traffic Info", ShowTrafficLayer},
1841 {NULL, NULL, -1}
1844 module_t *pdcp_lte_module;
1845 expert_module_t* expert_pdcp_lte;
1847 /* Register protocol. */
1848 proto_pdcp_lte = proto_register_protocol("PDCP-LTE", "PDCP-LTE", "pdcp-lte");
1849 proto_register_field_array(proto_pdcp_lte, hf, array_length(hf));
1850 proto_register_subtree_array(ett, array_length(ett));
1851 expert_pdcp_lte = expert_register_protocol(proto_pdcp_lte);
1852 expert_register_field_array(expert_pdcp_lte, ei, array_length(ei));
1854 /* Allow other dissectors to find this one by name. */
1855 register_dissector("pdcp-lte", dissect_pdcp_lte, proto_pdcp_lte);
1857 pdcp_lte_module = prefs_register_protocol(proto_pdcp_lte, NULL);
1859 /* Obsolete preferences */
1860 prefs_register_obsolete_preference(pdcp_lte_module, "show_feedback_option_tag_length");
1862 /* Dissect uncompressed user-plane data as IP */
1863 prefs_register_bool_preference(pdcp_lte_module, "show_user_plane_as_ip",
1864 "Show uncompressed User-Plane data as IP",
1865 "Show uncompressed User-Plane data as IP",
1866 &global_pdcp_dissect_user_plane_as_ip);
1868 /* Dissect unciphered signalling data as RRC */
1869 prefs_register_bool_preference(pdcp_lte_module, "show_signalling_plane_as_rrc",
1870 "Show unciphered Signalling-Plane data as RRC",
1871 "Show unciphered Signalling-Plane data as RRC",
1872 &global_pdcp_dissect_signalling_plane_as_rrc);
1874 /* Check for missing sequence numbers */
1875 prefs_register_enum_preference(pdcp_lte_module, "check_sequence_numbers",
1876 "Do sequence number analysis",
1877 "Do sequence number analysis",
1878 &global_pdcp_check_sequence_numbers, sequence_analysis_vals, FALSE);
1880 /* Attempt to dissect ROHC messages */
1881 prefs_register_bool_preference(pdcp_lte_module, "dissect_rohc",
1882 "Attempt to decode ROHC data",
1883 "Attempt to decode ROHC data",
1884 &global_pdcp_dissect_rohc);
1886 prefs_register_bool_preference(pdcp_lte_module, "heuristic_pdcp_lte_over_udp",
1887 "Try Heuristic LTE-PDCP over UDP framing",
1888 "When enabled, use heuristic dissector to find PDCP-LTE frames sent with "
1889 "UDP framing",
1890 &global_pdcp_lte_heur);
1892 prefs_register_enum_preference(pdcp_lte_module, "layer_to_show",
1893 "Which layer info to show in Info column",
1894 "Can show RLC, PDCP or Traffic layer info in Info column",
1895 &global_pdcp_lte_layer_to_show, show_info_col_vals, FALSE);
1897 register_init_routine(&pdcp_lte_init_protocol);
1900 void proto_reg_handoff_pdcp_lte(void)
1902 /* Add as a heuristic UDP dissector */
1903 heur_dissector_add("udp", dissect_pdcp_lte_heur, proto_pdcp_lte);
1905 ip_handle = find_dissector("ip");
1906 ipv6_handle = find_dissector("ipv6");
1907 rohc_handle = find_dissector("rohc");
1908 data_handle = find_dissector("data");