Fix: LAPDm contention resoltion must acknowledge subsequent SABM

After reception of SABM, the network responds with UA and enters the
establised multiframe state. If UA is not received by mobile, the SABM
is transmitted again, and the network must respond with UA again, unless
it is from a different mobile.

Add LAPDm collision test (contention resolution on network side).
diff --git a/src/gsm/lapd_core.c b/src/gsm/lapd_core.c
index b33cf6e..f351308 100644
--- a/src/gsm/lapd_core.c
+++ b/src/gsm/lapd_core.c
@@ -820,7 +820,12 @@
 				"frame established state\n");
 			/* If link is lost on the remote side, we start over
 			 * and send DL-ESTABLISH indication again. */
-			if (dl->v_send != dl->v_recv) {
+			/* Additionally, continue in case of content resoltion
+			 * (GSM network). This happens, if the mobile has not
+			 * yet received UA or another mobile (collision) tries
+			 * to establish connection. The mobile must receive
+			 * UA again. */
+			if (!dl->cont_res && dl->v_send != dl->v_recv) {
 				LOGP(DLLAPD, LOGL_INFO, "Remote reestablish\n");
 				mdl_error(MDL_CAUSE_SABM_MF, lctx);
 				break;
@@ -831,7 +836,8 @@
 #ifdef TEST_CONTENT_RESOLUTION_NETWORK
 				dl->cont_res->data[0] ^= 0x01;
 #endif
-				if (memcmp(dl->cont_res, msg->data, length)) {
+				if (memcmp(dl->cont_res->data, msg->data,
+								length)) {
 					LOGP(DLLAPD, LOGL_INFO, "Another SABM "
 						"with diffrent content - "
 						"ignoring!\n");
diff --git a/tests/lapd/lapd_test.c b/tests/lapd/lapd_test.c
index a60c45d..49b7eef 100644
--- a/tests/lapd/lapd_test.c
+++ b/tests/lapd/lapd_test.c
@@ -67,6 +67,12 @@
 	0x2b, 0x2b, 0x2b, 0x2b
 };
 
+static const uint8_t ua[] = {
+	0x01, 0x73, 0x41, 0x05, 0x24, 0x31, 0x03, 0x50,
+	0x18, 0x93, 0x08, 0x29, 0x47, 0x80, 0x00, 0x00,
+	0x00, 0x00, 0x80, 0x2b, 0x2b, 0x2b, 0x2b
+};
+
 static const uint8_t mm[] = {
 	0x00, 0x0c, 0x00, 0x03, 0x01, 0x01, 0x20, 0x02,
 	0x00, 0x0b, 0x00, 0x03, 0x05, 0x04, 0x0d
@@ -153,6 +159,32 @@
 	return 0;
 }
 
+static int send_sabm(struct lapdm_channel *chan, int second_ms)
+{
+	struct osmo_phsap_prim pp;
+	struct msgb *msg;
+	int rc;
+
+	msg = msgb_alloc_headroom(128, 64, "PH-DATA.ind");
+	osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_DATA,
+			PRIM_OP_INDICATION, msg);
+	/* copy over actual MAC block */
+	msg->l2h = msgb_put(msg, 23);
+	msg->l2h[0] = 0x01;
+	msg->l2h[1] = 0x3f;
+	msg->l2h[2] = 0x01 | (sizeof(cm) << 2);
+	memcpy(msg->l2h + 3, cm_padded, sizeof(cm_padded));
+	msg->l2h[3] += second_ms; /* alter message, for second mobile */
+
+	/* LAPDm requires those... */
+	pp.u.data.chan_nr = 0;
+	pp.u.data.link_id = 0;
+        /* feed into the LAPDm code of libosmogsm */
+        rc = lapdm_phsap_up(&pp.oph, &chan->lapdm_dcch);
+	OSMO_ASSERT(rc == 0 || rc == -EBUSY);
+	return 0;
+}
+
 /*
  * I get called from the LAPDm code when something was sent my way...
  */
@@ -348,12 +380,56 @@
 	lapdm_channel_exit(&bts_to_ms_channel);
 }
 
+static void test_lapdm_contention_resolution()
+{
+	printf("I test contention resultion by having two mobiles collide and "
+		"first mobile repeating SABM.\n");
+
+	int rc;
+	struct lapdm_polling_state test_state;
+	struct osmo_phsap_prim pp;
+
+	/* Configure LAPDm on both sides */
+	struct lapdm_channel bts_to_ms_channel;
+	memset(&bts_to_ms_channel, 0, sizeof(bts_to_ms_channel));
+
+	memset(&test_state, 0, sizeof(test_state));
+	test_state.bts = &bts_to_ms_channel;
+
+	/* BTS to MS in polling mode */
+	lapdm_channel_init(&bts_to_ms_channel, LAPDM_MODE_BTS);
+	lapdm_channel_set_flags(&bts_to_ms_channel, LAPDM_ENT_F_POLLING_ONLY);
+	lapdm_channel_set_l1(&bts_to_ms_channel, NULL, &test_state);
+	lapdm_channel_set_l3(&bts_to_ms_channel, bts_to_ms_tx_cb, &test_state);
+
+	/* Send SABM MS 1, we must get UA */
+	send_sabm(&bts_to_ms_channel, 0);
+	rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+	CHECK_RC(rc);
+	OSMO_ASSERT(memcmp(pp.oph.msg->l2h, ua, ARRAY_SIZE(ua)) == 0);
+
+	/* Send SABM MS 2, we must get nothing, due to collision */
+	send_sabm(&bts_to_ms_channel, 1);
+	rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+	OSMO_ASSERT(rc == -ENODEV);
+
+	/* Send SABM MS 1 again, we must get UA gain */
+	send_sabm(&bts_to_ms_channel, 0);
+	rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+	CHECK_RC(rc);
+	OSMO_ASSERT(memcmp(pp.oph.msg->l2h, ua, ARRAY_SIZE(ua)) == 0);
+
+	/* clean up */
+	lapdm_channel_exit(&bts_to_ms_channel);
+}
+
 int main(int argc, char **argv)
 {
 	osmo_init_logging(&info);
 
 	test_lapdm_polling();
 	test_lapdm_early_release();
+	test_lapdm_contention_resolution();
 	printf("Success.\n");
 
 	return 0;
diff --git a/tests/lapd/lapd_test.ok b/tests/lapd/lapd_test.ok
index f1b990e..aa92708 100644
--- a/tests/lapd/lapd_test.ok
+++ b/tests/lapd/lapd_test.ok
@@ -18,4 +18,7 @@
 bts_to_ms_tx_cb: MS->BTS(us) message 14
 BTS: Verifying dummy message.
 I test RF channel release of an unestablished channel.
+I test contention resultion by having two mobiles collide and first mobile repeating SABM.
+bts_to_ms_tx_cb: MS->BTS(us) message 29
+BTS: Verifying CM request.
 Success.