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..54b44c0 100644
--- a/openbsc/include/openbsc/gsm_04_11.h
+++ b/openbsc/include/openbsc/gsm_04_11.h
@@ -3,6 +3,21 @@
/* GSM TS 04.11 definitions */
+/* Chapter 5.2.3: SMC-CS states at the network side */
+enum gsm411_cp_state {
+ GSM411_CPS_IDLE = 0,
+ GSM411_CPS_MM_CONN_PENDING = 1, /* only MT ! */
+ GSM411_CPS_WAIT_CP_ACK = 2,
+ GSM411_CPS_MM_ESTABLISHED = 3,
+};
+
+/* Chapter 6.2.2: SMR states at the network side */
+enum gsm411_rp_state {
+ GSM411_RPS_IDLE = 0,
+ GSM411_RPS_WAIT_FOR_RP_ACK = 1,
+ GSM411_RPS_WAIT_TO_TX_RP_ACK = 3,
+};
+
/* Chapter 8.1.2 (refers to GSM 04.07 Chapter 11.2.3.1.1 */
#define GSM411_PDISC_SMS 0x09
@@ -16,6 +31,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 +58,41 @@
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 10: Timers */
+#define GSM411_TMR_TR1M 40 /* 35 < x < 45 seconds */
+#define GSM411_TMR_TRAM 30 /* 25 < x < 35 seconds */
+#define GSM411_TMR_TR2M 15 /* 12 < x < 20 seconds */
+
/* Chapter 8.2.1 */
struct gsm411_rp_hdr {
u_int8_t len;
@@ -49,20 +112,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;
@@ -141,23 +204,22 @@
#define GSM338_DCS_1111_CLASS2_SIM 2
#define GSM338_DCS_1111_CLASS3_TE 3 /* See TS 07.05 */
-
/* 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 +228,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 e6dffa8..f23c440 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", \
@@ -100,44 +100,6 @@
struct gsm_mncc;
struct rtp_socket;
-/* One transaction */
-struct gsm_trans {
- /* Entry in list of all transactions */
- struct llist_head entry;
-
- /* The protocol within which we live */
- u_int8_t protocol;
-
- /* The current transaction ID */
- u_int8_t transaction_id;
-
- /* To whom we belong, unique identifier of remote MM entity */
- struct gsm_subscriber *subscr;
-
- /* The LCHAN that we're currently using to transmit messages */
- struct gsm_lchan *lchan;
-
- /* reference from MNCC or other application */
- u_int32_t callref;
-
- union {
- struct {
-
- /* current call state */
- int state;
-
- /* current timer and message queue */
- int Tcurrent; /* current CC timer */
- int T308_second; /* used to send release again */
- struct timer_list timer;
- struct gsm_mncc msg; /* stores setup/disconnect/release message */
- } cc;
- struct {
- } sms;
- };
-};
-
-
/* Network Management State */
struct gsm_nm_state {
u_int8_t operational;
@@ -390,6 +352,13 @@
struct gsm_subscriber *sender;
struct gsm_subscriber *receiver;
+ unsigned long validity_minutes;
+ unsigned char reply_path_req;
+ unsigned char status_rep_req;
+ unsigned char protocol_id;
+ unsigned char data_coding_scheme;
+
+ 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/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h
index 1450dbc..ad6fe35 100644
--- a/openbsc/include/openbsc/transaction.h
+++ b/openbsc/include/openbsc/transaction.h
@@ -3,8 +3,55 @@
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
+#include <openbsc/linuxlist.h>
+#include <openbsc/gsm_04_11.h>
-struct gsm_trans *trans_find_by_id(struct gsm_lchan *lchan, u_int8_t trans_id);
+/* One transaction */
+struct gsm_trans {
+ /* Entry in list of all transactions */
+ struct llist_head entry;
+
+ /* The protocol within which we live */
+ u_int8_t protocol;
+
+ /* The current transaction ID */
+ u_int8_t transaction_id;
+
+ /* To whom we belong, unique identifier of remote MM entity */
+ struct gsm_subscriber *subscr;
+
+ /* The LCHAN that we're currently using to transmit messages */
+ struct gsm_lchan *lchan;
+
+ /* reference from MNCC or other application */
+ u_int32_t callref;
+
+ union {
+ struct {
+
+ /* current call state */
+ int state;
+
+ /* current timer and message queue */
+ int Tcurrent; /* current CC timer */
+ int T308_second; /* used to send release again */
+ struct timer_list timer;
+ struct gsm_mncc msg; /* stores setup/disconnect/release message */
+ } cc;
+ struct {
+ int is_mt; /* is this a MO (0) or MT (1) transfer */
+ enum gsm411_cp_state cp_state;
+ enum gsm411_rp_state rp_state;
+
+ struct timer_list timer;
+ } sms;
+ };
+};
+
+
+
+struct gsm_trans *trans_find_by_id(struct gsm_subscriber *subscr,
+ u_int8_t proto, u_int8_t trans_id);
struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
u_int32_t callref);
diff --git a/openbsc/src/db.c b/openbsc/src/db.c
index fc2950a..03b281a 100644
--- a/openbsc/src/db.c
+++ b/openbsc/src/db.c
@@ -77,9 +77,14 @@
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"created TIMESTAMP NOT NULL, "
"sent TIMESTAMP, "
+ "valid_until TIMESTAMP, "
+ "reply_path_req NUMERIC NOT NULL, "
+ "status_rep_req NUMERIC NOT NULL, "
+ "protocol_id NUMERIC NOT NULL, "
+ "data_coding_scheme NUMERIC NOT NULL, "
"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 +240,13 @@
);
free(quoted);
break;
+ case GSM_SUBSCRIBER_ID:
+ dbi_conn_quote_string_copy(conn, id, "ed);
+ 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 +458,25 @@
{
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);
+ /* FIXME: correct validity period */
result = dbi_conn_queryf(conn,
"INSERT INTO SMS "
- "(created,sender_id,receiver_id,header,text) VALUES "
- "(datetime('now'),%llu,%llu,%s,%s)",
+ "(created,sender_id,receiver_id,header,text,"
+ "valid_until,reply_path_req,status_rep_req,"
+ "protocol_id,data_coding_scheme) VALUES "
+ "(datetime('now'),%llu,%llu,%s,%s,%s,%u,%u,%u,%u)",
sms->sender->id,
sms->receiver ? sms->receiver->id : 0,
- NULL, q_text);
+ q_header, q_text, '2222-2-2', sms->reply_path_req,
+ sms->status_rep_req, sms->protocol_id,
+ sms->data_coding_scheme);
free(q_text);
+ free(q_header);
if (!result)
return -EIO;
@@ -468,7 +489,11 @@
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));
+ const char *text;
+ const unsigned char *header;
+ char buf[32];
if (!sms) {
free(sms);
@@ -482,8 +507,30 @@
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: validity */
+ sms->reply_path_req = dbi_result_get_uchar(result, "reply_path_req");
+ sms->status_rep_req = dbi_result_get_uchar(result, "status_rep_req");
+ sms->protocol_id = dbi_result_get_uchar(result, "protocol_id");
+ sms->data_coding_scheme = dbi_result_get_uchar(result,
+ "data_coding_scheme");
+
+ sms->header_len = dbi_result_get_field_length(result, "header");
+ header = dbi_result_get_binary(result, "header");
+ memcpy(sms->header, header, sms->header_len);
+
+ 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 2d3a634..690c591 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -245,7 +245,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;
@@ -3620,7 +3620,7 @@
}
/* Find transaction */
- trans = trans_find_by_id(lchan, transaction_id);
+ trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id);
DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
"Received '%s' from MS in state %d (%s)\n",
diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c
index 9218783..5ce25f3 100644
--- a/openbsc/src/gsm_04_11.c
+++ b/openbsc/src/gsm_04_11.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <time.h>
#include <netinet/in.h>
#include <openbsc/msgb.h>
@@ -42,6 +43,7 @@
#include <openbsc/signal.h>
#include <openbsc/db.h>
#include <openbsc/talloc.h>
+#include <openbsc/transaction.h>
#define GSM411_ALLOC_SIZE 1024
#define GSM411_ALLOC_HEADROOM 128
@@ -49,13 +51,15 @@
static void *tall_sms_ctx;
static void *tall_gsms_ctx;
+static u_int32_t new_callref = 0x40000001;
+
struct msgb *gsm411_msgb_alloc(void)
{
return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
"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 +69,45 @@
return rsl_data_request(msg, 0);
}
+/* Prefix msg with a 04.08/04.11 CP header */
+static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
+ u_int8_t msg_type)
+{
+ struct gsm48_hdr *gh;
+
+ gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
+ /* Outgoing needs the highest bit set */
+ gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
+ gh->msg_type = msg_type;
+
+ /* assign the outgoing lchan */
+ msg->lchan = trans->lchan;
+
+ /* mobile originating */
+ switch (gh->msg_type) {
+ case GSM411_MT_CP_DATA:
+ /* 5.2.3.1.2: enter MO-wait for CP-ack */
+ trans->sms.cp_state = GSM411_CPS_WAIT_CP_ACK;
+ break;
+ }
+
+ return gsm411_sendmsg(msg);
+}
+
+/* Prefix msg with a RP-DATA header and send as CP-DATA */
+static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
+ u_int8_t rp_msg_type, u_int8_t rp_msg_ref)
+{
+ 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, trans, GSM411_MT_CP_DATA);
+}
#if 0
static u_int8_t gsm0411_tpdu_from_sms(u_int8_t *tpdu, struct sms_deliver *sms)
@@ -144,14 +187,95 @@
{
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) */
+static int gsm340_gen_oa(u_int8_t *oa, struct gsm_subscriber *subscr)
+{
+ int len = 0;
+
+}
+
+static u_int8_t bcdify(u_int8_t value)
+{
+ u_int8_t ret;
+
+ ret = value % 10;
+ ret |= (value / 10) << 4;
+
+ return ret;
+}
+
+/* Generate 03.40 TP-SCTS */
+static void gsm340_gen_scts(u_int8_t *scts, time_t time)
+{
+ struct tm *tm = localtime(&time);
+ u_int8_t digit;
+
+ *scts++ = bcdify(tm->tm_year % 100);
+ *scts++ = bcdify(tm->tm_mon);
+ *scts++ = bcdify(tm->tm_mday);
+ *scts++ = bcdify(tm->tm_hour);
+ *scts++ = bcdify(tm->tm_min);
+ *scts++ = bcdify(tm->tm_sec);
+ *scts++ = 0; /* FIXME: timezone */
+}
+
+static struct msgb *gsm340_gen_tpdu(struct gsm_sms *sms)
+{
+ struct msgb *msg = gsm411_msgb_alloc();
+ u_int8_t *smsp;
+ u_int8_t oa[12]; /* max len per 03.40 */
+ u_int8_t oa_len = 0;
+
+ /* generate first octet with masked bits */
+ smsp = msgb_put(msg, 1);
+ *smsp = GSM340_SMS_DELIVER_SC2MS;
+ if (0 /* FIXME: MMS */)
+ *smsp |= 0x04;
+ /* two bits empty */
+ if (sms->status_rep_req)
+ *smsp |= 0x20;
+#if 0
+ if (sms->header_len)
+ *smsp |= 0x40;
+ if (sms->
+ *smsp |= 0x80;
+#endif
+
+ /* generate originator address */
+ smsp = msgb_put(msg, oa_len);
+ oa_len = gsm340_gen_oa(&oa, sms->sender);
+ memcpy(smsp, oa, oa_len);
+
+ /* generate TP-PID */
+ smsp = msgb_put(msg, 1);
+ *smsp = sms->protocol_id;
+
+ /* generate TP-DCS */
+ smsp = msgb_put(msg, 1);
+ *smsp = sms->data_coding_scheme;
+
+ /* generate TP-SCTS */
+ smsp = msgb_put(msg, 7);
+ gsm340_gen_scts(smsp, time(NULL));
+#if 0
+ /* generate TP-UDL */
+ smsp = msgb_put(msg, 1);
+ *smsp = ud_len;
+
+ /* generate TP-UD */
+ smsp = msgb_put(msg, ud_len);
+ memcpy(smsp, FIXME, ud_len);
+#endif
+
+ return msg;
+}
+
+/* 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;
@@ -164,13 +288,13 @@
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));
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));
@@ -178,9 +302,9 @@
sms->mti = *smsp & 0x03;
sms->mms = !!(*smsp & 0x04);
sms->vpf = (*smsp & 0x18) >> 3;
- sms->sri = !!(*smsp & 0x20);
- sms->udhi= !!(*smsp & 0x40);
- sms->rp = !!(*smsp & 0x80);
+ sms->srr = (*smsp & 0x20);
+ sms->udhi= (*smsp & 0x40);
+ sms->rp = (*smsp & 0x80);
smsp++;
sms->msg_ref = *smsp++;
@@ -189,7 +313,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));
@@ -242,13 +366,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) {
@@ -256,7 +386,12 @@
goto out;
}
- if (sms->user_data)
+ if (sms->user_data) {
+ gsms->header_len = sms->ud_len;
+ memcpy(gsms->header, sms->user_data, sms->ud_len);
+ }
+
+ if (sms->decoded)
strncpy(gsms->text, sms->decoded, sizeof(gsms->text));
switch (sms->mti) {
@@ -267,12 +402,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);
@@ -280,62 +420,35 @@
return rc;
}
-static int gsm411_send_rp_ack(struct gsm_lchan *lchan, u_int8_t trans_id,
- u_int8_t msg_ref)
+static int gsm411_send_rp_ack(struct gsm_trans *trans, 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, trans, GSM411_MT_RP_ACK_MT, msg_ref);
}
-static int gsm411_send_rp_error(struct gsm_lchan *lchan, u_int8_t trans_id,
- u_int8_t msg_ref, u_int8_t cause)
+static int gsm411_send_rp_error(struct gsm_trans *trans,
+ 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, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
}
/* Receive a 04.11 TPDU inside RP-DATA / user data */
-static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm411_rp_hdr *rph,
+static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
+ struct gsm411_rp_hdr *rph,
u_int8_t src_len, u_int8_t *src,
u_int8_t dst_len, u_int8_t *dst,
u_int8_t tpdu_len, u_int8_t *tpdu)
{
struct gsm48_hdr *gh = msgb_l3(msg);
- u_int8_t trans_id = gh->proto_discr >> 4;
int rc = 0;
if (src_len && src)
@@ -343,24 +456,26 @@
if (!dst_len || !dst || !tpdu_len || !tpdu) {
DEBUGP(DSMS, "RP-DATA (MO) without DST or TPDU ?!?\n");
+ gsm411_send_rp_error(trans, 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)
- return gsm411_send_rp_ack(msg->lchan, trans_id, rph->msg_ref);
+ return gsm411_send_rp_ack(trans, rph->msg_ref);
else if (rc > 0)
- return gsm411_send_rp_error(msg->lchan, trans_id, rph->msg_ref, rc);
+ return gsm411_send_rp_error(trans, rph->msg_ref, rc);
else
return rc;
}
/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
-static int gsm411_rx_rp_data(struct msgb *msg, struct gsm411_rp_hdr *rph)
+static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
+ struct gsm411_rp_hdr *rph)
{
u_int8_t src_len, dst_len, rpud_len;
u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
@@ -378,12 +493,60 @@
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);
- return gsm411_rx_rp_ud(msg, rph, src_len, src, dst_len, dst,
+ 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, trans, rph, src_len, src, dst_len, dst,
rpud_len, rp_ud);
}
-static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh)
+
+static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
+ 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 gsm_trans *trans,
+ struct gsm411_rp_hdr *rph)
+{
+ u_int8_t cause_len = rph->data[0];
+ u_int8_t cause = rph->data[1];
+
+ /* 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 */
+
+ DEBUGP(DSMS, "RX SMS RP-ERROR Cause=0x%02x\n", cause);
+
+ /* we need to look-up the transaction based on rph->msg_ref to
+ * identify which particular RP_DATA/SMS-submit failed */
+
+ return 0;
+}
+
+static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans,
+ struct gsm411_rp_hdr *rph)
+{
+ int rc;
+
+ /* 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_send_rp_ack(trans, rph->msg_ref);
+ trans->sms.rp_state = GSM411_RPS_IDLE;
+
+ return rc;
+}
+
+static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
+ struct gsm_trans *trans)
{
struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
u_int8_t msg_type = rp_data->msg_type & 0x07;
@@ -391,50 +554,129 @@
switch (msg_type) {
case GSM411_MT_RP_DATA_MO:
- DEBUGP(DSMS, "SMS RP-DATA (MO)\n");
- rc = gsm411_rx_rp_data(msg, rp_data);
+ DEBUGP(DSMS, "RX SMS RP-DATA (MO)\n");
+ /* start TR2N and enter 'wait to send RP-ACK state' */
+ trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
+ rc = gsm411_rx_rp_data(msg, trans, rp_data);
break;
case GSM411_MT_RP_ACK_MO:
- /* Acnkowledgement to MT RP_DATA */
- case GSM411_MT_RP_ERROR_MO:
- /* Error in response to MT RP_DATA */
+ DEBUGP(DSMS,"RX SMS RP-ACK (MO)\n");
+ rc = gsm411_rx_rp_ack(msg, trans, 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 */
- DEBUGP(DSMS, "Unimplemented RP type 0x%02x\n", msg_type);
+ DEBUGP(DSMS, "RX SMS RP-SMMA\n");
+ /* start TR2N and enter 'wait to send RP-ACK state' */
+ trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
+ rc = gsm411_rx_rp_smma(msg, trans, rp_data);
+ break;
+ case GSM411_MT_RP_ERROR_MO:
+ rc = gsm411_rx_rp_error(msg, trans, rp_data);
break;
default:
DEBUGP(DSMS, "Invalid RP type 0x%02x\n", msg_type);
+ rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
+ GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
break;
}
return rc;
}
+/* send CP-ACK to given transaction */
+static int gsm411_tx_cp_ack(struct gsm_trans *trans)
+{
+ struct msgb *msg = gsm411_msgb_alloc();
+
+ return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ACK);
+}
+
+static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
+{
+ struct msgb *msg = gsm411_msgb_alloc();
+ u_int8_t *causep;
+
+ cause = msgb_put(msg, 1);
+ *causep = cause;
+
+ return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ERROR);
+}
+
+/* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */
int gsm0411_rcv_sms(struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
u_int8_t msg_type = gh->msg_type;
+ u_int8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
+ struct gsm_lchan *lchan = msg->lchan;
+ struct gsm_trans *trans;
int rc = 0;
+ if (!lchan->subscr)
+ return -EIO;
+ /* FIXME: send some error message */
+
+ trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS,
+ transaction_id);
+ if (!trans) {
+ DEBUGP(DSMS, "Unknown transaction ID %x, "
+ "creating new trans\n", transaction_id);
+ trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
+ transaction_id, new_callref++);
+ if (!trans) {
+ DEBUGP(DSMS, "No memory for trans\n");
+ /* FIXME: send some error message */
+ return -ENOMEM;
+ }
+ trans->sms.cp_state = GSM411_CPS_IDLE;
+ trans->sms.rp_state = GSM411_RPS_IDLE;
+ trans->sms.is_mt = 0;
+
+ trans->lchan = lchan;
+ use_lchan(lchan);
+ }
+
switch(msg_type) {
case GSM411_MT_CP_DATA:
- DEBUGP(DSMS, "SMS CP-DATA\n");
- rc = gsm411_rx_cp_data(msg, gh);
+ DEBUGP(DSMS, "RX SMS CP-DATA\n");
+ if (!trans->sms.is_mt) {
+ /* 5.2.3.1.3: MO state exists when SMC has received
+ * CP-DATA, including sending of the assoc. CP-ACK */
+ trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
+ }
+
+ rc = gsm411_rx_cp_data(msg, gh, trans);
+ /* Send CP-ACK or CP-ERORR in response */
+ if (rc < 0) {
+ rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_NET_FAIL);
+ } else
+ rc = gsm411_tx_cp_ack(trans);
break;
case GSM411_MT_CP_ACK:
- DEBUGP(DSMS, "SMS CP-ACK\n");
+ /* previous CP-DATA in this transaction was confirmed */
+ DEBUGP(DSMS, "RX SMS CP-ACK\n");
+ if (!trans->sms.is_mt) {
+ /* 5.2.3.1.3: MO state exists when SMC has received
+ * CP-ACK */
+ trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
+ /* FIXME: we have sont one CP-DATA, which was now
+ * acknowledged. Check if we want to transfer more,
+ * i.e. multi-part message */
+ trans->sms.cp_state = GSM411_CPS_IDLE;
+ trans_free(trans);
+ }
break;
case GSM411_MT_CP_ERROR:
- DEBUGP(DSMS, "SMS CP-ERROR, cause 0x%02x\n", gh->data[0]);
+ DEBUGP(DSMS, "RX SMS CP-ERROR, cause 0x%02x\n", gh->data[0]);
+ trans->sms.cp_state = GSM411_CPS_IDLE;
+ trans_free(trans);
break;
default:
- DEBUGP(DSMS, "Unimplemented CP msg_type: 0x%02x\n", msg_type);
+ DEBUGP(DSMS, "RX Unimplemented CP msg_type: 0x%02x\n", msg_type);
+ rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
+ trans_free(trans);
break;
}
-
return rc;
}
@@ -462,32 +704,29 @@
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;
+ struct gsm_trans *trans;
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;
+ /* FIXME: allocate trans */
- 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);
@@ -503,9 +742,29 @@
DEBUGP(DSMS, "TX: SMS SUBMIT\n");
- return gsm0411_sendmsg(msg);
+ return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
+ /* FIXME: enter 'wait for RP-ACK' state, start TR1N */
}
+
+#if 0
+{
+ struct sms_deliver *smsd;
+
+ smsd->mti = GSM340_SMS_DELIVER_SC2MS;
+ smsd->mms = 0; /* FIXME: determine if there are more */
+ smsd->rp = FIXME;
+ smsd->udhi = FIXME;
+ smsd->sri = 1;
+ smsd->oa = FIXME;
+ smsd->pid = FIXME;
+ smsd->dcs = FIXME;
+ smsd->scts = FIXME;
+ smsd->ud_len = FIXME;
+ smsd->ud = FIXME;
+}
+#endif
+
static __attribute__((constructor)) void on_dso_load_sms(void)
{
tall_sms_ctx = talloc_named_const(tall_bsc_ctx, 1, "sms_submit");
diff --git a/openbsc/src/gsm_subscriber.c b/openbsc/src/gsm_subscriber.c
index 7480156..0bcbdf4 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",
diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c
index f4cef28..9e7c794 100644
--- a/openbsc/src/transaction.c
+++ b/openbsc/src/transaction.c
@@ -31,13 +31,16 @@
static void *tall_trans_ctx;
-struct gsm_trans *trans_find_by_id(struct gsm_lchan *lchan, u_int8_t trans_id)
+struct gsm_trans *trans_find_by_id(struct gsm_subscriber *subscr,
+ u_int8_t proto, u_int8_t trans_id)
{
struct gsm_trans *trans;
- struct gsm_network *net = lchan->ts->trx->bts->network;
+ struct gsm_network *net = subscr->net;
llist_for_each_entry(trans, &net->trans_list, entry) {
- if (trans->lchan == lchan && trans->transaction_id == trans_id)
+ if (trans->subscr == subscr &&
+ trans->protocol == proto &&
+ trans->transaction_id == trans_id)
return trans;
}
return NULL;