[PATCH,v2] SMS decode

Gianni Tedesco gianni at scaramanga.co.uk
Sun May 15 15:50:40 UTC 2011


This is a folowup to previous patch implementing SMS decoding. I have
removed the 7bit decoding functions to use those in libosmocore. This
time I have also tried to send CP-ACK in response to the CP-DATA
containing the SMS. But this seems to break the entire state machine,
not sure what I'm doing wrong here. I just built the packet and used
gsm48_rr_downmsg() to send it. Maybe I just need to learn more about the
lower layers.

A BTS or a GSM tester would be really handy I guess...

Gianni

diff --git a/src/host/layer23/include/osmocom/bb/mobile/gsm48_sms.h b/src/host/layer23/include/osmocom/bb/mobile/gsm48_sms.h
new file mode 100644
index 0000000..99911ad
--- /dev/null
+++ b/src/host/layer23/include/osmocom/bb/mobile/gsm48_sms.h
@@ -0,0 +1,7 @@
+#ifndef _GSM48_SMS_H
+#define _GSM48_SMS_H
+
+int gsm48_rcv_sms(struct osmocom_ms *ms, struct msgb *msg);
+
+#endif /* _GSM48_SMS_H */
+
diff --git a/src/host/layer23/src/mobile/Makefile.am b/src/host/layer23/src/mobile/Makefile.am
index fb0423e..60e8d23 100644
--- a/src/host/layer23/src/mobile/Makefile.am
+++ b/src/host/layer23/src/mobile/Makefile.am
@@ -4,7 +4,7 @@ LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOG
 
 noinst_LIBRARIES = libmobile.a
 libmobile_a_SOURCES = gsm322.c gsm48_cc.c gsm48_mm.c gsm48_rr.c	\
-	mnccms.c settings.c subscriber.c support.c \
+	gsm48_sms.c mnccms.c settings.c subscriber.c support.c \
 	transaction.c vty_interface.c
 
 bin_PROGRAMS = mobile
diff --git a/src/host/layer23/src/mobile/gsm48_mm.c b/src/host/layer23/src/mobile/gsm48_mm.c
index bf5bbc2..2155a71 100644
--- a/src/host/layer23/src/mobile/gsm48_mm.c
+++ b/src/host/layer23/src/mobile/gsm48_mm.c
@@ -36,6 +36,7 @@
 #include <osmocom/bb/common/networks.h>
 #include <osmocom/bb/common/l1ctl.h>
 #include <osmocom/bb/mobile/gsm48_cc.h>
+#include <osmocom/bb/mobile/gsm48_sms.h>
 #include <osmocom/bb/mobile/app_mobile.h>
 
 extern void *l23_ctx;
@@ -737,10 +738,10 @@ int gsm48_mmxx_dequeue(struct osmocom_ms *ms)
 		case GSM48_MMSS_CLASS:
 			gsm48_rcv_ss(ms, msg);
 			break;
+#endif
 		case GSM48_MMSMS_CLASS:
 			gsm48_rcv_sms(ms, msg);
 			break;
-#endif
 		}
 		msgb_free(msg);
 		work = 1; /* work done */
@@ -3788,11 +3789,11 @@ static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg)
 		rr_prim = GSM48_MMSS_DATA_IND;
 		rr_est = GSM48_MMSS_EST_IND;
 		break;
+#endif
 	case GSM48_PDISC_SMS:
 		rr_prim = GSM48_MMSMS_DATA_IND;
 		rr_est = GSM48_MMSMS_EST_IND;
 		break;
-#endif
 	}
 	if (rr_prim != -1) {
 		uint8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4;
@@ -3847,9 +3848,10 @@ static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg)
 	case GSM48_PDISC_NC_SS:
 		return gsm48_rcv_ss(ms, msg);
 
+#endif
 	case GSM48_PDISC_SMS:
+		LOGP(DMM, LOGL_NOTICE, "SMS PDISC = 0x%.2x\n", GSM48_PDISC_SMS);
 		return gsm48_rcv_sms(ms, msg);
