more SMS improvements

* describe data structures in gsm_04_11.h
* increae LCHAN RELEASE TIMEOUT for case of long SMS
* convert header field in sql table from NUMERIC to BLOB
* initial handling for validity period
* send RP ERROR messages with meaningful RP CAUSE in case of error
diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h
index 51c37f0..4f45357 100644
--- a/openbsc/include/openbsc/gsm_04_11.h
+++ b/openbsc/include/openbsc/gsm_04_11.h
@@ -92,20 +92,20 @@
 /* SMS submit PDU */
 struct sms_submit {
 	u_int8_t *smsc;
-	u_int8_t mti:2;
-	u_int8_t vpf:2;
-	u_int8_t msg_ref;
-	u_int8_t pid;
-	u_int8_t dcs;
-	u_int8_t *vp;
-	u_int8_t ud_len;
-	u_int8_t *user_data;
+	u_int8_t mti:2;		/* message type indicator */
+	u_int8_t vpf:2;		/* validity period format */
+	u_int8_t msg_ref;	/* message reference */
+	u_int8_t pid;		/* protocol identifier */
+	u_int8_t dcs;		/* data coding scheme */
+	u_int8_t *vp;		/* validity period */
+	u_int8_t ud_len;	/* user data length */
+	u_int8_t *user_data;	/* user data */
 
 	/* interpreted */
-	u_int8_t mms:1;
-	u_int8_t sri:1;
-	u_int8_t udhi:1;
-	u_int8_t rp:1;
+	u_int8_t mms:1;		/* more messages to send */
+	u_int8_t srr:1;		/* status report request */
+	u_int8_t udhi:1;	/* user data headre indication */
+	u_int8_t rp:1;		/* request for reply path */
 	enum sms_alphabet alphabet;
 	char dest_addr[20+1];	/* DA LV is 12 bytes max, i.e. 10 bytes BCD == 20 bytes string */
 	unsigned long validity_mins;
@@ -187,20 +187,20 @@
 
 /* SMS deliver PDU */
 struct sms_deliver {
+	u_int8_t mti:2;		/* message type indicator */
+	u_int8_t mms:1;		/* more messages to send */
+	u_int8_t rp:1;		/* reply path */
+	u_int8_t udhi:1;	/* user data header indicator */
+	u_int8_t sri:1;		/* status report indication */
+	u_int8_t *orig_addr;	/* originating address */
+	u_int8_t pid;		/* protocol identifier */
+	u_int8_t dcs;		/* data coding scheme */
+				/* service centre time stamp */
+	u_int8_t ud_len;	/* user data length */
+	u_int8_t *user_data;	/* user data */
+
+	u_int8_t msg_ref;	/* message reference */
 	u_int8_t *smsc;
-	u_int8_t mti:2;
-	u_int8_t rd:1;
-	u_int8_t vpf:2;
-	u_int8_t srr:1;
-	u_int8_t udhi:1;
-	u_int8_t rp:1;
-	u_int8_t msg_ref;
-	u_int8_t *orig_addr;
-	u_int8_t pid;
-	u_int8_t dcs;
-	u_int8_t vp;
-	u_int8_t ud_len;
-	u_int8_t *user_data;
 };
 
 struct msgb;
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index af2e22c..11176d6 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -74,7 +74,7 @@
  * Use the channel. As side effect the lchannel recycle timer
  * will be started.
  */
-#define LCHAN_RELEASE_TIMEOUT 10, 0
+#define LCHAN_RELEASE_TIMEOUT 20, 0
 #define use_lchan(lchan) \
 	do {	lchan->use_count++; \
 		DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \
@@ -381,6 +381,8 @@
 	struct gsm_subscriber *sender;
 	struct gsm_subscriber *receiver;
 
+	unsigned long validity_minutes;
+	unsigned int header_len;
 	unsigned char header[SMS_HDR_SIZE];
 	char text[SMS_TEXT_SIZE];
 };
diff --git a/openbsc/src/db.c b/openbsc/src/db.c
index 600699a..1bcd101 100644
--- a/openbsc/src/db.c
+++ b/openbsc/src/db.c
@@ -75,7 +75,7 @@
 		"sent TIMESTAMP, "
 		"sender_id NUMERIC NOT NULL, "
 		"receiver_id NUMERIC NOT NULL, "
-		"header NUMERIC, "
+		"header BLOB, "
 		"text TEXT NOT NULL "
 		")",
 	"CREATE TABLE IF NOT EXISTS VLR ("
@@ -402,16 +402,20 @@
 {
 	dbi_result result;
 	char *q_text;
+	unsigned char *q_header;
 
 	dbi_conn_quote_string_copy(conn, (char *)sms->text, &q_text);
+	dbi_conn_quote_binary_copy(conn, sms->header, sms->header_len,
+				   &q_header);
 	result = dbi_conn_queryf(conn,
 		"INSERT INTO SMS "
 		"(created,sender_id,receiver_id,header,text) VALUES "
 		"(datetime('now'),%llu,%llu,%s,%s)",
 		sms->sender->id,
 		sms->receiver ? sms->receiver->id : 0,
-		NULL, q_text);
+		q_header, q_text);
 	free(q_text);
+	free(q_header);
 
 	if (!result)
 		return -EIO;
diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c
index 351a5fc..68ccec6 100644
--- a/openbsc/src/gsm_04_11.c
+++ b/openbsc/src/gsm_04_11.c
@@ -173,14 +173,13 @@
 {
 	if (db_sms_store(gsms) != 0) {
 		DEBUGP(DSMS, "Failed to store SMS in Database\n");
-		talloc_free(sms);
-		talloc_free(gsms);
-		return -EIO;
+		return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
 	}
 	return 0;
 }
 
-/* process an incoming TPDU (called from RP-DATA) */
+/* process an incoming TPDU (called from RP-DATA) 
+ * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */ 
 static int gsm340_rx_tpdu(struct msgb *msg)
 {
 	u_int8_t *smsp = msgb_sms(msg);
@@ -196,7 +195,7 @@
 
 	sms = talloc(tall_sms_ctx, struct sms_submit);
 	if (!sms)
-		return -ENOMEM;
+		return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
 	memset(sms, 0, sizeof(*sms));
 
 	if (!tall_gsms_ctx)
@@ -206,7 +205,7 @@
 	gsms = talloc(tall_gsms_ctx, struct gsm_sms);
 	if (!gsms) {
 		talloc_free(sms);
-		return -ENOMEM;
+		return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
 	}
 	memset(gsms, 0, sizeof(*gsms));
 
@@ -214,7 +213,7 @@
 	sms->mti = *smsp & 0x03;
 	sms->mms = !!(*smsp & 0x04);
 	sms->vpf = (*smsp & 0x18) >> 3;
-	sms->sri = !!(*smsp & 0x20);
+	sms->srr = !!(*smsp & 0x20);
 	sms->udhi= !!(*smsp & 0x40);
 	sms->rp  = !!(*smsp & 0x80);
 
@@ -225,7 +224,7 @@
 	da_len_bytes = 2 + *smsp/2 + *smsp%2;
 	if (da_len_bytes > 12) {
 		DEBUGP(DSMS, "Destination Address > 12 bytes ?!?\n");
-		rc = -EIO;
+		rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
 		goto out;
 	}
 	memset(address_lv, 0, sizeof(address_lv));
@@ -278,21 +277,25 @@
 			"PID: 0x%02x, DCS: 0x%02x, DA: %s, UserDataLength: 0x%02x "
 			"UserData: \"%s\"\n", sms->mti, sms->vpf, sms->msg_ref,
 			sms->pid, sms->dcs, sms->dest_addr, sms->ud_len,
-			sms->alphabet == DCS_7BIT_DEFAULT ? sms->decoded : hexdump(sms->user_data, sms->ud_len));
+			sms->alphabet == DCS_7BIT_DEFAULT ? sms->decoded : 
+					hexdump(sms->user_data, sms->ud_len));
 
 	dispatch_signal(SS_SMS, 0, sms);
 
