gsm/lapdm: Prevent LAPD tx_queue from filling up in polling mode

If LAPDm receives an I-Frame while there already is an I-Frame in the
tx_queue the code generates an additional RR (to acknowledge the
received I-Frame). Instead, N(R) of the I-Frame in the tx_queue should
be updated to ACK the data.
diff --git a/TODO-RELEASE b/TODO-RELEASE
new file mode 100644
index 0000000..2a1f978
--- /dev/null
+++ b/TODO-RELEASE
@@ -0,0 +1,2 @@
+#library	what		description / commit summary line
+libosmogsm	abi-change	Prevent LAPD tx_queue from filling up in polling mode
diff --git a/include/osmocom/gsm/lapd_core.h b/include/osmocom/gsm/lapd_core.h
index c2fdc62..f88fb11 100644
--- a/include/osmocom/gsm/lapd_core.h
+++ b/include/osmocom/gsm/lapd_core.h
@@ -125,6 +125,7 @@
 	int (*send_dlsap)(struct osmo_dlsap_prim *dp,
 	        struct lapd_msg_ctx *lctx);
 	int (*send_ph_data_req)(struct lapd_msg_ctx *lctx, struct msgb *msg);
+	int (*update_pending_frames)(struct lapd_msg_ctx *lctx);
 	struct {
 		/*! \brief filled-in once we set the lapd_mode above */
 		struct lapd_cr_ent loc2rem;
diff --git a/src/gsm/lapd_core.c b/src/gsm/lapd_core.c
index ef1d22a..8c5fe9c 100644
--- a/src/gsm/lapd_core.c
+++ b/src/gsm/lapd_core.c
@@ -1607,6 +1607,12 @@
 		if (!dl->own_busy) {
 			/* NOTE: V(R) is already set above */
 			rc = lapd_send_i(lctx, __LINE__);
+
+			/* if update_pending_iframe returns 0 it updated
+			 * the lapd header of an iframe in the tx queue */
+			if (rc && dl->update_pending_frames)
+				rc = dl->update_pending_frames(lctx);
+
 			if (rc) {
 				LOGP(DLLAPD, LOGL_INFO, "we are not busy and "
 					"have no pending data, send RR\n");
diff --git a/src/gsm/lapdm.c b/src/gsm/lapdm.c
index 4edae63..698f850 100644
--- a/src/gsm/lapdm.c
+++ b/src/gsm/lapdm.c
@@ -114,6 +114,7 @@
 static int lapdm_send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg);
 static int send_rslms_dlsap(struct osmo_dlsap_prim *dp,
 	struct lapd_msg_ctx *lctx);
+static int update_pending_frames(struct lapd_msg_ctx *lctx);
 
 static void lapdm_dl_init(struct lapdm_datalink *dl,
 			  struct lapdm_entity *entity, int t200)
@@ -124,6 +125,7 @@
 	dl->dl.reestablish = 0; /* GSM uses no reestablish */
 	dl->dl.send_ph_data_req = lapdm_send_ph_data_req;
 	dl->dl.send_dlsap = send_rslms_dlsap;
+	dl->dl.update_pending_frames = update_pending_frames;
 	dl->dl.n200_est_rel = N200_EST_REL;
 	dl->dl.n200 = N200;
 	dl->dl.t203_sec = 0; dl->dl.t203_usec = 0;
@@ -488,6 +490,25 @@
 			23);
 }
 
+static int update_pending_frames(struct lapd_msg_ctx *lctx)
+{
+	struct lapd_datalink *dl = lctx->dl;
+	struct msgb *msg;
+	int rc = -1;
+
+	llist_for_each_entry(msg, &dl->tx_queue, list) {
+		if (LAPDm_CTRL_is_I(msg->l2h[1])) {
+			msg->l2h[1] = LAPDm_CTRL_I(dl->v_recv, LAPDm_CTRL_I_Ns(msg->l2h[1]),
+					LAPDm_CTRL_PF_BIT(msg->l2h[1]));
+			rc = 0;
+		} else if (LAPDm_CTRL_is_S(msg->l2h[1])) {
+			LOGP(DLLAPD, LOGL_ERROR, "Supervisory frame in queue, this shouldn't happen\n");
+		}
+	}
+
+	return rc;
+}
+
 /* input into layer2 (from layer 1) */
 static int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le,
 	uint8_t chan_nr, uint8_t link_id)
