Don't attach sequence analysis results to control/data PDUs when not appropriate...
[obnox/wireshark/wip.git] / epan / dissectors / packet-rlc-lte.c
index 5fa42ad78ab5caf5fc8c74b626ea87f6cdfe4434..d7ceb111c2a75cb9866539c38b14e6ef5a5528ec 100644 (file)
@@ -61,14 +61,16 @@ static gint global_rlc_lte_um_sequence_analysis = FALSE;
 /* By default don't call PDCP/RRC dissectors for SDU data */
 static gboolean global_rlc_lte_call_pdcp_for_srb = FALSE;
 
-enum pdcp_for_drb { PDCP_drb_off, PDCP_drb_SN_7, PDCP_drb_SN_12};
+enum pdcp_for_drb { PDCP_drb_off, PDCP_drb_SN_7, PDCP_drb_SN_12, PDCP_drb_SN_signalled};
 static enum_val_t pdcp_drb_col_vals[] = {
     {"pdcp-drb-off",   "Off",       PDCP_drb_off},
     {"pdcp-drb-sn-7",  "7-bit SN",  PDCP_drb_SN_7},
     {"pdcp-drb-sn-12", "12-bit SN", PDCP_drb_SN_12},
+    {"pdcp-drb-sn-signalling", "Use signalled value", PDCP_drb_SN_signalled},
     {NULL, NULL, -1}
 };
 static gint global_rlc_lte_call_pdcp_for_drb = (gint)PDCP_drb_off;
+static gint signalled_pdcp_sn_bits = 12;
 
 static gboolean global_rlc_lte_call_rrc = FALSE;
 
@@ -138,6 +140,7 @@ static int hf_rlc_lte_am_ack_sn = -1;
 static int hf_rlc_lte_am_e1 = -1;
 static int hf_rlc_lte_am_e2 = -1;
 static int hf_rlc_lte_am_nack_sn = -1;
+static int hf_rlc_lte_am_nacks = -1;
 static int hf_rlc_lte_am_so_start = -1;
 static int hf_rlc_lte_am_so_end = -1;
 
@@ -159,6 +162,9 @@ static int hf_rlc_lte_sequence_analysis_skipped = -1;
 static int hf_rlc_lte_sequence_analysis_repeated_nack = -1;
 static int hf_rlc_lte_sequence_analysis_repeated_nack_original_frame = -1;
 
+static int hf_rlc_lte_sequence_analysis_ack_out_of_range = -1;
+static int hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame = -1;
+
 /* Subtrees. */
 static int ett_rlc_lte = -1;
 static int ett_rlc_lte_context = -1;
@@ -194,11 +200,12 @@ static const value_string rlc_mode_vals[] =
 
 static const value_string rlc_channel_type_vals[] =
 {
-    { CHANNEL_TYPE_CCCH,     "CCCH"},
-    { CHANNEL_TYPE_BCCH,     "BCCH"},
-    { CHANNEL_TYPE_PCCH,     "PCCH"},
-    { CHANNEL_TYPE_SRB,      "SRB"},
-    { CHANNEL_TYPE_DRB,      "DRB"},
+    { CHANNEL_TYPE_CCCH,         "CCCH"},
+    { CHANNEL_TYPE_BCCH_BCH,     "BCCH_BCH"},
+    { CHANNEL_TYPE_PCCH,         "PCCH"},
+    { CHANNEL_TYPE_SRB,          "SRB"},
+    { CHANNEL_TYPE_DRB,          "DRB"},
+    { CHANNEL_TYPE_BCCH_DL_SCH,  "BCCH_DL_SCH"},
     { 0, NULL }
 };
 
@@ -340,7 +347,7 @@ typedef struct
     guint16   lastSN;
 
     /* AM/UM */
-    enum { SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing} state;
+    enum { SN_OK, SN_Repeated, SN_MAC_Retx, SN_Retx, SN_Missing, ACK_Out_of_Window} state;
 } state_sequence_analysis_report_in_frame;
 
 
