GPRS LLC: Add non-standard method of sequence number recovery

In some situations (like MS reboot without prior DETACH or SGSN reboot
without prior MS detach), the LLC sequence numbers for UI mode could
be different on both sides.

The LLC spec unfortunately doesn't permit us to send something like a
FRMR in this case, but instructs us to silently discard the frame.  At
that time the remote LLC entity will re-transmit the frame with the same
seqeunce number over and over again, which we will drop again and again.

The mthod used now will keep track of the last received UI sequence
number.  If that number is retransmitted for three times in a row, then
we accept this sequence number and recover from that point on.
diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h
index e3fc82e..4be7b1f 100644
--- a/openbsc/include/openbsc/gprs_llc.h
+++ b/openbsc/include/openbsc/gprs_llc.h
@@ -126,6 +126,10 @@
 	uint16_t vu_send;
 	uint16_t vu_recv;
 
+	/* non-standard LLC state */
+	uint16_t vu_recv_last;
+	uint16_t vu_recv_duplicates;
+
 	/* Overflow Counter for ABM */
 	uint32_t oc_i_send;
 	uint32_t oc_i_recv;
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index 6244d18..a4bff65 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -547,7 +547,23 @@
 				"TLLI=%08x dropping UI, N(U=%d) not in window V(URV(UR:%d).\n",
 				lle->llme ? lle->llme->tlli : -1,
 				gph->seq_tx, lle->vu_recv);
-			return -EIO;
+
+			/* HACK: non-standard recovery handling.  If remote LLE
+			 * is re-transmitting the same sequence number for
+			 * threee times, don't discard the frame but pass it on
+			 * and 'learn' the new sequence number */
+			if (gph->seq_tx != lle->vu_recv_last) {
+				lle->vu_recv_last = gph->seq_tx;
+				lle->vu_recv_duplicates = 0;
+			} else {
+				lle->vu_recv_duplicates++;
+				if (lle->vu_recv_duplicates < 3)
+					return -EIO;
+				LOGP(DLLC, LOGL_NOTICE, "TLLI=%08x recovering "
+				     "N(U=%d) after receiving %u duplicates\n",
+					lle->llme ? lle->llme->tlli : -1,
+					gph->seq_tx, lle->vu_recv_duplicates);
+			}
 		}
 		/* Increment the sequence number that we expect in the next frame */
 		lle->vu_recv = (gph->seq_tx + 1) % 512;