diff --git a/tests/lapd/lapd_test.c b/tests/lapd/lapd_test.c
index c8bb394..18ea1dc 100644
--- a/tests/lapd/lapd_test.c
+++ b/tests/lapd/lapd_test.c
@@ -621,17 +621,13 @@
 	0xd2, 0x6f, 0x09, 0xf1, 0x07, 0x00, 0x01, 0x00, 0x02
 };
 
-const uint8_t gprs_susp_ack[] = {
-	0x01, 0x41, 0x01
-};
-
 const uint8_t cipher_cmd[] = {
 	0x06, 0x35, 0x01
 };
 
-/* The cipher command we send to the MS */
+/* The cipher command we send to the MS after updating our N(R) */
 const uint8_t cipher_cmd_out[] = {
-	0x03, 0x20, 0x0d, 0x06, 0x35, 0x01
+	0x03, 0x40, 0x0d, 0x06, 0x35, 0x01
 };
 
 uint8_t cipher_compl[] = {
@@ -730,7 +726,7 @@
 
 	rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
 	CHECK_RC(rc);
-	OSMO_ASSERT(memcmp(pp.oph.msg->l2h, gprs_susp_ack, ARRAY_SIZE(gprs_susp_ack)) == 0);
+	OSMO_ASSERT(memcmp(pp.oph.msg->l2h, cipher_compl_ack, ARRAY_SIZE(cipher_compl_ack)) == 0);
 
 	printf("\nEstablishing SAPI=3\n");
 	send_sabm(&bts_to_ms_channel, 3, NULL, 0);
@@ -746,7 +742,7 @@
 
 	rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
 	CHECK_RC(rc);
-	OSMO_ASSERT(memcmp(pp.oph.msg->l2h, cipher_compl_ack, ARRAY_SIZE(cipher_compl_ack)) == 0);
+	OSMO_ASSERT(memcmp(pp.oph.msg->l2h, cp_data_1_ack, ARRAY_SIZE(cp_data_1_ack)) == 0);
 
 	/* clean up */
 	lapdm_channel_exit(&bts_to_ms_channel);
diff --git a/tests/lapd/lapd_test.ok b/tests/lapd/lapd_test.ok
index a58a118..e188e27 100644
--- a/tests/lapd/lapd_test.ok
+++ b/tests/lapd/lapd_test.ok
@@ -68,27 +68,24 @@
 bts_to_ms_dummy_tx_cb: MS->BTS(us) message 22
 
 Dumping queue:
-00 00 17 [L2]> 03 20 0d [L3]> 06 35 01 
-00 00 17 [L2]> 01 41 01 
+00 00 17 [L2]> 03 40 0d [L3]> 06 35 01 
 
 Took message from DCCH queue: L2 header size 3, L3 size 20, SAP 0x1000000, 0/0, Link 0x00
-Message: [L2]> 03 20 0d [L3]> 06 35 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 
+Message: [L2]> 03 40 0d [L3]> 06 35 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 
 
 Sending Cipher Mode Complete
 bts_to_ms_dummy_tx_cb: MS->BTS(us) message 11
 
 Dumping queue:
-00 00 17 [L2]> 01 41 01 
 00 00 17 [L2]> 01 61 01 
 
 Took message from DCCH queue: L2 header size 23, L3 size 0, SAP 0x1000000, 0/0, Link 0x00
-Message: [L2]> 01 41 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 
+Message: [L2]> 01 61 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 
 
 Establishing SAPI=3
 bts_to_ms_dummy_tx_cb: MS->BTS(us) message 6
 
 Dumping queue:
-00 00 17 [L2]> 01 61 01 
 
 Took message from DCCH queue: L2 header size 3, L3 size 20, SAP 0x1000000, 0/0, Link 0x03
 Message: [L2]> 0d 73 01 [L3]> 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 
@@ -96,8 +93,7 @@
 Sending CP-DATA
 
 Dumping queue:
-00 00 17 [L2]> 01 61 01 
 
-Took message from DCCH queue: L2 header size 23, L3 size 0, SAP 0x1000000, 0/0, Link 0x00
-Message: [L2]> 01 61 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 
+Took message from DCCH queue: L2 header size 23, L3 size 0, SAP 0x1000000, 0/0, Link 0x03
+Message: [L2]> 0d 21 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 
 Success.