Merge branch 'master' into sms
diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h
index 12c607f..4f45357 100644
--- a/openbsc/include/openbsc/gsm_04_11.h
+++ b/openbsc/include/openbsc/gsm_04_11.h
@@ -16,6 +16,19 @@
 	GSM411_CP_IE_CAUSE		= 0x02,	/* 8.1.4.2. */
 };
 
+/* Section 8.1.4.2 / Table 8.2 */
+enum gsm411_cp_cause {
+	GSM411_CP_CAUSE_NET_FAIL	= 17,
+	GSM411_CP_CAUSE_CONGESTION	= 22,
+	GSM411_CP_CAUSE_INV_TRANS_ID	= 81,
+	GSM411_CP_CAUSE_SEMANT_INC_MSG	= 95,
+	GSM411_CP_CAUSE_INV_MAND_INF	= 96,
+	GSM411_CP_CAUSE_MSGTYPE_NOTEXIST= 97,
+	GSM411_CP_CAUSE_MSG_INCOMP_STATE= 98,
+	GSM411_CP_CAUSE_IE_NOTEXIST	= 99,
+	GSM411_CP_CAUSE_PROTOCOL_ERR	= 111,
+};
+
 /* Chapter 8.2.2 */
 #define GSM411_MT_RP_DATA_MO	0x00
 #define GSM411_MT_RP_DATA_MT	0x01
@@ -30,6 +43,36 @@
 	GSM411_IE_RP_CAUSE		= 0x42,	/* 8.2.5.4 */
 };
 
+/* Chapter 8.2.5.4 Table 8.4 */
+enum gsm411_rp_cause {
+	/* valid only for MO */
+	GSM411_RP_CAUSE_MO_NUM_UNASSIGNED	= 1,
+	GSM411_RP_CAUSE_MO_OP_DET_BARR		= 8,
+	GSM411_RP_CAUSE_MO_CALL_BARRED		= 10,
+	GSM411_RP_CAUSE_MO_SMS_REJECTED		= 21,
+	GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER	= 27,
+	GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR	= 28,
+	GSM411_RP_CAUSE_MO_FACILITY_REJ		= 29,
+	GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR	= 30,
+	GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER	= 38,
+	GSM411_RP_CAUSE_MO_TEMP_FAIL		= 41,
+	GSM411_RP_CAUSE_MO_CONGESTION		= 42,
+	GSM411_RP_CAUSE_MO_RES_UNAVAIL		= 47,
+	GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR	= 50,
+	GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL	= 69,
+	GSM411_RP_CAUSE_MO_INTERWORKING		= 127,
+	/* valid only for MT */
+	GSM411_RP_CAUSE_MT_MEM_EXCEEDED		= 22,
+	/* valid for both directions */
+	GSM411_RP_CAUSE_INV_TRANS_REF		= 81,
+	GSM411_RP_CAUSE_SEMANT_INC_MSG		= 95,
+	GSM411_RP_CAUSE_INV_MAND_INF		= 96,
+	GSM411_RP_CAUSE_MSGTYPE_NOTEXIST	= 97,
+	GSM411_RP_CAUSE_MSG_INCOMP_STATE	= 98,
+	GSM411_RP_CAUSE_IE_NOTEXIST		= 99,
+	GSM411_RP_CAUSE_PROTOCOL_ERR		= 111,
+};
+
 /* Chapter 8.2.1 */
 struct gsm411_rp_hdr {
 	u_int8_t len;
@@ -49,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;
@@ -144,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;
@@ -166,7 +209,4 @@
 
 int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms);
 
-struct msgb *gsm411_msgb_alloc(void);
-int gsm0411_sendmsg(struct msgb *msg);
-
 #endif
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 5eac8a7..087123f 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", \
@@ -388,6 +388,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/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h
index 00eeb32..f182230 100644
--- a/openbsc/include/openbsc/gsm_subscriber.h
+++ b/openbsc/include/openbsc/gsm_subscriber.h
@@ -50,6 +50,7 @@
 	GSM_SUBSCRIBER_IMSI,
 	GSM_SUBSCRIBER_TMSI,
 	GSM_SUBSCRIBER_EXTENSION,
