This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/baseband-devel@lists.osmocom.org/.
Gianni Tedesco gianni at scaramanga.co.ukThis 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; +}