sndcp: Allow empty SNDCP-XID indications

In some rare cases the modem might send a xid indication that does
not contain anything except the version number field. The sgsn
ignors such SNDCP-XID indications by stripping the entire field
from the response. We found a modem in the wild that started to
act problematic when the empty SNDCP-XID was missing in the
response. This patch changes the XID negotiation behaviour in
a way that if a modem should send empty SNDCP-XID indications,
the reply will also contain an empty SNDCP-XID indication. Apart
from that the SNDCP-XID version number is now parsed and echoed
in the response. This ensures that we always reply with the version
number that the modem expects. (The version was 0 in all cases we
observed so far)

Change-Id: I097a770cb4907418f53e620a051ebb8cd110c5f2
Related: OS#1794
diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c
index 1cbeede..60455b5 100644
--- a/openbsc/src/gprs/gprs_sndcp.c
+++ b/openbsc/src/gprs/gprs_sndcp.c
@@ -960,8 +960,13 @@
 		llist_add(&v42bis_comp_field.list, &comp_fields);
 	}
 
+	/* Do not attempt to compile anything if there is no data in the list */
+	if (llist_empty(&comp_fields))
+		return 0;
+
 	/* Compile bytestream */
-	return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields);
+	return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields,
+				      DEFAULT_SNDCP_VERSION);
 }
 
 /* Set of SNDCP-XID bnegotiation (See also: TS 144 065,
@@ -1106,6 +1111,7 @@
 
 	int rc;
 	int compclass;
+	int version;
 
 	struct llist_head *comp_fields;
 	struct gprs_sndcp_comp_field *comp_field;
@@ -1115,22 +1121,13 @@
 	OSMO_ASSERT(lle);
 
 	/* Parse SNDCP-CID XID-Field */
-	comp_fields = gprs_sndcp_parse_xid(lle->llme,
+	comp_fields = gprs_sndcp_parse_xid(&version, lle->llme,
 					   xid_field_indication->data,
 					   xid_field_indication->data_len,
 					   NULL);
 	if (!comp_fields)
 		return -EINVAL;
 
-	/* Don't bother with empty indications */
-	if (llist_empty(comp_fields)) {
-		xid_field_response->data = NULL;
-		xid_field_response->data_len = 0;
-		DEBUGP(DSNDCP,
-		       "SNDCP-XID indication did not contain any parameters!\n");
-		return 0;
-	}
-
 	/* Handle compression entites */
 	DEBUGP(DSNDCP, "SNDCP-XID-IND (ms):\n");
 	gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG);
@@ -1168,7 +1165,7 @@
 	/* Compile modified SNDCP-XID bytes */
 	rc = gprs_sndcp_compile_xid(xid_field_response->data,
 				    xid_field_indication->data_len,
-				    comp_fields);
+				    comp_fields, 0);
 
 	if (rc > 0)
 		xid_field_response->data_len = rc;
@@ -1210,7 +1207,7 @@
 	OSMO_ASSERT(xid_field_request);
 
 	/* Parse SNDCP-CID XID-Field */
-	comp_fields_req = gprs_sndcp_parse_xid(lle->llme,
+	comp_fields_req = gprs_sndcp_parse_xid(NULL, lle->llme,
 					       xid_field_request->data,
 					       xid_field_request->data_len,
 					       NULL);
@@ -1221,7 +1218,7 @@
 	gprs_sndcp_dump_comp_fields(comp_fields_req, LOGL_DEBUG);
 
 	/* Parse SNDCP-CID XID-Field */
-	comp_fields_conf = gprs_sndcp_parse_xid(lle->llme,
+	comp_fields_conf = gprs_sndcp_parse_xid(NULL, lle->llme,
 						xid_field_conf->data,
 						xid_field_conf->data_len,
 						comp_fields_req);