implement human-readable RSL cause printing
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index 394d98e..a494ad3 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -314,18 +314,55 @@
 		memset(out+len, 0x2b, MACBLOCK_SIZE-len);
 }
 
-static void print_rsl_cause(u_int8_t *cause_tlv)
+static const char *rsl_err_vals[0xff] = {
+	[RSL_ERR_RADIO_IF_FAIL] =	"Radio Interface Failure",
+	[RSL_ERR_RADIO_LINK_FAIL] =	"Radio Link Failure",
+	[RSL_ERR_HANDOVER_ACC_FAIL] =	"Handover Access Failure",
+	[RSL_ERR_TALKER_ACC_FAIL] =	"Talker Access Failure",
+	[RSL_ERR_OM_INTERVENTION] =	"O&M Intervention",
+	[RSL_ERR_NORMAL_UNSPEC] =	"Normal event, unspecified",
+	[RSL_ERR_EQUIPMENT_FAIL] =	"Equipment Failure",
+	[RSL_ERR_RR_UNAVAIL] =		"Radio Resource not available",
+	[RSL_ERR_TERR_CH_FAIL] =	"Terrestrial Channel Failure",
+	[RSL_ERR_CCCH_OVERLOAD] =	"CCCH Overload",
+	[RSL_ERR_ACCH_OVERLOAD] =	"ACCH Overload",
+	[RSL_ERR_PROCESSOR_OVERLOAD] =	"Processor Overload",
+	[RSL_ERR_RES_UNAVAIL] =		"Resource not available, unspecified",
+	[RSL_ERR_TRANSC_UNAVAIL] =	"Transcoding not available",
+	[RSL_ERR_SERV_OPT_UNAVAIL] =	"Service or Option not available",
+	[RSL_ERR_ENCR_UNIMPL] =		"Encryption algorithm not implemented",
+	[RSL_ERR_SERV_OPT_UNIMPL] =	"Service or Option not implemented",
+	[RSL_ERR_RCH_ALR_ACTV_ALLOC] =	"Radio channel already activated",
+	[RSL_ERR_INVALID_MESSAGE] =	"Invalid Message, unspecified",
+	[RSL_ERR_MSG_DISCR] =		"Message Discriminator Error",
+	[RSL_ERR_MSG_TYPE] =		"Message Type Error",
+	[RSL_ERR_MSG_SEQ] =		"Message Sequence Error",
+	[RSL_ERR_IE_ERROR] =		"General IE error",
+	[RSL_ERR_MAND_IE_ERROR] =	"Mandatory IE error",
+	[RSL_ERR_OPT_IE_ERROR] =	"Optional IE error",
+	[RSL_ERR_IE_NONEXIST] =		"IE non-existent",
+	[RSL_ERR_IE_LENGTH] =		"IE length error",
+	[RSL_ERR_IE_CONTENT] =		"IE content error",
+	[RSL_ERR_PROTO] =		"Protocol error, unspecified",
+	[RSL_ERR_INTERWORKING] =	"Interworking error, unspecified",
+};
+
+static const char *rsl_err_name(u_int8_t err)
 {
-	u_int8_t cause_len;
+	if (rsl_err_vals[err])
+		return rsl_err_vals[err];
+	else
+		return "unknown";
+}
+
+static void print_rsl_cause(const u_int8_t *cause_v, u_int8_t cause_len)
+{
 	int i;
 
-	if (cause_tlv[0] != RSL_IE_CAUSE)
-		return;
-
-	cause_len = cause_tlv[1];
-	DEBUGPC(DRSL, "CAUSE: ");
-	for (i = 0; i < cause_len; i++) 
-		DEBUGPC(DRSL, "%02x ", cause_tlv[2+i]);
+	DEBUGPC(DRSL, "CAUSE=0x%02x(%s) ",
+		cause_v[0], rsl_err_name(cause_v[0]));
+	for (i = 1; i < cause_len-1; i++) 
+		DEBUGPC(DRSL, "%02x ", cause_v[i]);
 }
 
 /* Send a BCCH_INFO message as per Chapter 8.5.1 */
@@ -817,8 +854,9 @@
 
 	rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
 	if (TLVP_PRESENT(&tp, RSL_IE_CAUSE))
-		DEBUGPC(DRSL, "CAUSE=0x%02x ", *TLVP_VAL(&tp, RSL_IE_CAUSE));
-	
+		print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE),
+				TLVP_LEN(&tp, RSL_IE_CAUSE));
+
 	return 0;
 }
 
@@ -829,10 +867,13 @@
 	struct tlv_parsed tp;
 
 	DEBUGPC(DRSL, "CONNECTION FAIL: ");
-	print_rsl_cause(dh->data);
 
 	rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
 
+	if (TLVP_PRESENT(&tp, RSL_IE_CAUSE))
+		print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE),
+				TLVP_LEN(&tp, RSL_IE_CAUSE));
+
 	if (msg->trx->bts->type == GSM_BTS_TYPE_BS11) {
 		/* FIXME: we have no idea what cause 0x18 is !!! */
 		if (TLVP_PRESENT(&tp, RSL_IE_CAUSE) &&
@@ -954,9 +995,16 @@
 static int rsl_rx_error_rep(struct msgb *msg)
 {
 	struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
+	struct tlv_parsed tp;
 
 	DEBUGP(DRSL, "ERROR REPORT ");
-	print_rsl_cause(rslh->data);
+
+	rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh));
+
+	if (TLVP_PRESENT(&tp, RSL_IE_CAUSE))
+		print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE),
+				TLVP_LEN(&tp, RSL_IE_CAUSE));
+
 	DEBUGPC(DRSL, "\n");
 
 	return 0;
@@ -1292,12 +1340,10 @@
 	struct tlv_parsed tv;
 
 	rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh));
-	if (!TLVP_PRESENT(&tv, RSL_IE_CAUSE)) {
-		DEBUGPC(DRSL, "mandatory IE missing! ");
-		return -EINVAL;
-	}
 
-	DEBUGPC(DRSL, "cause=0x%02x ", *TLVP_VAL(&tv, RSL_IE_CAUSE));
+	if (TLVP_PRESENT(&tv, RSL_IE_CAUSE))
+		print_rsl_cause(TLVP_VAL(&tv, RSL_IE_CAUSE),
+				TLVP_LEN(&tv, RSL_IE_CAUSE));
 
 	return 0;
 }