@@ -530,6 +537,11 @@ static void show_PDU_in_tree(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb
                 case PDCP_drb_SN_12:
                     p_pdcp_lte_info->seqnum_length = 12;
                     break;
+                case PDCP_drb_SN_signalled:
+                    /* Use whatever was signalled (e.g. in RRC) */
+                    p_pdcp_lte_info->seqnum_length = signalled_pdcp_sn_bits;
+                    break;
+
                 default:
                     DISSECTOR_ASSERT(FALSE);
                     break;
@@ -597,6 +609,7 @@ static guint rlc_frame_hash_func(gconstpointer v)
 
 /* Add to the tree values associated with sequence analysis for this frame */
 static void addChannelSequenceInfo(state_sequence_analysis_report_in_frame *p,
+                                   gboolean isControlFrame,
                                    rlc_lte_info *p_rlc_lte_info,
                                    guint16   sequenceNumber,
                                    gboolean  newSegmentStarted,
@@ -625,6 +638,10 @@ static void addChannelSequenceInfo(state_sequence_analysis_report_in_frame *p,
 
             switch (p->state) {
                 case SN_OK:
+                    if (isControlFrame) {
+                        return;
+                    }
+
                     ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
                                                 tvb, 0, 0, TRUE);
                     PROTO_ITEM_SET_GENERATED(ti);
@@ -632,6 +649,10 @@ static void addChannelSequenceInfo(state_sequence_analysis_report_in_frame *p,
                     break;
 
                 case SN_MAC_Retx:
+                    if (isControlFrame) {
+                        return;
+                    }
+
                     ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
                                                 tvb, 0, 0, FALSE);
                     PROTO_ITEM_SET_GENERATED(ti);
@@ -639,12 +660,17 @@ static void addChannelSequenceInfo(state_sequence_analysis_report_in_frame *p,
                                                 tvb, 0, 0, TRUE);
                     PROTO_ITEM_SET_GENERATED(ti);
                     expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
-                                           "AM Frame retransmitted for %s on UE %u - due to MAC retx!",
+                                           "AM Frame retransmitted for %s on UE %u (SN=%u) - due to MAC retx!",
                                            val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
-                                           p_rlc_lte_info->ueid);
+                                           p_rlc_lte_info->ueid,
+                                           p->firstSN);
                     break;
 
                 case SN_Retx:
+                    if (isControlFrame) {
+                        return;
+                    }
+
                     ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
                                                 tvb, 0, 0, FALSE);
                     PROTO_ITEM_SET_GENERATED(ti);
@@ -652,13 +678,18 @@ static void addChannelSequenceInfo(state_sequence_analysis_report_in_frame *p,
                                                 tvb, 0, 0, TRUE);
                     PROTO_ITEM_SET_GENERATED(ti);
                     expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
-                                           "AM Frame retransmitted for %s on UE %u - most likely in response to NACK",
+                                           "AM Frame retransmitted for %s on UE %u (SN=%u) - most likely in response to NACK",
                                            val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
-                                           p_rlc_lte_info->ueid);
+                                           p_rlc_lte_info->ueid,
+                                           p->firstSN);
                     proto_item_append_text(seqnum_ti, " - SN %u retransmitted", p->firstSN);
                     break;
 
                 case SN_Repeated:
+                    if (isControlFrame) {
+                        return;
+                    }
+
                     ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
                                                 tvb, 0, 0, FALSE);
                     PROTO_ITEM_SET_GENERATED(ti);
@@ -675,6 +706,10 @@ static void addChannelSequenceInfo(state_sequence_analysis_report_in_frame *p,
                     break;
 
                 case SN_Missing:
+                    if (isControlFrame) {
+                        return;
+                    }
+
                     ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
                                                 tvb, 0, 0, FALSE);
                     PROTO_ITEM_SET_GENERATED(ti);
@@ -702,6 +737,36 @@ static void addChannelSequenceInfo(state_sequence_analysis_report_in_frame *p,
                         tap_info->missingSNs = 1;
                     }
                     break;