+	/* now we've filled the 'sms' structure.  Go on filling
+	 * the gsms structure based on information from the sms */
+
 	gsms->sender = msg->lchan->subscr;
 	/* FIXME: sender refcount */
 
+	gsms->validity_minutes = gsm340_validity_period(sms);
+
 	/* determine gsms->receiver based on dialled number */
 	gsms->receiver = subscr_get_by_extension(sms->dest_addr);
-	if (!gsms->receiver) {
-		rc = 1; /* cause 1: unknown subscriber */
-		goto out;
-	}
-
 	if (sms->user_data)
+		memcpy(gsms->header, sms->user_data, sms->ud_len);
+
+	if (sms->decoded)
 		strncpy(gsms->text, sms->decoded, sizeof(gsms->text));
 
 	switch (sms->mti) {
@@ -303,12 +306,17 @@
 	case GSM340_SMS_COMMAND_MS2SC:
 	case GSM340_SMS_DELIVER_REP_MS2SC:
 		DEBUGP(DSMS, "Unimplemented MTI 0x%02x\n", sms->mti);
+		rc = GSM411_RP_CAUSE_IE_NOTEXIST;
 		break;
 	default:
 		DEBUGP(DSMS, "Undefined MTI 0x%02x\n", sms->mti);
+		rc = GSM411_RP_CAUSE_IE_NOTEXIST;
 		break;
 	}
 
