+
+ /* Work out expected sequence number */
+ 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 */
+ p_report_in_frame->sequenceExpectedCorrect = (sequenceNumber == expectedSequenceNumber);
+
+ /* For wrong sequence number... */
+ if (!p_report_in_frame->sequenceExpectedCorrect) {
+
+ p_report_in_frame->sequenceExpectedCorrect = FALSE;
+
+ /* 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 */
+ /* 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;
+
+ /* Update channel status to remember *this* frame */
+ p_channel_status->previousFrameNum = pinfo->fd->num;
+ p_channel_status->previousSequenceNumber = sequenceNumber;
+ p_channel_status->previousSegmentIncomplete = !last_includes_end;
+ }
+ else {
+ /* An SN has been repeated */
+ p_report_in_frame->state = SN_Repeated;
+ p_report_in_frame->firstSN = sequenceNumber;
+
+ p_report_in_frame->sequenceExpected = expectedSequenceNumber;
+ p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
+ }
+ }
+ else {
+ /* SN was 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;
+ p_channel_status->previousSequenceNumber = sequenceNumber;
+ p_channel_status->previousSegmentIncomplete = !last_includes_end;
+ }
+
+ break;
+
+ case RLC_AM_MODE:
+
+ /* Work out expected sequence number */
+ if (!createdChannel) {
+ expectedSequenceNumber = (p_channel_status->previousSequenceNumber + 1) % 1024;
+ }
+
+ /* For AM, may be:
+ - expected Sequence number OR
+ - previous frame repeated
+ - old SN being sent (in response to NACK)
+ - new SN, but with frames missed out
+ Assume window whose front is at expectedSequenceNumber */
+
+ /* First of all, check to see whether frame is judged to be MAC Retx */
+ 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) {
+
+ /* Set report for this frame */
+ p_report_in_frame->sequenceExpectedCorrect = TRUE;
+ p_report_in_frame->sequenceExpected = expectedSequenceNumber;
+ p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
+ p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
+ p_report_in_frame->state = SN_OK;
+
+ /* Update channel status */
+ p_channel_status->previousSequenceNumber = sequenceNumber;
+ p_channel_status->previousFrameNum = pinfo->fd->num;
+ p_channel_status->previousSegmentIncomplete = !last_includes_end;
+ }
+
+ /* Previous subframe repeated? */
+ else if (((sequenceNumber+1) % 1024) == expectedSequenceNumber) {
+ p_report_in_frame->state = SN_Repeated;
+
+ /* Set report for this frame */
+ p_report_in_frame->sequenceExpectedCorrect = FALSE;
+ p_report_in_frame->sequenceExpected = expectedSequenceNumber;
+ p_report_in_frame->firstSN = sequenceNumber;
+ p_report_in_frame->previousFrameNum = p_channel_status->previousFrameNum;
+ p_report_in_frame->previousSegmentIncomplete = p_channel_status->previousSegmentIncomplete;
+
+
+ /* Really should be nothing to update... */
+ p_channel_status->previousSequenceNumber = sequenceNumber;
+ p_channel_status->previousFrameNum = pinfo->fd->num;
+ p_channel_status->previousSegmentIncomplete = !last_includes_end;
+ }
+
+ else {
+ /* Need to work out if new (with skips, or likely a retx (due to NACK)) */
+ int delta = (1024 + expectedSequenceNumber - sequenceNumber) % 1024;
+
+ /* Rx window is 512, so check to see if this is a retx */
+ if (delta < 512) {
+ /* Probably a retx due to receiving NACK */
+ p_report_in_frame->state = SN_Retx;
+
+ p_report_in_frame->firstSN = sequenceNumber;
+ /* Don't update anything in channel state */
+ }
+
+ else {
+ if (!createdChannel) {
+ /* Ahead of expected SN. Assume frames have been missed */
+ p_report_in_frame->state = SN_Missing;
+
+ p_report_in_frame->firstSN = expectedSequenceNumber;
+ p_report_in_frame->lastSN = (1024 + sequenceNumber-1) % 1024;
+ }
+ else {
+ /* The log may not contain the very first SNs for this channel, so be forgiving... */
+ p_report_in_frame->state = SN_OK;
+ }
+
+ /* Update channel state - forget about missed SNs */
+ p_report_in_frame->sequenceExpected = expectedSequenceNumber;
+ p_channel_status->previousSequenceNumber = sequenceNumber;
+ p_channel_status->previousFrameNum = pinfo->fd->num;
+ p_channel_status->previousSegmentIncomplete = !last_includes_end;
+ }
+ }
+ break;
+
+ default:
+ /* Shouldn't get here! */
+ return;
+ }
+
+ /* 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, isControlFrame, p_rlc_lte_info, sequenceNumber,
+ first_includes_start, tap_info, pinfo, tree, tvb);
+}
+
+
+/* Add to the tree values associated with sequence analysis for this frame */
+static void addChannelRepeatedNACKInfo(rlc_channel_repeated_nack_report_in_frame *p,
+ rlc_lte_info *p_rlc_lte_info,
+ packet_info *pinfo, proto_tree *tree,
+ tvbuff_t *tvb)
+{
+ proto_tree *seqnum_tree;
+ proto_item *seqnum_ti;
+ proto_item *ti;
+ gint n;
+
+ /* Create subtree */
+ seqnum_ti = proto_tree_add_string_format(tree,
+ hf_rlc_lte_sequence_analysis,
+ tvb, 0, 0,
+ "", "Sequence Analysis");
+ seqnum_tree = proto_item_add_subtree(seqnum_ti,
+ ett_rlc_lte_sequence_analysis);
+ PROTO_ITEM_SET_GENERATED(seqnum_ti);
+
+ /* OK = FALSE */
+ ti = proto_tree_add_boolean(seqnum_tree, hf_rlc_lte_sequence_analysis_ok,
+ tvb, 0, 0, FALSE);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ /* Add each repeated NACK as item & expert info */
+ for (n=0; n < p->noOfNACKsRepeated; n++) {
+
+ ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack,
+ tvb, 0, 0, p->repeatedNACKs[n]);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_ERROR,
+ "Same SN (%u) NACKd for %s on UE %u in successive Status PDUs",
+ p->repeatedNACKs[n],
+ val_to_str_const(p_rlc_lte_info->direction, direction_vals, "Unknown"),
+ p_rlc_lte_info->ueid);
+ }
+
+ /* Link back to previous status report */
+ ti = proto_tree_add_uint(seqnum_tree, hf_rlc_lte_sequence_analysis_repeated_nack_original_frame,
+ tvb, 0, 0, p->previousFrameNum);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ /* Append count to sequence analysis root */
+ proto_item_append_text(seqnum_ti, " - %u SNs repeated from previous Status PDU",
+ p->noOfNACKsRepeated);
+}
+
+
+/* Update the channel repeated NACK status and set report for this frame */
+static void checkChannelRepeatedNACKInfo(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_hash_key *p_channel_key;
+ rlc_channel_repeated_nack_status *p_channel_status;
+ rlc_channel_repeated_nack_report_in_frame *p_report_in_frame = NULL;
+
+ guint16 noOfNACKsRepeated = 0;
+ guint16 repeatedNACKs[MAX_NACKs];
+ gint n, i, j;
+
+ /* If find state_report_in_frame already, use that and get out */
+ if (pinfo->fd->flags.visited) {
+ p_report_in_frame = (rlc_channel_repeated_nack_report_in_frame*)g_hash_table_lookup(rlc_lte_frame_repeated_nack_report_hash,
+ &pinfo->fd->num);
+ if (p_report_in_frame != NULL) {
+ addChannelRepeatedNACKInfo(p_report_in_frame, p_rlc_lte_info,
+ pinfo, tree, tvb);
+ return;
+ }
+ else {
+ /* Give up - we must have tried already... */
+ return;