SNDCP: add RFC1144 header compression functionality

- Add module to handle compression entities
- Add module to control header compression
- Introduce VTY commands for heade compression configuration
- Add changes in sndcp and llc to integrate header compression

Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index a2ffa51..ff771b8 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -40,6 +40,7 @@
 #include <openbsc/crc24.h>
 #include <openbsc/sgsn.h>
 #include <openbsc/gprs_llc_xid.h>
+#include <openbsc/gprs_sndcp_comp.h>
 #include <openbsc/gprs_sndcp.h>
 
 static struct gprs_llc_llme *llme_alloc(uint32_t tlli);
@@ -140,6 +141,16 @@
 
 	struct llist_head *xid_fields;
 	struct gprs_llc_xid_field *xid_field;
+	struct gprs_llc_xid_field *xid_field_request;
+	struct gprs_llc_xid_field *xid_field_request_l3 = NULL;
+
+	/* Pick layer3 XID from the XID request we have sent last */
+	if (lle->llme->xid) {
+		llist_for_each_entry(xid_field_request, lle->llme->xid, list) {
+			if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR)
+				xid_field_request_l3 = xid_field_request;
+		}
+	}
 
 	/* Parse and analyze XID-Response */
 	xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len);
@@ -150,12 +161,10 @@
 		llist_for_each_entry(xid_field, xid_fields, list) {
 
 			/* Forward SNDCP-XID fields to Layer 3 (SNDCP) */
-			if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) {
-				LOGP(DLLC, LOGL_NOTICE,
-				     "Ignoring SNDCP-XID-Field: XID: type=%i, data_len=%i, data=%s\n",
-				     xid_field->type, xid_field->data_len,
-				     osmo_hexdump_nospc(xid_field->data,
-				     xid_field->data_len));
+			if (xid_field->type == GPRS_LLC_XID_T_L3_PAR &&
+			    xid_field_request_l3) {
+				sndcp_sn_xid_conf(xid_field,
+						  xid_field_request_l3, lle);
 			}
 
 			/* Process LLC-XID fields: */
@@ -204,10 +213,6 @@
 	struct gprs_llc_xid_field *xid_field;
 	struct gprs_llc_xid_field *xid_field_response;
 
-	/* Flush eventually pending XID fields */
-	talloc_free(lle->llme->xid);
-	lle->llme->xid = NULL;
-
 	/* Parse and analyze XID-Request */
 	xid_fields =
 	    gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len);
@@ -239,6 +244,23 @@
 			}
 		}
 
+		/* Forward SNDCP-XID fields to Layer 3 (SNDCP) */
+		llist_for_each_entry(xid_field, xid_fields, list) {
+			if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) {
+
+				xid_field_response =
+				    talloc_zero(lle->llme,
+						struct gprs_llc_xid_field);
+				rc = sndcp_sn_xid_ind(xid_field,
+						      xid_field_response, lle);
+				if (rc == 0)
+					llist_add(&xid_field_response->list,
+						  xid_fields_response);
+				else
+					talloc_free(xid_field_response);
+			}
+		}
+
 		rc = gprs_llc_compile_xid(bytes_response,
 					  bytes_response_maxlen,
 					  xid_fields_response);
@@ -269,9 +291,13 @@
 		    gprs_llc_process_xid_ind(gph->data, gph->data_len,
 					     response, sizeof(response),
 					     lle);
-		xid = msgb_put(resp, response_len);
-		memcpy(xid, response, response_len);
-
+		if (response_len < 0) {
+			LOGP(DLLC, LOGL_ERROR,
+			     "invalid XID indication received!\n");
+		} else {
+			xid = msgb_put(resp, response_len);
+			memcpy(xid, response, response_len);
+		}
 		gprs_llc_tx_xid(lle, resp, 0);
 	} else {
 		LOGP(DLLC, LOGL_NOTICE,
@@ -525,11 +551,16 @@
 
 	llist_add(&llme->list, &gprs_llc_llmes);
 
+	llme->comp.proto = gprs_sndcp_comp_alloc(llme);
+	llme->comp.data = gprs_sndcp_comp_alloc(llme);
+
 	return llme;
 }
 
 static void llme_free(struct gprs_llc_llme *llme)
 {
+	gprs_sndcp_comp_free(llme->comp.proto);
+	gprs_sndcp_comp_free(llme->comp.data);
 	talloc_free(llme->xid);
 	llist_del(&llme->list);
 	talloc_free(llme);