aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gsm_04_11.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/gsm_04_11.c')
-rw-r--r--openbsc/src/gsm_04_11.c373
1 files changed, 243 insertions, 130 deletions
diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c
index 75ddf9dd9..7f570b8e5 100644
--- a/openbsc/src/gsm_04_11.c
+++ b/openbsc/src/gsm_04_11.c
@@ -173,7 +173,7 @@ static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
DEBUGP(DSMS, "TX: CP-ACK ");
break;
case GSM411_MT_CP_ERROR:
- DEBUGP(DSMS, "TX: CP-ACK ");
+ DEBUGP(DSMS, "TX: CP-ERROR ");
break;
}
@@ -198,48 +198,174 @@ static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA);
}
-static time_t gsm340_scts(u_int8_t *scts);
+/* Turn int into semi-octet representation: 98 => 0x89 */
+static u_int8_t bcdify(u_int8_t value)
+{
+ u_int8_t ret;
-static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp)
+ ret = value / 10;
+ ret |= (value % 10) << 4;
+
+ return ret;
+}
+
+/* Turn semi-octet representation into int: 0x89 => 98 */
+static u_int8_t unbcdify(u_int8_t value)
+{
+ u_int8_t ret;
+
+ if ((value & 0x0F) > 9 || (value >> 4) > 9)
+ LOGP(DSMS, LOGL_ERROR,
+ "unbcdify got too big nibble: 0x%02X\n", value);
+
+ ret = (value&0x0F)*10;
+ ret += value>>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);
+
+ *scts++ = bcdify(tm->tm_year % 100);
+ *scts++ = bcdify(tm->tm_mon + 1);
+ *scts++ = bcdify(tm->tm_mday);
+ *scts++ = bcdify(tm->tm_hour);
+ *scts++ = bcdify(tm->tm_min);
+ *scts++ = bcdify(tm->tm_sec);
+ *scts++ = bcdify(tm->tm_gmtoff/(60*15));
+}
+
+/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */
+static time_t gsm340_scts(u_int8_t *scts)
+{
+ struct tm tm;
+
+ u_int8_t yr = unbcdify(*scts++);
+
+ if (yr <= 80)
+ tm.tm_year = 100 + yr;
+ else
+ tm.tm_year = yr;
+ tm.tm_mon = unbcdify(*scts++) - 1;
+ tm.tm_mday = unbcdify(*scts++);
+ tm.tm_hour = unbcdify(*scts++);
+ tm.tm_min = unbcdify(*scts++);
+ tm.tm_sec = unbcdify(*scts++);
+ /* according to gsm 03.40 time zone is
+ "expressed in quarters of an hour" */
+ tm.tm_gmtoff = unbcdify(*scts++) * 15*60;
+
+ return mktime(&tm);
+}
+
+/* Return the default validity period in minutes */
+static unsigned long gsm340_vp_default(void)
+{
+ unsigned long minutes;
+ /* Default validity: two days */
+ minutes = 24 * 60 * 2;
+ return minutes;
+}
+
+/* Decode validity period format 'relative' */
+static unsigned long gsm340_vp_relative(u_int8_t *sms_vp)
+{
+ /* Chapter 9.2.3.12.1 */
u_int8_t vp;
unsigned long minutes;
- time_t expires;
- time_t now;
+
+ vp = *(sms_vp);
+ if (vp <= 143)
+ minutes = vp + 1 * 5;
+ else if (vp <= 167)
+ minutes = 12*60 + (vp-143) * 30;
+ else if (vp <= 196)
+ minutes = vp-166 * 60 * 24;
+ else
+ minutes = vp-192 * 60 * 24 * 7;
+ return minutes;
+}
+
+/* Decode validity period format 'absolute' */
+static unsigned long gsm340_vp_absolute(u_int8_t *sms_vp)
+{
+ /* Chapter 9.2.3.12.2 */
+ time_t expires, now;
+ unsigned long minutes;
+
+ expires = gsm340_scts(sms_vp);
+ now = mktime(gmtime(NULL));
+ if (expires <= now)
+ minutes = 0;
+ else
+ minutes = (expires-now)/60;
+ return minutes;
+}
+
+/* Decode validity period format 'relative in integer representation' */
+static unsigned long gsm340_vp_relative_integer(u_int8_t *sms_vp)
+{
+ u_int8_t vp;
+ unsigned long minutes;
+ vp = *(sms_vp);
+ if (vp == 0) {
+ LOGP(DSMS, LOGL_ERROR,
+ "reserved relative_integer validity period\n");
+ return gsm340_vp_default();
+ }
+ minutes = vp/60;
+ return minutes;
+}
+
+/* Decode validity period format 'relative in semi-octet representation' */
+static unsigned long gsm340_vp_relative_semioctet(u_int8_t *sms_vp)
+{
+ unsigned long minutes;
+ minutes = unbcdify(*sms_vp++)*60; /* hours */
+ minutes += unbcdify(*sms_vp++); /* minutes */
+ minutes += unbcdify(*sms_vp++)/60; /* seconds */
+ return minutes;
+}
+
+/* decode validity period. return minutes */
+static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp)
+{
+ u_int8_t fi; /* functionality indicator */
switch (sms_vpf) {
case GSM340_TP_VPF_RELATIVE:
- /* Chapter 9.2.3.12.1 */
- vp = *(sms_vp);
- if (vp <= 143)
- minutes = vp + 1 * 5;
- else if (vp <= 167)
- minutes = 12*60 + (vp-143) * 30;
- else if (vp <= 196)
- minutes = vp-166 * 60 * 24;
- else
- minutes = vp-192 * 60 * 24 * 7;
- break;
+ return gsm340_vp_relative(sms_vp);
case GSM340_TP_VPF_ABSOLUTE:
- /* Chapter 9.2.3.12.2 */
- expires = gsm340_scts(sms_vp);
- now = mktime(gmtime(NULL));
- if (expires <= now)
- minutes = 0;
- else
- minutes = (expires-now)/60;
- break;
+ return gsm340_vp_absolute(sms_vp);
case GSM340_TP_VPF_ENHANCED:
/* Chapter 9.2.3.12.3 */
- /* FIXME: implementation */
- DEBUGP(DSMS, "VPI enhanced not implemented yet\n");
- break;
+ fi = *sms_vp++;
+ /* ignore additional fi */
+ if (fi & (1<<7)) sms_vp++;
+ /* read validity period format */
+ switch (fi & 0b111) {
+ case 0b000:
+ return gsm340_vp_default(); /* no vpf specified */
+ case 0b001:
+ return gsm340_vp_relative(sms_vp);
+ case 0b010:
+ return gsm340_vp_relative_integer(sms_vp);
+ case 0b011:
+ return gsm340_vp_relative_semioctet(sms_vp);
+ default:
+ /* The GSM spec says that the SC should reject any
+ unsupported and/or undefined values. FIXME */
+ LOGP(DSMS, LOGL_ERROR,
+ "Reserved enhanced validity period format\n");
+ return gsm340_vp_default();
+ }
case GSM340_TP_VPF_NONE:
- /* Default validity: two days */
- minutes = 24 * 60 * 2;
- break;
+ default:
+ return gsm340_vp_default();
}
- return minutes;
}
/* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */
@@ -250,7 +376,8 @@ enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
if ((cgbits & 0xc) == 0) {
if (cgbits & 2)
- DEBUGP(DSMS, "Compressed SMS not supported yet\n");
+ LOGP(DSMS, LOGL_NOTICE,
+ "Compressed SMS not supported yet\n");
switch ((dcs >> 2)&0x03) {
case 0:
@@ -280,7 +407,7 @@ enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms)
{
if (db_sms_store(gsms) != 0) {
- DEBUGP(DSMS, "Failed to store SMS in Database\n");
+ LOGP(DSMS, LOGL_ERROR, "Failed to store SMS in Database\n");
return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
}
/* dispatch a signal to tell higher level about it */
@@ -307,69 +434,6 @@ static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len,
return len_in_bytes;
}
-/* Turn int into semi-octet representation: 98 => 0x89 */
-static u_int8_t bcdify(u_int8_t value)
-{
- u_int8_t ret;
-
- ret = value / 10;
- ret |= (value % 10) << 4;
-
- return ret;
-}
-
-/* Turn semi-octet representation into int: 0x89 => 98 */
-static u_int8_t unbcdify(u_int8_t value)
-{
- u_int8_t ret;
-
- if ((value & 0x0F) > 9 || (value >> 4) > 9)
- DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value);
-
- ret = (value&0x0F)*10;
- if (ret > 90)
- ret += value>>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);
-
- *scts++ = bcdify(tm->tm_year % 100);
- *scts++ = bcdify(tm->tm_mon + 1);
- *scts++ = bcdify(tm->tm_mday);
- *scts++ = bcdify(tm->tm_hour);
- *scts++ = bcdify(tm->tm_min);
- *scts++ = bcdify(tm->tm_sec);
- *scts++ = bcdify(tm->tm_gmtoff/(60*15));
-}
-
-/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */
-static time_t gsm340_scts(u_int8_t *scts)
-{
- struct tm tm;
-
- u_int8_t yr = unbcdify(*scts++);
-
- if (yr <= 80)
- tm.tm_year = 100 + yr;
- else
- tm.tm_year = yr;
- tm.tm_mon = unbcdify(*scts++) - 1;
- tm.tm_mday = unbcdify(*scts++);
- tm.tm_hour = unbcdify(*scts++);
- tm.tm_min = unbcdify(*scts++);
- tm.tm_sec = unbcdify(*scts++);
- /* according to gsm 03.40 time zone is
- "expressed in quarters of an hour" */
- tm.tm_gmtoff = unbcdify(*scts++) * 15*60;
-
- return mktime(&tm);
-}
-
/* generate a msgb containing a TPDU derived from struct gsm_sms,
* returns total size of TPDU */
static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
@@ -437,7 +501,8 @@ static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
memcpy(smsp, sms->user_data, sms->user_data_len);
break;
default:
- DEBUGP(DSMS, "Unhandled Data Coding Scheme: 0x%02X\n", sms->data_coding_scheme);
+ LOGP(DSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: 0x%02X\n",
+ sms->data_coding_scheme);
break;
}
@@ -457,6 +522,8 @@ static int gsm340_rx_tpdu(struct msgb *msg)
u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
int rc = 0;
+ counter_inc(bts->network->stats.sms.submitted);
+
gsms = sms_alloc();
if (!gsms)
return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
@@ -475,7 +542,7 @@ static int gsm340_rx_tpdu(struct msgb *msg)
/* length in bytes of the destination address */
da_len_bytes = 2 + *smsp/2 + *smsp%2;
if (da_len_bytes > 12) {
- DEBUGP(DSMS, "Destination Address > 12 bytes ?!?\n");
+ LOGP(DSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n");
rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
goto out;
}
@@ -499,14 +566,17 @@ static int gsm340_rx_tpdu(struct msgb *msg)
case GSM340_TP_VPF_ABSOLUTE:
case GSM340_TP_VPF_ENHANCED:
sms_vp = smsp;
+ /* the additional functionality indicator... */
+ if (sms_vpf == GSM340_TP_VPF_ENHANCED && *smsp & (1<<7))
+ smsp++;
smsp += 7;
break;
case GSM340_TP_VPF_NONE:
sms_vp = 0;
break;
default:
- DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n",
- sms_vpf);
+ LOGP(DSMS, LOGL_NOTICE,
+ "SMS Validity period not implemented: 0x%02x\n", sms_vpf);
return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
}
gsms->user_data_len = *smsp++;
@@ -524,16 +594,17 @@ static int gsm340_rx_tpdu(struct msgb *msg)
}
}
- DEBUGP(DSMS, "SMS:\nMTI: 0x%02x, VPF: 0x%02x, MR: 0x%02x "
- "PID: 0x%02x, DCS: 0x%02x, DA: %s, UserDataLength: 0x%02x "
- "UserData: \"%s\"\n", sms_mti, sms_vpf, gsms->msg_ref,
- gsms->protocol_id, gsms->data_coding_scheme,
- gsms->dest_addr, gsms->user_data_len,
+ gsms->sender = subscr_get(msg->lchan->subscr);
+
+ LOGP(DSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, "
+ "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, "
+ "UserDataLength: 0x%02x, UserData: \"%s\"\n",
+ subscr_name(gsms->sender), sms_mti, sms_vpf, gsms->msg_ref,
+ gsms->protocol_id, gsms->data_coding_scheme, gsms->dest_addr,
+ gsms->user_data_len,
sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
hexdump(gsms->user_data, gsms->user_data_len));
- gsms->sender = subscr_get(msg->lchan->subscr);
-
gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
dispatch_signal(SS_SMS, 0, gsms);
@@ -542,6 +613,7 @@ static int gsm340_rx_tpdu(struct msgb *msg)
gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr);
if (!gsms->receiver) {
rc = 1; /* cause 1: unknown subscriber */
+ counter_inc(bts->network->stats.sms.no_receiver);
goto out;
}
@@ -552,11 +624,11 @@ static int gsm340_rx_tpdu(struct msgb *msg)
break;
case GSM340_SMS_COMMAND_MS2SC:
case GSM340_SMS_DELIVER_REP_MS2SC:
- DEBUGP(DSMS, "Unimplemented MTI 0x%02x\n", sms_mti);
+ LOGP(DSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti);
rc = GSM411_RP_CAUSE_IE_NOTEXIST;
break;
default:
- DEBUGP(DSMS, "Undefined MTI 0x%02x\n", sms_mti);
+ LOGP(DSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti);
rc = GSM411_RP_CAUSE_IE_NOTEXIST;
break;
}
@@ -586,7 +658,7 @@ static int gsm411_send_rp_error(struct gsm_trans *trans,
msgb_tv_put(msg, 1, cause);
- DEBUGP(DSMS, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
+ LOGP(DSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
get_value_string(rp_cause_strs, cause));
return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
@@ -602,10 +674,11 @@ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
int rc = 0;
if (src_len && src)
- DEBUGP(DSMS, "RP-DATA (MO) with SRC ?!?\n");
+ LOGP(DSMS, LOGL_ERROR, "RP-DATA (MO) with SRC ?!?\n");
if (!dst_len || !dst || !tpdu_len || !tpdu) {
- DEBUGP(DSMS, "RP-DATA (MO) without DST or TPDU ?!?\n");
+ LOGP(DSMS, LOGL_ERROR,
+ "RP-DATA (MO) without DST or TPDU ?!?\n");
gsm411_send_rp_error(trans, rph->msg_ref,
GSM411_RP_CAUSE_INV_MAND_INF);
return -EIO;
@@ -660,13 +733,13 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
* transmitted */
if (!trans->sms.is_mt) {
- DEBUGP(DSMS, "RX RP-ACK on a MO transfer ?\n");
+ LOGP(DSMS, LOGL_ERROR, "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 but no sms in transaction?!?\n");
+ LOGP(DSMS, LOGL_ERROR, "RX RP-ACK but no sms in transaction?!?\n");
return gsm411_send_rp_error(trans, rph->msg_ref,
GSM411_RP_CAUSE_PROTOCOL_ERR);
}
@@ -679,14 +752,16 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
sms_free(sms);
trans->sms.sms = NULL;
- /* free the transaction here */
- trans_free(trans);
-
/* check for more messages for this subscriber */
sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr);
if (sms)
gsm411_send_sms_lchan(msg->lchan, sms);
- else
+
+ /* free the transaction here */
+ trans_free(trans);
+
+ /* release channel if done */
+ if (!sms)
rsl_release_request(msg->lchan, trans->sms.link_id);
return 0;
@@ -695,6 +770,7 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
struct gsm411_rp_hdr *rph)
{
+ struct gsm_network *net = trans->lchan->ts->trx->bts->network;
struct gsm_sms *sms = trans->sms.sms;
u_int8_t cause_len = rph->data[0];
u_int8_t cause = rph->data[1];
@@ -703,11 +779,12 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
* successfully receive the SMS. We need to investigate
* the cause and take action depending on it */
- DEBUGP(DSMS, "RX SMS RP-ERROR, cause %d:%d (%s)\n", cause_len, cause,
- get_value_string(rp_cause_strs, cause));
+ LOGP(DSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
+ subscr_name(msg->lchan->subscr), cause_len, cause,
+ get_value_string(rp_cause_strs, cause));
if (!trans->sms.is_mt) {
- DEBUGP(DSMS, "RX RP-ERR on a MO transfer ?\n");
+ LOGP(DSMS, LOGL_ERROR, "RX RP-ERR on a MO transfer ?\n");
#if 0
return gsm411_send_rp_error(trans, rph->msg_ref,
GSM411_RP_CAUSE_MSG_INCOMP_STATE);
@@ -715,7 +792,8 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
}
if (!sms) {
- DEBUGP(DSMS, "RX RP-ERR, but no sms in transaction?!?\n");
+ LOGP(DSMS, LOGL_ERROR,
+ "RX RP-ERR, but no sms in transaction?!?\n");
return -EINVAL;
#if 0
return gsm411_send_rp_error(trans, rph->msg_ref,
@@ -728,7 +806,9 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
* to store this in our database and wati for a SMMA message */
/* FIXME */
dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr);
- }
+ counter_inc(net->stats.sms.rp_err_mem);
+ } else
+ counter_inc(net->stats.sms.rp_err_other);
sms_free(sms);
trans->sms.sms = NULL;
@@ -790,7 +870,7 @@ static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
rc = gsm411_rx_rp_error(msg, trans, rp_data);
break;
default:
- DEBUGP(DSMS, "Invalid RP type 0x%02x\n", msg_type);
+ LOGP(DSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type);
rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
break;
@@ -821,7 +901,7 @@ static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
struct msgb *msg = gsm411_msgb_alloc();
u_int8_t *causep;
- DEBUGP(DSMS, "TX CP-ERROR, cause %d (%s)\n", cause,
+ LOGP(DSMS, LOGL_NOTICE, "TX CP-ERROR, cause %d (%s)\n", cause,
get_value_string(cp_cause_strs, cause));
causep = msgb_put(msg, 1);
@@ -844,11 +924,11 @@ int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id)
return -EIO;
/* FIXME: send some error message */
- DEBUGP(DSMS, "trans_id=%x ", gh->proto_discr >> 4);
+ DEBUGP(DSMS, "trans_id=%x ", transaction_id);
trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS,
transaction_id);
if (!trans) {
- DEBUGPC(DSMS, "(unknown) ");
+ DEBUGPC(DSMS, "(new) ");
trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
transaction_id, new_callref++);
if (!trans) {
@@ -868,6 +948,33 @@ int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id)
switch(msg_type) {
case GSM411_MT_CP_DATA:
DEBUGPC(DSMS, "RX SMS CP-DATA\n");
+
+ /* 5.4: For MO, if a CP-DATA is received for a new
+ * transaction, equals reception of an implicit
+ * last CP-ACK for previous transaction */
+ if (trans->sms.cp_state == GSM411_CPS_IDLE) {
+ int i;
+ struct gsm_trans *ptrans;
+
+ /* Scan through all remote initiated transactions */
+ for (i=8; i<15; i++) {
+ if (i == transaction_id)
+ continue;
+
+ ptrans = trans_find_by_id(lchan->subscr,
+ GSM48_PDISC_SMS, i);
+ if (!ptrans)
+ continue;
+
+ DEBUGP(DSMS, "Implicit CP-ACK for trans_id=%x\n", i);
+
+ /* Finish it for good */
+ bsc_del_timer(&ptrans->sms.cp_timer);
+ ptrans->sms.cp_state = GSM411_CPS_IDLE;
+ trans_free(ptrans);
+ }
+ }
+
/* 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
@@ -940,10 +1047,14 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
struct gsm_trans *trans;
u_int8_t *data, *rp_ud_len;
u_int8_t msg_ref = 42;
- u_int8_t transaction_id;
+ int transaction_id;
int rc;
- transaction_id = 4; /* FIXME: we always use 4 for now */
+ transaction_id = trans_assign_trans_id(lchan->subscr, GSM48_PDISC_SMS, 0);
+ if (transaction_id == -1) {
+ LOGP(DSMS, LOGL_ERROR, "No available transaction ids\n");
+ return -EBUSY;
+ }
msg->lchan = lchan;
@@ -953,7 +1064,7 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
transaction_id, new_callref++);
if (!trans) {
- DEBUGP(DSMS, "No memory for trans\n");
+ LOGP(DSMS, LOGL_ERROR, "No memory for trans\n");
/* FIXME: send some error message */
return -ENOMEM;
}
@@ -1001,6 +1112,8 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
DEBUGP(DSMS, "TX: SMS DELIVER\n");
+ counter_inc(lchan->ts->trx->bts->network->stats.sms.delivered);
+
return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
/* FIXME: enter 'wait for RP-ACK' state, start TR1N */
}