+	GSM_SUBSCRIBER_ID,
 };
 
 enum gsm_subscriber_update_reason {
diff --git a/openbsc/src/db.c b/openbsc/src/db.c
index fc2950a..57c5c85 100644
--- a/openbsc/src/db.c
+++ b/openbsc/src/db.c
@@ -79,7 +79,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 ("
@@ -235,6 +235,13 @@
 		);
 		free(quoted);
 		break;
+	case GSM_SUBSCRIBER_ID:
+		dbi_conn_quote_string_copy(conn, id, &quoted);
+		result = dbi_conn_queryf(conn,
+			"SELECT * FROM Subscriber "
+			"WHERE id = %s ", quoted);
+		free(quoted);
+		break;
 	default:
 		printf("DB: Unknown query selector for Subscriber.\n");
 		return NULL;
@@ -446,16 +453,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;
@@ -468,7 +479,10 @@
 struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id)
 {
 	dbi_result result;
+	long long unsigned int sender_id, receiver_id;
 	struct gsm_sms *sms = malloc(sizeof(*sms));
+	char *text;
+	char buf[32];
 
 	if (!sms) {
 		free(sms);
@@ -482,8 +496,21 @@
 		free(sms);
 		return NULL;
 	}
+	sms->id = dbi_result_get_ulonglong(result, "id");
 
-	/* FIXME: fill gsm_sms from database */
+	sender_id = dbi_result_get_ulonglong(result, "sender_id");
+	sprintf(buf, "%llu", sender_id);
+	sms->sender = db_get_subscriber(net, GSM_SUBSCRIBER_ID, buf); 
+
+	receiver_id = dbi_result_get_ulonglong(result, "receiver_id");
+	sprintf(buf, "%llu", receiver_id);
+	sms->receiver = db_get_subscriber(net, GSM_SUBSCRIBER_ID, buf); 
+
+	/* FIXME: fill header */
+
+	text = dbi_result_get_string(result, "text");
+	if (text)
+		strncpy(sms->text, text, sizeof(sms->text));
 
 	dbi_result_free(result);
 	return sms;
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index 28d573a..e82bd0c 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -240,7 +240,7 @@
 		rep->flags |= MEAS_REP_F_BA1;
 	if (data[0] & 0x40)
 		rep->flags |= MEAS_REP_F_DTX;
-	if (data[1] & 0x40)
+	if ((data[1] & 0x40) == 0x00)
 		rep->flags |= MEAS_REP_F_VALID;
 
 	rep->rxlev_full = data[0] & 0x3f;
diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c
index 8db402b..ed39f79 100644
--- a/openbsc/src/gsm_04_11.c
+++ b/openbsc/src/gsm_04_11.c
@@ -55,7 +55,7 @@
 				   "GSM 04.11");
 }
 
-int gsm0411_sendmsg(struct msgb *msg)
+static int gsm411_sendmsg(struct msgb *msg)
 {
 	if (msg->lchan)
 		msg->trx = msg->lchan->ts->trx;
@@ -65,6 +65,35 @@
 	return rsl_data_request(msg, 0);
 }
 
+/* Prefix msg with a 04.08/04.11 CP header */
+static int gsm411_cp_sendmsg(struct msgb *msg, u_int8_t msg_type,
+			     u_int8_t trans_id)
+{
+	struct gsm48_hdr *gh;
+
+	gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
+	/* Outgoing needs the highest bit set */
+	gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
+	gh->msg_type = msg_type;
+
+	return gsm411_sendmsg(msg);
+}
+
+/* Prefix msg with a RP-DATA header and send as CP-DATA */
+static int gsm411_rp_sendmsg(struct msgb *msg, u_int8_t rp_msg_type,
+			     u_int8_t rp_msg_ref, u_int8_t cp_trans_id)
+{
+	struct gsm411_rp_hdr *rp;
+
+	/* GSM 04.11 RP-DATA header */
+	rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
+	rp->len = msg->len;
+	rp->msg_type = rp_msg_type;
+	rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */
+
+	return gsm411_cp_sendmsg(msg, GSM411_MT_CP_DATA, cp_trans_id);
+}
+
 
 #if 0
 static u_int8_t gsm0411_tpdu_from_sms(u_int8_t *tpdu, struct sms_deliver *sms)
@@ -144,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)
 {
 	struct gsm_bts *bts = msg->lchan->ts->trx->bts;
@@ -168,7 +196,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)
@@ -178,7 +206,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));
 
@@ -186,7 +214,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);
 