+
+                case ACK_Out_of_Window:
+                    if (!isControlFrame) {
+                        return;
+                    }
+
+
+                    /* Not OK */
+                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
+                                                tvb, 0, 0, FALSE);
+                    /* Out of range */
+                    PROTO_ITEM_SET_GENERATED(ti);
+                    ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range,
+                                                tvb, 0, 0, TRUE);
+                    PROTO_ITEM_SET_GENERATED(ti);
+
+                    /* Link back to last seen SN in other direction */
+                    ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
+                                             tvb, 0, 0, p->previousFrameNum);
+                    PROTO_ITEM_SET_GENERATED(ti);
+
+                    /* Expert error */
+                    expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_ERROR,
+                                           "AM ACK for SN %u - but last received SN in other direction is %u for UE %u",
+                                           p->firstSN, p->sequenceExpected,
+                                           p_rlc_lte_info->ueid);
+                    proto_item_append_text(seqnum_ti, "- ACK SN %u Outside Rx Window - last received SN is %u",
+                                           p->firstSN, p->sequenceExpected);
+
+                    break;
             }
             break;
 
@@ -791,6 +856,13 @@ static void addChannelSequenceInfo(state_sequence_analysis_report_in_frame *p,
                                                p_rlc_lte_info->ueid);
                         break;
 
+                    case SN_OK:
+                        ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
+                                                    tvb, 0, 0, TRUE);
+                        PROTO_ITEM_SET_GENERATED(ti);
+                        proto_item_append_text(seqnum_ti, " - OK");
+                        break;
+
                     default:
                         /* Incorrect sequence number */
                         expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_WARN,