-#endif
 
 	default:
 		LOGP(DMM, LOGL_NOTICE, "Protocol type 0x%02x unsupported.\n",
diff --git a/src/host/layer23/src/mobile/gsm48_sms.c b/src/host/layer23/src/mobile/gsm48_sms.c
new file mode 100644
index 0000000..5337b1e
--- /dev/null
+++ b/src/host/layer23/src/mobile/gsm48_sms.c
@@ -0,0 +1,355 @@
+/*
+ * (C) 2010 by Andreas Eversberg <jolly at eversberg.eu>
+ * (C) 2011 by Gianni Tedesco <gianni at scaramanga.co.uk>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/core/talloc.h>
+
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/networks.h>
+#include <osmocom/bb/common/l1ctl.h>
+#include <osmocom/bb/mobile/gsm48_sms.h>
+#include <osmocom/bb/mobile/app_mobile.h>
+
+/* GSM 04.11 Table 8.1 */
+#define CP_DATA			1
+#define CP_ACK			4
+#define CP_ERROR		16
+
+#define CP_CAUSE_INVALID_MANDATORY_INFO		96
+#define CP_CAUSE_MSG_TYPE_NOT_IMPLEMENTED	97
+#define CP_CAUSE_INFO_ELEMENT_NOT_IMPLEMENTED	97
+#define CP_CAUSE_PROTOCOL_ERROR			111
+
+#define RP_DATA			1
+#define RP_ACK			3
+#define RP_ERROR		5
+
+#define TP_MTI_MASK		3
+#define SMS_DELIVER		0
+#define SMS_SUBMIT_REPORT	1
+#define SMS_STATUS_REPORT	2
+
+#define TP_RP		0x80
+#define TP_UDHI		0x40
+#define TP_SRI		0x20
+#define TP_MMS		0x04
+
+static uint8_t hi_nibble(uint8_t byte)
+{
+	return byte >> 4;
+}
+
+static uint8_t lo_nibble(uint8_t byte)
+{
+	return byte & 0xf;
+}
+
+static int parse_address(struct msgb *msg, int rp, const char *name)
+{
+	uint8_t len, type;
+
+	if ( !msg->len )
+		return -EPROTO;
+
+	len = msgb_get_u8(msg);
+	if ( !len )
+		return 0;
+	
+	type = msgb_get_u8(msg);
+
+	if ( rp ) {
+		/* for RP address, len is in bytes including type field */
+		len = len - 1;
+	}else{
+		/* TP address is in BCD digits, not including type field */
+		len = len / 2;
+	}
+
+	if ( msg->len < len )
+		return -EPROTO;
+
+	LOGP(DMM, LOGL_NOTICE, "%s: type=0x%.2x %s\n",
+		name, type, hexdump(msg->data, len));
+
+	msgb_pull(msg, len);
+	return 0;
+}
+
+static int parse_timestamp(struct msgb *msg, const char *name)
+{
+	if ( msg->len < 7 )
+		return -EPROTO;
+	 LOGP(DMM, LOGL_NOTICE,
+	 	"%s: 20%1x%1x-%1x%1x-%1x%1x %1x%1x:%1x%1x:%1x%1x\n",
+	 	name,
+		lo_nibble(msg->data[0]),
+		hi_nibble(msg->data[0]),
+		lo_nibble(msg->data[1]),
+		hi_nibble(msg->data[1]),
+		lo_nibble(msg->data[2]),
+		hi_nibble(msg->data[2]),
+		lo_nibble(msg->data[3]),
+		hi_nibble(msg->data[3]),
+		lo_nibble(msg->data[4]),
+		hi_nibble(msg->data[4]),
+		lo_nibble(msg->data[5]),
+		hi_nibble(msg->data[5]));
+	msgb_pull(msg, 7);
+	return 0;
+}
+
+static int sms_7bit(const uint8_t *in, size_t octets, size_t chars)
+{
+	char out[chars + 1];
+
+	if ( (chars * 7 + 6) / 8 > octets ) {
+		chars = (octets * 8) / 7;
+		octets = (chars * 7 + 6) / 8;
+	}
+
+	gsm_7bit_decode(out, in, octets);
+	LOGP(DMM, LOGL_NOTICE, "SMS-MSG: %s\n", out);
+	return 0;
+}
+
+static int sms_deliver(struct osmocom_ms *ms, struct msgb *msg, uint8_t b)
+{
+	uint8_t tp_pid, tp_dcs, tp_udlen;
+	int rc;
+
+	if ( !(b & TP_MMS) )
+		LOGP(DMM, LOGL_NOTICE, "SMS-DELIVER: More messages to send.\n");
+
+	rc = parse_address(msg, 0, "TP-Originating");
+	if ( rc )
+		return -EPROTO;
+
+	if ( msg->len < 2 )
+		return -EPROTO;
+
+	tp_pid = msgb_get_u8(msg);
+	tp_dcs = msgb_get_u8(msg);
+	LOGP(DMM, LOGL_NOTICE, "TP-PID: 0x%.2x\n", tp_pid);
+	LOGP(DMM, LOGL_NOTICE, "TP-DCS: 0x%.2x\n", tp_dcs);
+
+	rc = parse_timestamp(msg, "TP-Service-Center-Time-Stamp");
+	if ( rc )
+		return -EPROTO;
+
+	if ( !msg->len )
+		return -EPROTO;
+	tp_udlen = msgb_get_u8(msg);
+
+	/* TODO: user-data-header? */
+
+	/* check for unknown data coding scheme */
+	switch(tp_dcs) {
+	case 0:
+		return sms_7bit(msg->data, msg->len, tp_udlen);
+	default:
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+static int sms_tpdu_decode(struct osmocom_ms *ms, struct msgb *msg)
+{
+	uint8_t tp_mti;
+
+	if ( !msg->len )
+		return 0;
+	tp_mti = msgb_get_u8(msg);
+
+	switch(tp_mti & TP_MTI_MASK) {
+	case SMS_DELIVER:
+		return sms_deliver(ms, msg, tp_mti);
+	case SMS_SUBMIT_REPORT:
+		LOGP(DMM, LOGL_NOTICE, "Received SMS-SUBMIT-REPORT: %s\n",
+			hexdump(msg->data, msg->len));
+		break;
+	case SMS_STATUS_REPORT:
+		LOGP(DMM, LOGL_NOTICE, "Received SMS-STATUS-REPORT: %s\n",
+			hexdump(msg->data, msg->len));
+		break;
+	default:
+		LOGP(DMM, LOGL_NOTICE, "Reserved MTI: 0x%.2x\n",
+			tp_mti);
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+static int rp_data_decode(struct osmocom_ms *ms, struct msgb *msg, uint8_t ref)
+{
+	static const char * const str[2] = {"RP-Origination", "RP-Destination"};
+	unsigned int i;
+	uint8_t tpdu_len;
+
+	LOGP(DMM, LOGL_NOTICE, "Received RP-DATA: ref %d\n", ref);
+
+	for(i = 0; i < 2; i++) {
+		int rc;
+
+		rc = parse_address(msg, 1, str[i]);
+		if ( rc )
+			return -EPROTO;
+	}
+
+	if ( !msg->len )
+		return -EPROTO;
+	tpdu_len = msgb_get_u8(msg);
+	if ( tpdu_len < msg->len )
+		return -EPROTO;
+	if ( tpdu_len < msg->len ) {
+		LOGP(DMM, LOGL_NOTICE, "RP-DATA: %u trailing bytes: %s\n",
+			msg->len - tpdu_len,
+			hexdump(msg->data + tpdu_len, msg->len - tpdu_len));
+		msg->len = tpdu_len;
+	}
+
+	/* TODO: pass in reference, and src/dst addresses */
+	return sms_tpdu_decode(ms, msg);
+}
+
+/* TODO: whatever happens here we need to send RP-ACK or RP-ERROR */
+static int rp_decode(struct osmocom_ms *ms, struct msgb *msg)
+{
+	uint8_t rp_mt, rp_ref;
+
+	if ( msg->len < 2  )
+		return -EPROTO;
+
+	rp_mt = msgb_get_u8(msg);
+	rp_ref = msgb_get_u8(msg);
+
+	switch(rp_mt) {
+	case RP_DATA:
+		return rp_data_decode(ms, msg, rp_ref);
+	case RP_ACK:
+		LOGP(DMM, LOGL_NOTICE, "Received RP-ACK: %s\n",
+			hexdump(msg->data, msg->len));
+		return -ENOTSUP;
+	case RP_ERROR:
+		LOGP(DMM, LOGL_NOTICE, "Received RP-ERROR: %s\n",
+			hexdump(msg->data, msg->len));
+		return -ENOTSUP;
+	default:
+		LOGP(DMM, LOGL_NOTICE, "Bad RP Message-type: 0x%.2x\n", rp_mt);
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+static int cp_tx_error(struct osmocom_ms *ms, uint8_t tid, uint8_t cause)
+{
+	struct gsm48_hdr *gh;
+	struct msgb *msg;
+
+	msg = gsm48_l3_msgb_alloc();
+	if ( NULL == msg )
+		return -ENOMEM;
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	gh->proto_discr = tid | GSM48_PDISC_SMS;
+	gh->msg_type = CP_ERROR;
+	msgb_put_u8(msg, cause);
+	return gsm48_rr_downmsg(ms, msg);
+}
+
+static int cp_tx_ack(struct osmocom_ms *ms, uint8_t tid)
+{
+	struct gsm48_hdr *gh;
+	struct msgb *msg;
+
+	msg = gsm48_l3_msgb_alloc();
+	if ( NULL == msg )
+		return -ENOMEM;
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	gh->proto_discr = tid | GSM48_PDISC_SMS;
+	gh->msg_type = CP_ACK;
+	return gsm48_rr_downmsg(ms, msg);
+}
+
+static int cp_data(struct osmocom_ms *ms, uint8_t tid, struct msgb *msg)
+{
+	uint8_t len;
+
+	if ( !msg->len ) {
+		return cp_tx_error(ms, tid, CP_CAUSE_PROTOCOL_ERROR);
+	}
+
+	len = msgb_get_u8(msg);
+	if ( len != msg->len ) {
+		LOGP(DMM, LOGL_NOTICE, "CP-DATA: size mismatch "
+			"%u != %u bytes\n", len, msg->len);
+	}else{
+		LOGP(DMM, LOGL_NOTICE, "CP-DATA: %u bytes\n", len);
+	}
+
+	rp_decode(ms, msg);
+	return cp_tx_ack(ms, tid);
+}
+
+int gsm48_rcv_sms(struct osmocom_ms *ms, struct msgb *msg)
+{
+	uint8_t cp_type, tid;
+	int rc;
+
+	LOGP(DMM, LOGL_NOTICE, "Received SMS: %s\n",
+		hexdump(msg->data, msg->len));
+
+	tid = msgb_get_u8(msg) & 0xf0;
+	if (!msg->len) {
+		rc = cp_tx_error(ms, tid, CP_CAUSE_PROTOCOL_ERROR);
+		goto out;
+	}
+
+	cp_type = msgb_get_u8(msg);
+
+	switch(cp_type) {
+	case CP_DATA:
+		rc = cp_data(ms, tid, msg);
+		break;
+	default:
+		LOGP(DMM, LOGL_NOTICE, "Unknown SMS type: 0x%.2x\n", cp_type);
+		rc = cp_tx_error(ms, tid, CP_CAUSE_MSG_TYPE_NOT_IMPLEMENTED);
+		break;
+	}
+
+out:
+	msgb_free(msg);
+	return rc;
+}






More information about the baseband-devel mailing list