+	if (!rc && !gsms->receiver)
+		rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
+
 out:
 	talloc_free(gsms);
 	talloc_free(sms);
@@ -357,12 +365,13 @@
 
 	if (!dst_len || !dst || !tpdu_len || !tpdu) {
 		DEBUGP(DSMS, "RP-DATA (MO) without DST or TPDU ?!?\n");
+		gsm411_send_rp_error(msg->lchan, trans_id, rph->msg_ref,
+				     GSM411_RP_CAUSE_INV_MAND_INF);
 		return -EIO;
 	}
 	msg->smsh = tpdu;
 
 	DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
-	//return gsm411_send_rp_error(msg->lchan, trans_id, rph->msg_ref, rc);
 
 	rc = gsm340_rx_tpdu(msg);
 	if (rc == 0)
@@ -392,11 +401,36 @@
 	if (rpud_len)
 		rp_ud = &rph->data[1+src_len+1+dst_len+1];
 
-	DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n", src_len, dst_len, rpud_len);
+	DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
+		src_len, dst_len, rpud_len);
 	return gsm411_rx_rp_ud(msg, rph, src_len, src, dst_len, dst,
 				rpud_len, rp_ud);
 }
 
+
+static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm411_rp_hdr *rph)
+{
+	/* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
+	 * successfully received a SMS.  We can now safely mark it as
+	 * transmitted */
+
+}
+
+static int gsm411_rx_rp_error(struct msgb *msg, struct gsm411_rp_hdr *rph)
+{
+	/* Error in response to MT RP_DATA, i.e. the MS did not
+	 * successfully receive the SMS.  We need to investigate
+	 * the cause and take action depending on it */
+
+}
+
+static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm411_rp_hdr *rph)
+{
+	/* MS tells us that it has memory for more SMS, we need
+	 * to check if we have any pending messages for it and then
+	 * transfer those */
+}
+
 static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh)
 {
 	struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
@@ -409,16 +443,17 @@
 		rc = gsm411_rx_rp_data(msg, rp_data);
 		break;
 	case GSM411_MT_RP_ACK_MO:
-		/* Acnkowledgement to MT RP_DATA */
+		rc = gsm411_rx_rp_ack(msg, rp_data);
+		break;
 	case GSM411_MT_RP_ERROR_MO:
-		/* Error in response to MT RP_DATA */
+		rc = gsm411_rx_rp_error(msg, rp_data);
+		break;
 	case GSM411_MT_RP_SMMA_MO:
-		/* MS tells us that it has memory for more SMS, we need
-		 * to check if we have any pending messages for it and then
-		 * transfer those */
+		rc = gsm411_rx_rp_smma(msg, rp_data);
 		DEBUGP(DSMS, "Unimplemented RP type 0x%02x\n", msg_type);
 		break;
 	default:
+		/* FIXME: send GSM411_CP_CAUSE_MSGTYPE_NOTEXIST */
 		DEBUGP(DSMS, "Invalid RP type 0x%02x\n", msg_type);
 		break;
 	}
@@ -485,8 +520,8 @@
 	/* Hardcode Originating Address for now */
 	data = (u_int8_t *)msgb_put(msg, 8);
 	data[0] = 0x07;	/* originator length == 7 */
-	data[1] = 0x91; /* type of number */
-	data[2] = 0x44;
+	data[1] = 0x91; /* type of number: international, ISDN */
+	data[2] = 0x44; /* 447785016005 */
 	data[3] = 0x77;
 	data[4] = 0x58;
 	data[5] = 0x10;
diff --git a/openbsc/src/gsm_subscriber.c b/openbsc/src/gsm_subscriber.c
index a323d4e..32f436f 100644
--- a/openbsc/src/gsm_subscriber.c
+++ b/openbsc/src/gsm_subscriber.c
@@ -175,7 +175,6 @@
 		/* Only detach if we are currently in this area */
 		if (bts->location_area_code == s->lac)
 			s->lac = 0;
-
 		break;
 	default:
 		fprintf(stderr, "subscr_update with unknown reason: %d\n",