@@ -197,7 +225,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));
@@ -250,13 +278,19 @@
 			"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(bts->network, sms->dest_addr);
 	if (!gsms->receiver) {
@@ -265,6 +299,9 @@
 	}
 
 	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) {
@@ -275,12 +312,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);
@@ -292,48 +334,26 @@
 		u_int8_t msg_ref)
 {
 	struct msgb *msg = gsm411_msgb_alloc();
-	struct gsm48_hdr *gh;
-	struct gsm411_rp_hdr *rp;
 
 	msg->lchan = lchan;
 
-	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
-	// Outgoing needs the highest bit set
-	gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
-	gh->msg_type = GSM411_MT_CP_DATA;
-
-	rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
-	rp->len = 2;
-	rp->msg_type = GSM411_MT_RP_ACK_MT;
-	rp->msg_ref = msg_ref;
-
 	DEBUGP(DSMS, "TX: SMS RP ACK\n");
 
-	return gsm0411_sendmsg(msg);
+	return gsm411_rp_sendmsg(msg, GSM411_MT_RP_ACK_MT, msg_ref, trans_id);
 }
 
 static int gsm411_send_rp_error(struct gsm_lchan *lchan, u_int8_t trans_id,
 		u_int8_t msg_ref, u_int8_t cause)
 {
 	struct msgb *msg = gsm411_msgb_alloc();
-	struct gsm48_hdr *gh;
-	struct gsm411_rp_hdr *rp;
 
 	msg->lchan = lchan;
 
-	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
-	// Outgoing needs the highest bit set
-	gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
-	gh->msg_type = GSM411_MT_CP_DATA;
-
-	rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
-	rp->msg_type = GSM411_MT_RP_ERROR_MT;
-	rp->msg_ref = msg_ref;
 	msgb_tv_put(msg, 1, cause);
 
 	DEBUGP(DSMS, "TX: SMS RP ERROR (cause %02d)\n", cause);
 
-	return gsm0411_sendmsg(msg);
+	return gsm411_rp_sendmsg(msg, GSM411_MT_RP_ERROR_MT, msg_ref, trans_id);
 }
 
 /* Receive a 04.11 TPDU inside RP-DATA / user data */
@@ -351,12 +371,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)
@@ -386,11 +407,42 @@
 	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 */
+
+	/* we need to look-up the transaction based on rph->msg_ref to
+	 * identify which particular RP_DATA/SMS-submit was ACKed */
+
+}
+
+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 */
+
+	/* we need to look-up the transaction based on rph->msg_ref to
+	 * identify which particular RP_DATA/SMS-submit failed */
+
+}
+
+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;
@@ -403,16 +455,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;
 	}
@@ -470,32 +523,26 @@
 int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms)
 {
 	struct msgb *msg = gsm411_msgb_alloc();
-	struct gsm48_hdr *gh;
-	struct gsm411_rp_hdr *rp;
 	u_int8_t *data;
+	u_int8_t msg_ref = 42;
+	u_int8_t trans_id = 23;
 
 	msg->lchan = lchan;
 
-	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
-	gh->proto_discr = GSM48_PDISC_SMS;
-	gh->msg_type = GSM411_MT_CP_DATA;
-
-	rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
-	rp->len = sizeof(tpdu_test) + 10;
-	rp->msg_type = GSM411_MT_RP_DATA_MT;
-	rp->msg_ref = 42; /* FIXME: Choose randomly */
-	/* Hardcode OA for now */
+	/* Hardcode Originating Address for now */
 	data = (u_int8_t *)msgb_put(msg, 8);
-	data[0] = 0x07;
-	data[1] = 0x91;
-	data[2] = 0x44;
+	data[0] = 0x07;	/* originator length == 7 */
+	data[1] = 0x91; /* type of number: international, ISDN */
+	data[2] = 0x44; /* 447785016005 */
 	data[3] = 0x77;
 	data[4] = 0x58;
 	data[5] = 0x10;
 	data[6] = 0x06;
 	data[7] = 0x50;
+
+	/* Hardcoded Destination Address */
 	data = (u_int8_t *)msgb_put(msg, 1);
-	data[0] = 0;
+	data[0] = 0;	/* destination length == 0 */
 
 	/* FIXME: Hardcoded for now */
 	//smslen = gsm0411_tpdu_from_sms(tpdu, sms);
@@ -511,5 +558,5 @@
 
 	DEBUGP(DSMS, "TX: SMS SUBMIT\n");
 
-	return gsm0411_sendmsg(msg);
+	return gsm411_rp_sendmsg(msg, GSM411_MT_RP_DATA_MT, msg_ref, trans_id);
 }
diff --git a/openbsc/src/gsm_subscriber.c b/openbsc/src/gsm_subscriber.c
index e892906..60dec43 100644
--- a/openbsc/src/gsm_subscriber.c
+++ b/openbsc/src/gsm_subscriber.c
@@ -179,7 +179,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",