Hi,
Attached patch implements SMS decoding. Right now it just logs it all to DMM (when I tried DSMS I didn't get any output?!). What remains is to plumb this through to mobile so that the messages can be displayed over a vty and also to send a response other than GSM48_REJECT_MSG_TYPE_NOT_IMPLEMENTED - but I'm not sure what needs to happen here.
Is anyone else working in this area?
Gianni
commit a244cccb6f7600cb867e4949926cc7d877b58f31 Author: Gianni Tedesco gianni@scaramanga.co.uk Date: Thu May 12 03:24:19 2011 +0100
Implement SMS decoding
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..84069f3 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 */ @@ -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);
- case GSM48_PDISC_SMS: - return gsm48_rcv_sms(ms, msg); #endif + case GSM48_PDISC_SMS: + LOGP(DMM, LOGL_NOTICE, "SMS PDISC = 0x%.2x\n", GSM48_PDISC_SMS); + gsm48_rcv_sms(ms, msg);
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..63b1965 --- /dev/null +++ b/src/host/layer23/src/mobile/gsm48_sms.c @@ -0,0 +1,306 @@ +/* + * (C) 2010 by Andreas Eversberg jolly@eversberg.eu + * (C) 2011 by Gianni Tedesco gianni@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> + +#define CP_DATA 1 + +#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 void decode_7bit(const uint8_t *inp, size_t octets, size_t len) +{ + uint8_t out[len + 1]; + unsigned int i; + + for(i = 0; i <= len; i++) { + int ipos = i - (i >> 3); + int offset = (i & 0x7); + + out[i] = (inp[ipos] & (0x7F >> offset)) << offset; + if( 0 == offset ) + continue; + + out[i] |= (inp[ipos - 1] & + (0x7F << (8 - offset)) & 0xFF) >> (8 - offset); + } + + out[len] = '\0'; + LOGP(DMM, LOGL_NOTICE, "SMS: "%s"\n", out); +} + +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_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); + + /* check for unknown data coding scheme */ + if (tp_dcs) + return 0; + + decode_7bit(msg->data, msg->len, tp_udlen); + 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); +} + +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_data(struct osmocom_ms *ms, struct msgb *msg) +{ + uint8_t len; + + if ( !msg->len ) + return -EPROTO; + 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); + } + + return rp_decode(ms, msg); +} + +int gsm48_rcv_sms(struct osmocom_ms *ms, struct msgb *msg) +{ + uint8_t cp_type; + + LOGP(DMM, LOGL_NOTICE, "Received SMS: %s\n", + hexdump(msg->data, msg->len)); + + if ( msg->len < 2) + return -EPROTO; + + msgb_pull(msg, 1); /* protocol discriminator */ + cp_type = msgb_get_u8(msg); + + switch(cp_type) { + case CP_DATA: + return cp_data(ms, msg); + default: + LOGP(DMM, LOGL_NOTICE, "Unknown SMS type: 0x%.2x\n", cp_type); + return 0; + } + + return 0; +}
Hi Gianni,
On Thu, May 12, 2011 at 03:27:15AM +0100, Gianni Tedesco wrote:
Attached patch implements SMS decoding.
are you aware that we already have 7bit decoding routines in libosmogsm, as well as other SMS parsing code in OpenBSC? I would prefer if we have one implementation that is in the shared library and re-used by all the various Osmocom projects.
Maybe the existing routines are not suitable right-away, then they should be adapted. But two implementations for the same task doesn't sound like a good solution to me.
Thanks!
On Thu, 2011-05-12 at 08:48 +0200, Harald Welte wrote:
Hi Gianni,
On Thu, May 12, 2011 at 03:27:15AM +0100, Gianni Tedesco wrote:
Attached patch implements SMS decoding.
are you aware that we already have 7bit decoding routines in libosmogsm, as well as other SMS parsing code in OpenBSC? I would prefer if we have one implementation that is in the shared library and re-used by all the various Osmocom projects.
Maybe the existing routines are not suitable right-away, then they should be adapted. But two implementations for the same task doesn't sound like a good solution to me.
No, I wasn't aware of that, I'll check it out.
I am planning to progress this work by sending back the CP-ACK, adding an API so that the SMS can be "delivered" via a function pointer somwhere and provide another API to send the RP-ACK + SMS-DELIVER-REPORT. I think that should complete it? But I'm only just getting familiar with the specs.
Will re-submit when I make the relevant changes.
Thanks for the feedback
Gianni
On Thu, 2011-05-12 at 08:48 +0200, Harald Welte wrote:
Hi Gianni,
On Thu, May 12, 2011 at 03:27:15AM +0100, Gianni Tedesco wrote:
Attached patch implements SMS decoding.
are you aware that we already have 7bit decoding routines in libosmogsm, as well as other SMS parsing code in OpenBSC? I would prefer if we have one implementation that is in the shared library and re-used by all the various Osmocom projects.
The 7bit decoding routines are useful as is, I'll go ahead and use them.
However, the SMS decode in OpenBSC (gsm_04_11.c) is very nice but its decoding everything we want to transmit and constructing everything we want to decode! Not sure how to share that? Maybe some strings, structs and numbers, unless it was an off the cuff suggestion or I am missing something?
Maybe the existing routines are not suitable right-away, then they should be adapted. But two implementations for the same task doesn't sound like a good solution to me.
If you can propose a way to move us there incrementally (for the CP/RP/SMS-DELIVER etc.), I'm all ears. I've only just dipped my toe in the pool here don't forget :)
Gianni
baseband-devel@lists.osmocom.org