aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gsm_04_11.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2009-08-09 14:59:02 +0200
committerHarald Welte <laforge@gnumonks.org>2009-08-09 14:59:02 +0200
commitcb8f4433994f8386fcf805c73e34f975f344a9a2 (patch)
treee036c3c05e8bba8e854a6e8c58afc3d86c660c03 /openbsc/src/gsm_04_11.c
parentce2eb871e189682da4616711fc7cf50c397ca9aa (diff)
implement proper SAPI3 handling for SMS
SM's need to be transferred over their own RLL connection on SAPI3, rather than the default SAPI0 connection that we're using for signalling like 04.08 RR/MM/CC. This is not that much of a problem in the case of SMS SUBMIT from the MS to the netwrok. In that case, the MS will start its primary RLL connection with SAPI3, and we can just respond with SAPI3. However, in the case of SMS DELIVER to a MS, we first page the MS, it then establishes SAPI0. We then need to explicitly request the establishment of a SAPI3 RLL connection, before we can send CP-DATA with our RP-DATA and DELIVER RPDU Now that we have the bsc_rll.c code, we can actually wait for a paging response, and from the paging response request the establishment of the SAPI3 connection. We will be called back once that connection is open and can successively start transmission of the SM.
Diffstat (limited to 'openbsc/src/gsm_04_11.c')
-rw-r--r--openbsc/src/gsm_04_11.c85
1 files changed, 63 insertions, 22 deletions
diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c
index 20555101a..4ab06ecb9 100644
--- a/openbsc/src/gsm_04_11.c
+++ b/openbsc/src/gsm_04_11.c
@@ -45,10 +45,13 @@
#include <openbsc/talloc.h>
#include <openbsc/transaction.h>
#include <openbsc/paging.h>
+#include <openbsc/bsc_rll.h>
#define GSM411_ALLOC_SIZE 1024
#define GSM411_ALLOC_HEADROOM 128
+#define UM_SAPI_SMS 3 /* See GSM 04.05/04.06 */
+
static void *tall_gsms_ctx;
static u_int32_t new_callref = 0x40000001;
@@ -84,7 +87,7 @@ static int gsm411_sendmsg(struct msgb *msg)
DEBUGP(DSMS, "GSM4.11 TX %s\n", hexdump(msg->data, msg->len));
- return rsl_data_request(msg, 0);
+ return rsl_data_request(msg, UM_SAPI_SMS);
}
/* Prefix msg with a 04.08/04.11 CP header */
@@ -105,6 +108,7 @@ static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
switch (gh->msg_type) {
case GSM411_MT_CP_DATA:
/* 5.2.3.1.2: enter MO-wait for CP-ack */
+ /* 5.2.3.2.3: enter MT-wait for CP-ACK */
trans->sms.cp_state = GSM411_CPS_WAIT_CP_ACK;
break;
}
@@ -502,6 +506,7 @@ static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
rpud_len, rp_ud);
}
+/* Receive a 04.11 RP-ACK message (response to RP-DATA from us) */
static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
struct gsm411_rp_hdr *rph)
{
@@ -511,13 +516,16 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
* 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 */
+ if (!trans->sms.is_mt) {
+ DEBUGP(DSMS, "RX RP-ACK on a MO transfer ?\n");
+ return gsm411_send_rp_error(trans, rph->msg_ref,
+ GSM411_RP_CAUSE_MSG_INCOMP_STATE);
+ }
if (!sms) {
- DEBUGP(DSMS, "RX RP-ACK (MT) but no sms in transaction?!?\n");
- put_lchan(trans->lchan);
- return -EIO;
+ DEBUGP(DSMS, "RX RP-ACK but no sms in transaction?!?\n");
+ return gsm411_send_rp_error(trans, rph->msg_ref,
+ GSM411_RP_CAUSE_PROTOCOL_ERR);
}
/* mark this SMS as sent in database */
@@ -528,7 +536,7 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
sms_free(sms);
trans->sms.sms = NULL;
- put_lchan(trans->lchan);
+ trans_free(trans);
return 0;
}
@@ -546,19 +554,29 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
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 */
+ if (!trans->sms.is_mt) {
+ DEBUGP(DSMS, "RX RP-ERR on a MO transfer ?\n");
+ return gsm411_send_rp_error(trans, rph->msg_ref,
+ GSM411_RP_CAUSE_MSG_INCOMP_STATE);
+ }
if (!sms) {
- DEBUGP(DSMS, "RX RP-ERR (MT) but no sms in transaction?!?\n");
- put_lchan(trans->lchan);
- return -EIO;
+ DEBUGP(DSMS, "RX RP-ERR, but no sms in transaction?!?\n");
+ return gsm411_send_rp_error(trans, rph->msg_ref,
+ GSM411_RP_CAUSE_PROTOCOL_ERR);
+ }
+
+ if (cause == GSM411_RP_CAUSE_MT_MEM_EXCEEDED) {
+ /* MS has not enough memory to store the message. We need
+ * to store this in our database and wati for a SMMA message */
+ /* FIXME */
+ dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr);
}
sms_free(sms);
trans->sms.sms = NULL;
- put_lchan(trans->lchan);
+ trans_free(trans);
return 0;
}
@@ -672,11 +690,11 @@ int gsm0411_rcv_sms(struct msgb *msg)
switch(msg_type) {
case GSM411_MT_CP_DATA:
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;
- }
+ /* 5.2.3.1.3: MO state exists when SMC has received
+ * CP-DATA, including sending of the assoc. CP-ACK */
+ /* 5.2.3.2.4: MT 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 */
@@ -688,10 +706,11 @@ int gsm0411_rcv_sms(struct msgb *msg)
case GSM411_MT_CP_ACK:
/* previous CP-DATA in this transaction was confirmed */
DEBUGP(DSMS, "RX SMS CP-ACK\n");
+ /* 5.2.3.1.3: MO state exists when SMC has received CP-ACK */
+ /* 5.2.3.2.4: MT state exists when SMC has received CP-ACK */
+ trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
+
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 */
@@ -707,6 +726,7 @@ int gsm0411_rcv_sms(struct msgb *msg)
default:
DEBUGP(DSMS, "RX Unimplemented CP msg_type: 0x%02x\n", msg_type);
rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
+ trans->sms.cp_state = GSM411_CPS_IDLE;
trans_free(trans);
break;
}
@@ -793,6 +813,27 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
/* FIXME: enter 'wait for RP-ACK' state, start TR1N */
}
+/* RLL SAPI3 establish callback */
+static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
+ void *_sms, enum bsc_rllr_ind type)
+{
+ struct gsm_sms *sms = _sms;
+
+ DEBUGP(DSMS, "rll_ind_cb(lchan=%p, link_id=%u, sms=%p, type=%u\n",
+ lchan, link_id, sms, type);
+
+ switch (type) {
+ case BSC_RLLR_IND_EST_CONF:
+ gsm411_send_sms_lchan(lchan, sms);
+ break;
+ case BSC_RLLR_IND_REL_IND:
+ case BSC_RLLR_IND_ERR_IND:
+ case BSC_RLLR_IND_TIMEOUT:
+ sms_free(sms);
+ break;
+ }
+}
+
/* paging callback */
static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
struct msgb *msg, void *_lchan, void *_sms)
@@ -815,7 +856,7 @@ static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
rc = -EIO;
break;
}
- rc = gsm411_send_sms_lchan(lchan, sms);
+ rc = rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
break;
case GSM_PAGING_EXPIRED:
sms_free(sms);