@@ -843,6 +915,7 @@ static void addChannelSequenceInfo(state_sequence_analysis_report_in_frame *p,
 /* Update the channel status and set report for this frame */
 static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
                                      rlc_lte_info *p_rlc_lte_info,
+                                     gboolean isControlFrame,
                                      guint16 sequenceNumber,
                                      gboolean first_includes_start, gboolean last_includes_end,
                                      gboolean is_resegmented _U_,
@@ -862,7 +935,7 @@ static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
         p_report_in_frame = (state_sequence_analysis_report_in_frame*)g_hash_table_lookup(rlc_lte_frame_sequence_analysis_report_hash,
                                                                                           &pinfo->fd->num);
         if (p_report_in_frame != NULL) {
-            addChannelSequenceInfo(p_report_in_frame, p_rlc_lte_info,
+            addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info,
                                    sequenceNumber, first_includes_start,
                                    tap_info, pinfo, tree, tvb);
             return;
@@ -888,12 +961,9 @@ static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
     if (p_channel_status == NULL) {
         createdChannel = TRUE;
 
-        /* Allocate a new key and value */
-        p_channel_key = se_alloc(sizeof(rlc_channel_hash_key));
+        /* Allocate a new value and duplicate key contents */
         p_channel_status = se_alloc0(sizeof(rlc_channel_sequence_analysis_status));
-
-        /* Copy key contents */
-        memcpy(p_channel_key, &channel_key, sizeof(rlc_channel_hash_key));
+        p_channel_key = se_memdup(&channel_key, sizeof(rlc_channel_hash_key));
 
         /* Set mode */
         p_channel_status->rlcMode = p_rlc_lte_info->rlcMode;
@@ -919,6 +989,10 @@ static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
             if (!createdChannel) {
                 expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % snLimit;
             }
+            else {
+                /* Whatever we got is fine.. */
+                expectedSequenceNumber = sequenceNumber;
+            }
 
             /* Set report for this frame */
             /* For UM, sequence number is always expectedSequence number */
@@ -932,24 +1006,20 @@ static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
                 /* Don't get confused by MAC (HARQ) retx */
                 if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
                     p_report_in_frame->state = SN_MAC_Retx;
+                    p_report_in_frame->firstSN = sequenceNumber;
                 }
 
                 /* Frames are not missing if we get an earlier sequence number again */
-                else if (((snLimit + expectedSequenceNumber - sequenceNumber) % snLimit) > 40) {
-                    if (!createdChannel) {
-                        p_report_in_frame->state = SN_Missing;
-                        tap_info->missingSNs = (snLimit + sequenceNumber - expectedSequenceNumber) % snLimit;
-                        p_report_in_frame->firstSN = expectedSequenceNumber;
-                        p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
+                /* TODO: taking time into account would give better idea of whether missing or repeated... */
+                else if (((snLimit + sequenceNumber - expectedSequenceNumber) % snLimit) < 10) {
+                    p_report_in_frame->state = SN_Missing;
+                    tap_info->missingSNs = (snLimit + sequenceNumber - expectedSequenceNumber) % snLimit;
+                    p_report_in_frame->firstSN = expectedSequenceNumber;
+                    p_report_in_frame->lastSN = (snLimit + sequenceNumber - 1) % snLimit;
 
-                        p_report_in_frame->sequenceExpected = expectedSequenceNumber;
-                        p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
-                        p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
-                    }
-                    else {
-                        /* The log may not contain the very first SNs for this channel, so be forgiving... */
-                        p_report_in_frame->state = SN_OK;
-                    }
+                    p_report_in_frame->sequenceExpected = expectedSequenceNumber;
+                    p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
+                    p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
 
                     /* Update channel status to remember *this* frame */
                     p_channel_status->previousFrameNum = pinfo->fd->num;
@@ -997,11 +1067,11 @@ static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
             if (is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
                 /* Just report that this is a MAC Retx */
                 p_report_in_frame->state = SN_MAC_Retx;
+                p_report_in_frame->firstSN = sequenceNumber;
 
                 /* No channel state to update */
             }
 
-
             /* Expected? */
             else if (sequenceNumber == expectedSequenceNumber) {
 
@@ -1080,7 +1150,7 @@ static void checkChannelSequenceInfo(packet_info *pinfo, tvbuff_t *tvb,
     g_hash_table_insert(rlc_lte_frame_sequence_analysis_report_hash, &pinfo->fd->num, p_report_in_frame);
 
     /* Add state report for this frame into tree */
-    addChannelSequenceInfo(p_report_in_frame, p_rlc_lte_info, sequenceNumber,
+    addChannelSequenceInfo(p_report_in_frame, isControlFrame, p_rlc_lte_info, sequenceNumber,
                            first_includes_start, tap_info, pinfo, tree, tvb);
 }
 
@@ -1237,6 +1307,74 @@ static void checkChannelRepeatedNACKInfo(packet_info *pinfo,
     p_channel_status->frameNum = pinfo->fd->num;
 }
 
+/* Check that the ACK is consistent with data the expected sequence number
+   in the other direction */
+static void checkChannelACKWindow(guint16 ack_sn,
+                                  packet_info *pinfo,
+                                  rlc_lte_info *p_rlc_lte_info,
+                                  rlc_lte_tap_info *tap_info,
+                                  proto_tree *tree,
+                                  tvbuff_t *tvb)
+{
+    rlc_channel_hash_key   channel_key;
+    rlc_channel_sequence_analysis_status     *p_channel_status;
+    state_sequence_analysis_report_in_frame  *p_report_in_frame = NULL;
+
+    /* If find stat_report_in_frame already, use that and get out */
+    if (pinfo->fd->flags.visited) {
+        p_report_in_frame = (state_sequence_analysis_report_in_frame*)g_hash_table_lookup(rlc_lte_frame_sequence_analysis_report_hash,
+                                                                                          &pinfo->fd->num);
+        if (p_report_in_frame != NULL) {
+            /* Add any info to tree */
+            addChannelSequenceInfo(p_report_in_frame, TRUE, p_rlc_lte_info,
+                                   0, FALSE,
+                                   tap_info, pinfo, tree, tvb);
+            return;
+        }
+        else {
+            /* Give up - we must have tried already... */
+            return;
+        }
+    }
+
+    /*******************************************************************/
+    /* Find an entry for this channel state (in the opposite direction */
+    channel_key.ueId = p_rlc_lte_info->ueid;
+    channel_key.channelType = p_rlc_lte_info->channelType;
+    channel_key.channelId = p_rlc_lte_info->channelId;
+    channel_key.direction =
+        (p_rlc_lte_info->direction == DIRECTION_UPLINK) ? DIRECTION_DOWNLINK : DIRECTION_UPLINK;
+
+    /* Do the table lookup */
+    p_channel_status = (rlc_channel_sequence_analysis_status*)g_hash_table_lookup(rlc_lte_sequence_analysis_channel_hash, &channel_key);
+
+    /* Create table entry if necessary */
+    if (p_channel_status == NULL) {
+        return;
+    }
+
+    /* Is it in the rx window? This test will catch if its ahead, but we don't
+       really know what the back of the tx window is... */
+    if (((1024 + p_channel_status->previousSequenceNumber+1 - ack_sn) % 1024) > 512) {
+
+        /* Set result */
+        p_report_in_frame = se_alloc(sizeof(state_sequence_analysis_report_in_frame));
+        p_report_in_frame->state = ACK_Out_of_Window;
+        p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
+        p_report_in_frame->sequenceExpected = p_channel_status->previousSequenceNumber;
+        p_report_in_frame->firstSN = ack_sn;
+
+        /* Associate with this frame number */
+        g_hash_table_insert(rlc_lte_frame_sequence_analysis_report_hash,
+                            &pinfo->fd->num, p_report_in_frame);
+
+        /* Add state report for this frame into tree */
+        addChannelSequenceInfo(p_report_in_frame, TRUE, p_rlc_lte_info, 0,
+                               FALSE, tap_info, pinfo, tree, tvb);
+    }
+}
+
+
 
 
 /***************************************************/
@@ -1252,7 +1390,7 @@ static void dissect_rlc_lte_tm(tvbuff_t *tvb, packet_info *pinfo,
 
     /* Create hidden TM root */
     tm_ti = proto_tree_add_string_format(tree, hf_rlc_lte_tm,
-                                         tvb, offset, 0, "", "UM");
+                                         tvb, offset, 0, "", "TM");
     PROTO_ITEM_SET_HIDDEN(tm_ti);
 
     /* Remaining bytes are all data */
@@ -1276,10 +1414,12 @@ static void dissect_rlc_lte_tm(tvbuff_t *tvb, packet_info *pinfo,
                 }
                 break;
 
-            case CHANNEL_TYPE_BCCH:
-                /* TODO: Problem is don't know which transport channel... */
-                return;
-
+            case CHANNEL_TYPE_BCCH_BCH:
+                protocol_handle = find_dissector("lte_rrc.bcch_bch");
+                break;
+            case CHANNEL_TYPE_BCCH_DL_SCH:
+                protocol_handle = find_dissector("lte_rrc.bcch_dl_sch");
+                break;
             case CHANNEL_TYPE_PCCH:
                 protocol_handle = find_dissector("lte-rrc.pcch");
                 break;
@@ -1402,7 +1542,7 @@ static void dissect_rlc_lte_um(tvbuff_t *tvb, packet_info *pinfo,
     tap_info->sequenceNumber = (guint16)sn;
 
     /* Show SN in info column */
-    write_pdu_label_and_info(top_ti, NULL, pinfo, "  SN=%-4u", (guint16)sn);
+    write_pdu_label_and_info(top_ti, um_header_ti, pinfo, "  SN=%-4u", (guint16)sn);
 
     proto_item_set_len(um_header_ti, offset-start_offset);
 
@@ -1441,6 +1581,7 @@ static void dissect_rlc_lte_um(tvbuff_t *tvb, packet_info *pinfo,
          (p_get_proto_data(pinfo->fd, proto_mac_lte) == NULL))) {
 
         checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info,
+                                FALSE,
                                 (guint16)sn, first_includes_start, last_includes_end,
                                 FALSE, /* UM doesn't re-segment */
                                 tap_info, um_header_tree);
@@ -1601,6 +1742,8 @@ static void dissect_rlc_lte_am_status_pdu(tvbuff_t *tvb,
     } while (e1 || e2);
 
     if (nack_count > 0) {
+        proto_item *count_ti = proto_tree_add_uint(tree, hf_rlc_lte_am_nacks, tvb, 0, 1, nack_count);
+        PROTO_ITEM_SET_GENERATED(count_ti);
         proto_item_append_text(status_ti, "  (%u NACKs)", nack_count);
         tap_info->noOfNACKs = nack_count;
     }
@@ -1617,7 +1760,7 @@ static void dissect_rlc_lte_am_status_pdu(tvbuff_t *tvb,
     /* Set selected length of control tree */
     proto_item_set_len(status_ti, offset);
 
-    /* Repeated NACK analysis */
+    /* Repeated NACK analysis & check ACK-SN is in range */
     if (((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_MAC_ONLY) &&
          (p_get_proto_data(pinfo->fd, proto_mac_lte) != NULL)) ||
         ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
@@ -1625,6 +1768,7 @@ static void dissect_rlc_lte_am_status_pdu(tvbuff_t *tvb,
 
         if (!is_mac_lte_frame_retx(pinfo, p_rlc_lte_info->direction)) {
             checkChannelRepeatedNACKInfo(pinfo, p_rlc_lte_info, tap_info, tree, tvb);
+            checkChannelACKWindow((guint16)ack_sn, pinfo, p_rlc_lte_info, tap_info, tree, tvb);
         }
      }
 }
@@ -1730,7 +1874,7 @@ static void dissect_rlc_lte_am(tvbuff_t *tvb, packet_info *pinfo,
         /* SO */
         segmentOffset = tvb_get_ntohs(tvb, offset) & 0x7fff;
         proto_tree_add_item(am_header_tree, hf_rlc_lte_am_segment_so, tvb, offset, 2, FALSE);
-        write_pdu_label_and_info(top_ti, NULL, pinfo, " SO=%u ", segmentOffset);
+        write_pdu_label_and_info(top_ti, am_header_ti, pinfo, " SO=%u ", segmentOffset);
         offset += 2;
     }
 
@@ -1770,7 +1914,7 @@ static void dissect_rlc_lte_am(tvbuff_t *tvb, packet_info *pinfo,
         ((global_rlc_lte_am_sequence_analysis == SEQUENCE_ANALYSIS_RLC_ONLY) &&
          (p_get_proto_data(pinfo->fd, proto_mac_lte) == NULL))) {
 
-        checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info, (guint16)sn,
+        checkChannelSequenceInfo(pinfo, tvb, p_rlc_lte_info, FALSE, (guint16)sn,
                                  first_includes_start, last_includes_end,
                                  is_resegmented, tap_info, tree);
     }
@@ -2131,6 +2275,13 @@ rlc_lte_init_protocol(void)
 }
 
 
+/* Configure number of PDCP SN bits to use for DRB channels.
+   TODO: currently assume all UEs/Channels will use the same length... */
+void set_rlc_lte_drb_pdcp_seqnum_length(guint16 ueid _U_, guint8 drbid _U_, guint8 userplane_seqnum_length)
+{
+    signalled_pdcp_sn_bits = userplane_seqnum_length;
+}
+
 
 
 void proto_register_rlc_lte(void)
@@ -2371,6 +2522,12 @@ void proto_register_rlc_lte(void)
               NULL, HFILL
             }
         },
+        { &hf_rlc_lte_am_nacks,
+            { "Number of NACKs",
+              "rlc-lte.am.nacks", FT_UINT16, BASE_DEC, 0, 0x0,
+              "Number of NACKs in this status PDU", HFILL
+            }
+        },
         { &hf_rlc_lte_am_nack_sn,
             { "NACK Sequence Number",
               "rlc-lte.am.nack-sn", FT_UINT16, BASE_DEC, 0, 0x0,
@@ -2464,6 +2621,19 @@ void proto_register_rlc_lte(void)
             }
         },
 
+        { &hf_rlc_lte_sequence_analysis_ack_out_of_range,
+            { "Out of range ACK",
+              "rlc-lte.sequence-analysis.ack-out-of-range", FT_BOOLEAN, BASE_NONE, 0, 0x0,
+              NULL, HFILL
+            }
+        },
+        { &hf_rlc_lte_sequence_analysis_ack_out_of_range_opposite_frame,
+            { "Frame with most recent SN",
+              "rlc-lte.sequence-analysis.ack-out-of-range.last-sn-frame",  FT_FRAMENUM, BASE_NONE, 0, 0x0,
+              NULL, HFILL
+            }
+        },
+
         { &hf_rlc_lte_header_only,
             { "RLC PDU Header only",
               "rlc-lte.header-only", FT_UINT8, BASE_DEC, VALS(header_only_vals), 0x0,