gsm411_sms.c: Handle negative return of gsm340_gen_oa()
[osmocom-bb.git] / src / host / layer23 / src / mobile / gsm411_sms.c
blob45decfd9262aa42525b13fb6217724055b382ac7
1 /*
2 * Code based on work of:
3 * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
4 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
5 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2010 by On-Waves
8 * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
10 * All Rights Reserved
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include <stdint.h>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
34 #include <osmocom/core/msgb.h>
35 #include <osmocom/bb/common/logging.h>
36 #include <osmocom/bb/common/osmocom_data.h>
37 #include <osmocom/bb/mobile/mncc.h>
38 #include <osmocom/bb/mobile/transaction.h>
39 #include <osmocom/bb/mobile/gsm411_sms.h>
40 #include <osmocom/gsm/gsm0411_utils.h>
41 #include <osmocom/core/talloc.h>
42 #include <osmocom/bb/mobile/vty.h>
43 #include <osmocom/bb/mobile/primitives.h>
45 #define UM_SAPI_SMS 3
47 extern void *l23_ctx;
48 static uint32_t new_callref = 0x40000001;
50 static int gsm411_rl_recv(struct gsm411_smr_inst *inst, int msg_type,
51 struct msgb *msg);
52 static int gsm411_mn_recv(struct gsm411_smc_inst *inst, int msg_type,
53 struct msgb *msg);
54 static int gsm411_mm_send(struct gsm411_smc_inst *inst, int msg_type,
55 struct msgb *msg, int cp_msg_type);
56 static int gsm411_mn_send(struct gsm411_smr_inst *inst, int msg_type,
57 struct msgb *msg);
59 * init / exit
62 int gsm411_sms_init(struct osmocom_ms *ms)
64 LOGP(DLSMS, LOGL_INFO, "init SMS\n");
66 return 0;
69 int gsm411_sms_exit(struct osmocom_ms *ms)
71 struct gsm_trans *trans, *trans2;
73 LOGP(DLSMS, LOGL_INFO, "exit SMS processes for %s\n", ms->name);
75 llist_for_each_entry_safe(trans, trans2, &ms->trans_list, entry) {
76 if (trans->protocol == GSM48_PDISC_SMS) {
77 LOGP(DLSMS, LOGL_NOTICE, "Free pendig "
78 "SMS-transaction.\n");
79 trans_free(trans);
83 return 0;
87 * SMS content
90 struct gsm_sms *sms_alloc(void)
92 return talloc_zero(l23_ctx, struct gsm_sms);
95 void sms_free(struct gsm_sms *sms)
97 talloc_free(sms);
100 struct gsm_sms *sms_from_text(const char *receiver, int dcs, const char *text)
102 struct gsm_sms *sms = sms_alloc();
104 if (!sms)
105 return NULL;
107 OSMO_STRLCPY_ARRAY(sms->text, text);
109 /* FIXME: don't use ID 1 static */
110 sms->reply_path_req = 0;
111 sms->status_rep_req = 0;
112 sms->ud_hdr_ind = 0;
113 sms->protocol_id = 0; /* implicit */
114 sms->data_coding_scheme = dcs;
115 OSMO_STRLCPY_ARRAY(sms->address, receiver);
116 /* Generate user_data */
117 sms->user_data_len = gsm_7bit_encode_n(sms->user_data,
118 sizeof(sms->user_data), sms->text, NULL);
120 return sms;
123 static int gsm411_sms_report(struct osmocom_ms *ms, struct gsm_sms *sms,
124 uint8_t cause)
126 vty_notify(ms, NULL);
127 if (!cause)
128 vty_notify(ms, "SMS to %s successfull\n", sms->address);
129 else
130 vty_notify(ms, "SMS to %s failed: %s\n", sms->address,
131 get_value_string(gsm411_rp_cause_strs, cause));
133 mobile_prim_ntfy_sms_status(ms, sms, cause);
134 return 0;
137 * transaction
140 /* SMS Specific transaction release.
141 * gets called by trans_free, DO NOT CALL YOURSELF!
143 void _gsm411_sms_trans_free(struct gsm_trans *trans)
145 gsm411_smr_clear(&trans->sms.smr_inst);
146 gsm411_smc_clear(&trans->sms.smc_inst);
148 if (trans->sms.sms) {
149 LOGP(DLSMS, LOGL_ERROR, "Transaction contains SMS.\n");
150 gsm411_sms_report(trans->ms, trans->sms.sms,
151 GSM411_RP_CAUSE_MO_SMS_REJECTED);
152 sms_free(trans->sms.sms);
153 trans->sms.sms = NULL;
157 /* release MM connection, free transaction */
158 static int gsm411_trans_free(struct gsm_trans *trans)
160 struct msgb *nmsg;
162 /* release MM connection */
163 nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_REL_REQ, trans->callref,
164 trans->transaction_id, trans->sms.sapi);
165 if (!nmsg)
166 return -ENOMEM;
167 LOGP(DLSMS, LOGL_INFO, "Sending MMSMS_REL_REQ\n");
168 gsm48_mmxx_downmsg(trans->ms, nmsg);
170 trans->callref = 0;
171 trans_free(trans);
173 return 0;
177 * receive SMS
180 /* store the SMS to disk */
181 static int sms_store(struct osmocom_ms *ms, struct msgb *msg,
182 struct gsm_sms *gsms)
184 const char osmocomsms[] = ".osmocom/bb/sms.txt";
185 const char *home;
186 char *sms_file;
187 char vty_text[sizeof(gsms->text)], *p;
188 FILE *fp;
190 /* remove linefeeds and show at VTY */
191 strcpy(vty_text, gsms->text);
192 for (p = vty_text; *p; p++) {
193 if (*p == '\n' || *p == '\r')
194 *p = ' ';
196 vty_notify(ms, NULL);
197 vty_notify(ms, "SMS from %s: '%s'\n", gsms->address, vty_text);
199 home = getenv("HOME");
200 if (!home) {
201 fail:
202 fprintf(stderr, "Can't deliver SMS, be sure to create '%s' in "
203 "your home directory.\n", osmocomsms);
204 return GSM411_RP_CAUSE_MT_MEM_EXCEEDED;
206 sms_file = talloc_asprintf(l23_ctx, "%s/%s", home, osmocomsms);
207 if (!sms_file)
208 goto fail;
210 fp = fopen(sms_file, "a");
211 if (!fp) {
212 talloc_free(sms_file);
213 goto fail;
215 fprintf(fp, "[SMS from %s]\n%s\n", gsms->address, gsms->text);
216 fclose(fp);
218 talloc_free(sms_file);
220 return 0;
223 /* now here comes our SMS */
224 static int gsm340_rx_sms_deliver(struct osmocom_ms *ms, struct msgb *msg,
225 struct gsm_sms *gsms)
227 mobile_prim_ntfy_sms_new(ms, gsms);
228 if (!ms->settings.store_sms)
229 return 0;
230 return sms_store(ms, msg, gsms);
233 /* process an incoming TPDU (called from RP-DATA)
234 * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
235 static int gsm340_rx_tpdu(struct gsm_trans *trans, struct msgb *msg, uint8_t msg_ref)
237 uint8_t *smsp = msgb_sms(msg);
238 struct gsm_sms *gsms;
239 unsigned int sms_alphabet;
240 uint8_t sms_mti;
241 uint8_t oa_len_bytes;
242 uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
243 int rc = 0;
245 gsms = sms_alloc();
246 gsms->msg_ref = msg_ref;
248 /* invert those fields where 0 means active/present */
249 sms_mti = *smsp & 0x03;
250 /* uint8_t sms_mms = !!(*smsp & 0x04); */
251 gsms->status_rep_req = (*smsp & 0x20);
252 gsms->ud_hdr_ind = (*smsp & 0x40);
253 gsms->reply_path_req = (*smsp & 0x80);
254 smsp++;
256 /* length in bytes of the originate address */
257 oa_len_bytes = 2 + *smsp/2 + *smsp%2;
258 if (oa_len_bytes > 12) {
259 LOGP(DLSMS, LOGL_ERROR, "Originate Address > 12 bytes ?!?\n");
260 rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
261 goto out;
263 memset(address_lv, 0, sizeof(address_lv));
264 memcpy(address_lv, smsp, oa_len_bytes);
265 /* mangle first byte to reflect length in bytes, not digits */
266 address_lv[0] = oa_len_bytes - 1;
267 /* convert to real number */
268 if (((smsp[1] & 0x70) >> 4) == 1)
269 strcpy(gsms->address, "+");
270 else if (((smsp[1] & 0x70) >> 4) == 2)
271 strcpy(gsms->address, "0");
272 else
273 gsms->address[0] = '\0';
274 gsm48_decode_bcd_number2(gsms->address + strlen(gsms->address),
275 sizeof(gsms->address) - strlen(gsms->address), address_lv, sizeof(address_lv), 1);
276 smsp += oa_len_bytes;
278 gsms->protocol_id = *smsp++;
279 gsms->data_coding_scheme = *smsp++;
281 sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
282 if (sms_alphabet == 0xffffffff) {
283 sms_free(gsms);
284 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
287 /* get timestamp */
288 gsms->time = gsm340_scts(smsp);
289 smsp += 7;
291 /* user data */
292 gsms->user_data_len = *smsp++;
293 if (gsms->user_data_len) {
294 memcpy(gsms->user_data, smsp, gsms->user_data_len);
296 switch (sms_alphabet) {
297 case DCS_7BIT_DEFAULT:
298 gsm_7bit_decode_n(gsms->text, sizeof(gsms->text),
299 smsp, gsms->user_data_len);
300 break;
301 case DCS_8BIT_DATA:
302 case DCS_UCS2:
303 case DCS_NONE:
304 break;
308 LOGP(DLSMS, LOGL_INFO, "RX SMS: MTI: 0x%02x, "
309 "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, OA: %s, "
310 "UserDataLength: 0x%02x, UserData: \"%s\"\n",
311 sms_mti, gsms->msg_ref,
312 gsms->protocol_id, gsms->data_coding_scheme, gsms->address,
313 gsms->user_data_len,
314 sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
315 osmo_hexdump(gsms->user_data,
316 gsms->user_data_len));
318 switch (sms_mti) {
319 case GSM340_SMS_DELIVER_SC2MS:
320 /* MS is receiving an SMS */
321 rc = gsm340_rx_sms_deliver(trans->ms, msg, gsms);
322 break;
323 case GSM340_SMS_STATUS_REP_SC2MS:
324 case GSM340_SMS_SUBMIT_REP_SC2MS:
325 LOGP(DLSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti);
326 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
327 break;
328 default:
329 LOGP(DLSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti);
330 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
331 break;
334 out:
335 sms_free(gsms);
337 return rc;
340 static int gsm411_send_rp_ack(struct gsm_trans *trans, uint8_t msg_ref)
342 struct msgb *msg = gsm411_msgb_alloc();
344 LOGP(DLSMS, LOGL_INFO, "TX: SMS RP ACK\n");
346 gsm411_push_rp_header(msg, GSM411_MT_RP_ACK_MO, msg_ref);
347 return gsm411_smr_send(&trans->sms.smr_inst, GSM411_SM_RL_REPORT_REQ,
348 msg);
351 static int gsm411_send_rp_error(struct gsm_trans *trans,
352 uint8_t msg_ref, uint8_t cause)
354 struct msgb *msg = gsm411_msgb_alloc();
356 msgb_tv_put(msg, 1, cause);
358 LOGP(DLSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
359 get_value_string(gsm411_rp_cause_strs, cause));
361 gsm411_push_rp_header(msg, GSM411_MT_RP_ERROR_MO, msg_ref);
362 return gsm411_smr_send(&trans->sms.smr_inst, GSM411_SM_RL_REPORT_REQ,
363 msg);
366 /* Receive a 04.11 TPDU inside RP-DATA / user data */
367 static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
368 struct gsm411_rp_hdr *rph,
369 uint8_t src_len, uint8_t *src,
370 uint8_t dst_len, uint8_t *dst,
371 uint8_t tpdu_len, uint8_t *tpdu)
373 int rc = 0;
375 if (dst_len && dst)
376 LOGP(DLSMS, LOGL_ERROR, "RP-DATA (MT) with DST ?!?\n");
378 if (!src_len || !src || !tpdu_len || !tpdu) {
379 LOGP(DLSMS, LOGL_ERROR,
380 "RP-DATA (MO) without DST or TPDU ?!?\n");
381 gsm411_send_rp_error(trans, rph->msg_ref,
382 GSM411_RP_CAUSE_INV_MAND_INF);
383 return -EIO;
385 msg->l4h = tpdu;
387 LOGP(DLSMS, LOGL_INFO, "DST(%u,%s)\n", src_len,
388 osmo_hexdump(src, src_len));
389 LOGP(DLSMS, LOGL_INFO, "TPDU(%ti,%s)\n", msg->tail-msg->l4h,
390 osmo_hexdump(msg->l4h, msg->tail-msg->l4h));
392 rc = gsm340_rx_tpdu(trans, msg, rph->msg_ref);
393 if (rc == 0)
394 return gsm411_send_rp_ack(trans, rph->msg_ref);
395 else if (rc > 0)
396 return gsm411_send_rp_error(trans, rph->msg_ref, rc);
397 else
398 return rc;
401 /* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
402 static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
403 struct gsm411_rp_hdr *rph)
405 uint8_t src_len, dst_len, rpud_len;
406 uint8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
408 /* in the MO case, this should always be zero length */
409 src_len = rph->data[0];
410 if (src_len)
411 src = &rph->data[1];
413 dst_len = rph->data[1+src_len];
414 if (dst_len)
415 dst = &rph->data[1+src_len+1];
417 rpud_len = rph->data[1+src_len+1+dst_len];
418 if (rpud_len)
419 rp_ud = &rph->data[1+src_len+1+dst_len+1];
421 LOGP(DLSMS, LOGL_INFO, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
422 src_len, dst_len, rpud_len);
423 return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst,
424 rpud_len, rp_ud);
427 /* receive RL DATA */
428 static int gsm411_rx_rl_data(struct msgb *msg, struct gsm48_hdr *gh,
429 struct gsm_trans *trans)
431 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
432 uint8_t msg_type = rp_data->msg_type & 0x07;
433 int rc = 0;
435 switch (msg_type) {
436 case GSM411_MT_RP_DATA_MT:
437 LOGP(DLSMS, LOGL_INFO, "RX SMS RP-DATA (MT)\n");
438 rc = gsm411_rx_rp_data(msg, trans, rp_data);
439 break;
440 default:
441 LOGP(DLSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type);
442 gsm411_trans_free(trans);
443 rc = -EINVAL;
444 break;
447 return rc;
451 * send SMS
454 /* Receive a 04.11 RP-ACK message (response to RP-DATA from us) */
455 static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
456 struct gsm411_rp_hdr *rph)
458 struct osmocom_ms *ms = trans->ms;
459 struct gsm_sms *sms = trans->sms.sms;
461 /* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
462 * successfully received a SMS. We can now safely mark it as
463 * transmitted */
465 if (!sms) {
466 LOGP(DLSMS, LOGL_ERROR, "RX RP-ACK but no sms in "
467 "transaction?!?\n");
468 return gsm411_send_rp_error(trans, rph->msg_ref,
469 GSM411_RP_CAUSE_PROTOCOL_ERR);
472 gsm411_sms_report(ms, sms, 0);
474 sms_free(sms);
475 trans->sms.sms = NULL;
477 return 0;
480 static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
481 struct gsm411_rp_hdr *rph)
483 struct osmocom_ms *ms = trans->ms;
484 struct gsm_sms *sms = trans->sms.sms;
485 uint8_t cause_len = rph->data[0];
486 uint8_t cause = rph->data[1];
488 /* Error in response to MT RP_DATA, i.e. the MS did not
489 * successfully receive the SMS. We need to investigate
490 * the cause and take action depending on it */
492 LOGP(DLSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
493 trans->ms->name, cause_len, cause,
494 get_value_string(gsm411_rp_cause_strs, cause));
496 if (!sms) {
497 LOGP(DLSMS, LOGL_ERROR,
498 "RX RP-ERR, but no sms in transaction?!?\n");
499 return -EINVAL;
500 #if 0
501 return gsm411_send_rp_error(trans, rph->msg_ref,
502 GSM411_RP_CAUSE_PROTOCOL_ERR);
503 #endif
506 gsm411_sms_report(ms, sms, cause);
508 sms_free(sms);
509 trans->sms.sms = NULL;
511 return 0;
514 /* receive RL REPORT */
515 static int gsm411_rx_rl_report(struct msgb *msg, struct gsm48_hdr *gh,
516 struct gsm_trans *trans)
518 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
519 uint8_t msg_type = rp_data->msg_type & 0x07;
520 int rc = 0;
522 switch (msg_type) {
523 case GSM411_MT_RP_ACK_MT:
524 LOGP(DLSMS, LOGL_INFO, "RX SMS RP-ACK (MT)\n");
525 rc = gsm411_rx_rp_ack(msg, trans, rp_data);
526 break;
527 case GSM411_MT_RP_ERROR_MT:
528 LOGP(DLSMS, LOGL_INFO, "RX SMS RP-ERROR (MT)\n");
529 rc = gsm411_rx_rp_error(msg, trans, rp_data);
530 break;
531 default:
532 LOGP(DLSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type);
533 gsm411_trans_free(trans);
534 rc = -EINVAL;
535 break;
538 return rc;
541 /* generate a msgb containing a TPDU derived from struct gsm_sms,
542 * returns total size of TPDU */
543 static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
545 uint8_t *smsp;
546 uint8_t da[12]; /* max len per 03.40 */
547 uint8_t da_len = 0;
548 uint8_t octet_len;
549 unsigned int old_msg_len = msg->len;
550 uint8_t sms_vpf = GSM340_TP_VPF_NONE;
551 uint8_t sms_vp;
553 /* generate first octet with masked bits */
554 smsp = msgb_put(msg, 1);
555 /* TP-MTI (message type indicator) */
556 *smsp = GSM340_SMS_SUBMIT_MS2SC;
557 /* TP-RD */
558 if (0 /* FIXME */)
559 *smsp |= 0x04;
560 /* TP-VPF */
561 *smsp |= (sms_vpf << 3);
562 /* TP-SRI(deliver)/SRR(submit) */
563 if (sms->status_rep_req)
564 *smsp |= 0x20;
565 /* TP-UDHI (indicating TP-UD contains a header) */
566 if (sms->ud_hdr_ind)
567 *smsp |= 0x40;
568 /* TP-RP */
569 if (sms->reply_path_req)
570 *smsp |= 0x80;
572 /* generate message ref */
573 smsp = msgb_put(msg, 1);
574 *smsp = sms->msg_ref;
576 /* generate destination address */
577 if (sms->address[0] == '+')
578 da_len = gsm340_gen_oa(da, sizeof(da), 0x1, 0x1,
579 sms->address + 1);
580 else
581 da_len = gsm340_gen_oa(da, sizeof(da), 0x0, 0x1, sms->address);
582 if (da_len < 0)
583 return da_len;
585 smsp = msgb_put(msg, da_len);
586 memcpy(smsp, da, da_len);
588 /* generate TP-PID */
589 smsp = msgb_put(msg, 1);
590 *smsp = sms->protocol_id;
592 /* generate TP-DCS */
593 smsp = msgb_put(msg, 1);
594 *smsp = sms->data_coding_scheme;
596 /* generate TP-VP */
597 switch (sms_vpf) {
598 case GSM340_TP_VPF_NONE:
599 sms_vp = 0;
600 break;
601 default:
602 fprintf(stderr, "VPF unsupported, please fix!\n");
603 exit(0);
605 smsp = msgb_put(msg, sms_vp);
607 /* generate TP-UDL */
608 smsp = msgb_put(msg, 1);
609 *smsp = sms->user_data_len;
611 /* generate TP-UD */
612 switch (gsm338_get_sms_alphabet(sms->data_coding_scheme)) {
613 case DCS_7BIT_DEFAULT:
614 octet_len = sms->user_data_len*7/8;
615 if (sms->user_data_len*7%8 != 0)
616 octet_len++;
617 /* Warning, user_data_len indicates the amount of septets
618 * (characters), we need amount of octets occupied */
619 smsp = msgb_put(msg, octet_len);
620 memcpy(smsp, sms->user_data, octet_len);
621 break;
622 case DCS_UCS2:
623 case DCS_8BIT_DATA:
624 smsp = msgb_put(msg, sms->user_data_len);
625 memcpy(smsp, sms->user_data, sms->user_data_len);
626 break;
627 default:
628 LOGP(DLSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: "
629 "0x%02X\n", sms->data_coding_scheme);
630 break;
633 return msg->len - old_msg_len;
636 /* Take a SMS in gsm_sms structure and send it. */
637 int gsm411_tx_sms_submit(struct osmocom_ms *ms, const char *sms_sca,
638 struct gsm_sms *sms)
640 struct msgb *msg;
641 struct gsm_trans *trans;
642 uint8_t *data, *rp_ud_len;
643 int rc;
644 int transaction_id;
645 uint8_t sca[11]; /* max len per 03.40 */
647 LOGP(DLSMS, LOGL_INFO, "..._sms_submit()\n");
649 /* no running, no transaction */
650 if (!ms->started || ms->shutdown != MS_SHUTDOWN_NONE) {
651 LOGP(DLSMS, LOGL_ERROR, "Phone is down\n");
652 gsm411_sms_report(ms, sms, GSM411_RP_CAUSE_MO_TEMP_FAIL);
653 sms_free(sms);
654 return -EIO;
657 /* allocate transaction with dummy reference */
658 transaction_id = trans_assign_trans_id(ms, GSM48_PDISC_SMS, 0);
659 if (transaction_id < 0) {
660 LOGP(DLSMS, LOGL_ERROR, "No transaction ID available\n");
661 gsm411_sms_report(ms, sms, GSM411_RP_CAUSE_MO_CONGESTION);
662 sms_free(sms);
663 return -ENOMEM;
665 trans = trans_alloc(ms, GSM48_PDISC_SMS, transaction_id, new_callref++);
666 if (!trans) {
667 LOGP(DLSMS, LOGL_ERROR, "No memory for trans\n");
668 gsm411_sms_report(ms, sms, GSM411_RP_CAUSE_MO_TEMP_FAIL);
669 sms_free(sms);
670 return -ENOMEM;
672 gsm411_smc_init(&trans->sms.smc_inst, transaction_id, 0,
673 gsm411_mn_recv, gsm411_mm_send);
674 gsm411_smr_init(&trans->sms.smr_inst, transaction_id, 0,
675 gsm411_rl_recv, gsm411_mn_send);
676 trans->sms.sms = sms;
677 trans->sms.sapi = UM_SAPI_SMS;
679 msg = gsm411_msgb_alloc();
681 /* no orig Address */
682 data = (uint8_t *)msgb_put(msg, 1);
683 data[0] = 0x00; /* originator length == 0 */
685 /* Destination Address */
686 sca[1] = 0x80; /* no extension */
687 sca[1] |= ((sms_sca[0] == '+') ? 0x01 : 0x00) << 4; /* type */
688 sca[1] |= 0x1; /* plan*/
690 rc = gsm48_encode_bcd_number(sca, sizeof(sca), 1,
691 sms_sca + (sms_sca[0] == '+'));
692 if (rc < 0) {
693 error:
694 gsm411_sms_report(ms, sms, GSM411_RP_CAUSE_SEMANT_INC_MSG);
695 gsm411_trans_free(trans);
696 msgb_free(msg);
697 return rc;
699 data = msgb_put(msg, rc);
700 memcpy(data, sca, rc);
702 /* obtain a pointer for the rp_ud_len, so we can fill it later */
703 rp_ud_len = (uint8_t *)msgb_put(msg, 1);
705 /* generate the 03.40 TPDU */
706 rc = gsm340_gen_tpdu(msg, sms);
707 if (rc < 0)
708 goto error;
709 *rp_ud_len = rc;
711 LOGP(DLSMS, LOGL_INFO, "TX: SMS DELIVER\n");
713 gsm411_push_rp_header(msg, GSM411_MT_RP_DATA_MO, sms->msg_ref);
714 return gsm411_smr_send(&trans->sms.smr_inst, GSM411_SM_RL_DATA_REQ,
715 msg);
718 /* create and send SMS */
719 int sms_send(struct osmocom_ms *ms, const char *sms_sca, const char *number,
720 const char *text, uint8_t msg_ref)
722 struct gsm_sms *sms = sms_from_text(number, 0, text);
724 if (!sms)
725 return -ENOMEM;
727 sms->msg_ref = msg_ref;
728 return gsm411_tx_sms_submit(ms, sms_sca, sms);
732 * message flow between layers
735 /* push MMSMS header and send to MM */
736 static int gsm411_to_mm(struct msgb *msg, struct gsm_trans *trans,
737 int msg_type)
739 struct gsm48_mmxx_hdr *mmh;
741 /* push RR header */
742 msgb_push(msg, sizeof(struct gsm48_mmxx_hdr));
743 mmh = (struct gsm48_mmxx_hdr *)msg->data;
744 mmh->msg_type = msg_type;
745 mmh->ref = trans->callref;
746 mmh->transaction_id = trans->transaction_id;
747 mmh->sapi = trans->sms.sapi;
748 mmh->emergency = 0;
750 /* send message to MM */
751 LOGP(DLSMS, LOGL_INFO, "Sending '%s' to MM (callref=%x, "
752 "transaction_id=%d, sapi=%d)\n", get_mmxx_name(msg_type),
753 trans->callref, trans->transaction_id, trans->sms.sapi);
754 return gsm48_mmxx_downmsg(trans->ms, msg);
757 /* mm_send: receive MMSMS sap message from SMC */
758 static int gsm411_mm_send(struct gsm411_smc_inst *inst, int msg_type,
759 struct msgb *msg, int cp_msg_type)
761 struct gsm_trans *trans =
762 container_of(inst, struct gsm_trans, sms.smc_inst);
763 int rc = 0;
765 switch (msg_type) {
766 case GSM411_MMSMS_EST_REQ:
767 gsm411_to_mm(msg, trans, msg_type);
768 break;
769 case GSM411_MMSMS_DATA_REQ:
770 gsm411_push_cp_header(msg, trans->protocol,
771 trans->transaction_id, cp_msg_type);
772 msg->l3h = msg->data;
773 LOGP(DLSMS, LOGL_INFO, "sending CP message (trans=%x)\n",
774 trans->transaction_id);
775 rc = gsm411_to_mm(msg, trans, msg_type);
776 break;
777 case GSM411_MMSMS_REL_REQ:
778 LOGP(DLSMS, LOGL_INFO, "Got MMSMS_REL_REQ, destroying "
779 "transaction.\n");
780 gsm411_to_mm(msg, trans, msg_type);
781 gsm411_trans_free(trans);
782 break;
783 default:
784 msgb_free(msg);
785 rc = -EINVAL;
788 return rc;
791 /* mm_send: receive MNSMS sap message from SMR */
792 static int gsm411_mn_send(struct gsm411_smr_inst *inst, int msg_type,
793 struct msgb *msg)
795 struct gsm_trans *trans =
796 container_of(inst, struct gsm_trans, sms.smr_inst);
798 /* forward to SMC */
799 return gsm411_smc_send(&trans->sms.smc_inst, msg_type, msg);
802 /* receive SM-RL sap message from SMR
803 * NOTE: Message is freed by sender
805 static int gsm411_rl_recv(struct gsm411_smr_inst *inst, int msg_type,
806 struct msgb *msg)
808 struct gsm_trans *trans =
809 container_of(inst, struct gsm_trans, sms.smr_inst);
810 struct gsm48_hdr *gh = msgb_l3(msg);
811 int rc = 0;
813 switch (msg_type) {
814 case GSM411_SM_RL_DATA_IND:
815 rc = gsm411_rx_rl_data(msg, gh, trans);
816 break;
817 case GSM411_SM_RL_REPORT_IND:
818 if (!gh)
819 LOGP(DLSMS, LOGL_INFO, "Release transaction on empty "
820 "report.\n");
821 else {
822 LOGP(DLSMS, LOGL_INFO, "Release transaction on RL "
823 "report.\n");
824 rc = gsm411_rx_rl_report(msg, gh, trans);
826 break;
827 default:
828 rc = -EINVAL;
831 return rc;
834 /* receive MNSMS sap message from SMC
835 * NOTE: Message is freed by sender
837 static int gsm411_mn_recv(struct gsm411_smc_inst *inst, int msg_type,
838 struct msgb *msg)
840 struct gsm_trans *trans =
841 container_of(inst, struct gsm_trans, sms.smc_inst);
842 struct gsm48_hdr *gh = msgb_l3(msg);
843 int rc = 0;
845 switch (msg_type) {
846 case GSM411_MNSMS_EST_IND:
847 case GSM411_MNSMS_DATA_IND:
848 LOGP(DLSMS, LOGL_INFO, "MNSMS-DATA/EST-IND\n");
849 rc = gsm411_smr_recv(&trans->sms.smr_inst, msg_type, msg);
850 break;
851 case GSM411_MNSMS_ERROR_IND:
852 if (gh)
853 LOGP(DLSMS, LOGL_INFO, "MNSMS-ERROR-IND, cause %d "
854 "(%s)\n", gh->data[0],
855 get_value_string(gsm411_cp_cause_strs,
856 gh->data[0]));
857 else
858 LOGP(DLSMS, LOGL_INFO, "MNSMS-ERROR-IND, no cause\n");
859 rc = gsm411_smr_recv(&trans->sms.smr_inst, msg_type, msg);
860 break;
861 default:
862 rc = -EINVAL;
865 return rc;
868 /* receive est/data message from MM layer */
869 static int gsm411_mmsms_ind(int mmsms_msg, struct gsm_trans *trans,
870 struct msgb *msg)
872 struct osmocom_ms *ms = trans->ms;
873 struct gsm48_hdr *gh = msgb_l3(msg);
874 int msg_type = gh->msg_type & 0xbf;
875 uint8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4;
876 /* flip */
878 /* pull the MMSMS header */
879 msgb_pull(msg, sizeof(struct gsm48_mmxx_hdr));
881 LOGP(DLSMS, LOGL_INFO, "(ms %s) Received est/data '%u'\n", ms->name,
882 msg_type);
884 /* 5.4: For MO, if a CP-DATA is received for a new
885 * transaction, equals reception of an implicit
886 * last CP-ACK for previous transaction */
887 if (trans->sms.smc_inst.cp_state == GSM411_CPS_IDLE
888 && msg_type == GSM411_MT_CP_DATA) {
889 int i;
890 struct gsm_trans *ptrans;
892 /* Scan through all remote initiated transactions */
893 for (i=8; i<15; i++) {
894 if (i == transaction_id)
895 continue;
897 ptrans = trans_find_by_id(ms, GSM48_PDISC_SMS, i);
898 if (!ptrans)
899 continue;
901 LOGP(DLSMS, LOGL_INFO, "Implicit CP-ACK for "
902 "trans_id=%x\n", i);
904 /* Finish it for good */
905 gsm411_trans_free(ptrans);
908 return gsm411_smc_recv(&trans->sms.smc_inst, mmsms_msg, msg, msg_type);
911 /* receive message from MM layer */
912 int gsm411_rcv_sms(struct osmocom_ms *ms, struct msgb *msg)
914 struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
915 int msg_type = mmh->msg_type;
916 int sapi = mmh->sapi;
917 struct gsm_trans *trans;
918 int rc = 0;
920 trans = trans_find_by_callref(ms, mmh->ref);
921 if (!trans) {
922 LOGP(DLSMS, LOGL_INFO, " -> (new transaction sapi=%d)\n", sapi);
923 trans = trans_alloc(ms, GSM48_PDISC_SMS, mmh->transaction_id,
924 mmh->ref);
925 if (!trans)
926 return -ENOMEM;
927 gsm411_smc_init(&trans->sms.smc_inst, trans->transaction_id, 0,
928 gsm411_mn_recv, gsm411_mm_send);
929 gsm411_smr_init(&trans->sms.smr_inst, trans->transaction_id, 0,
930 gsm411_rl_recv, gsm411_mn_send);
931 trans->sms.sapi = mmh->sapi;
934 LOGP(DLSMS, LOGL_INFO, "(ms %s) Received '%s' from MM\n", ms->name,
935 get_mmxx_name(msg_type));
937 switch (msg_type) {
938 case GSM48_MMSMS_EST_CNF:
939 rc = gsm411_smc_recv(&trans->sms.smc_inst, GSM411_MMSMS_EST_CNF,
940 msg, 0);
941 break;
942 case GSM48_MMSMS_EST_IND:
943 case GSM48_MMSMS_DATA_IND:
944 rc = gsm411_mmsms_ind(msg_type, trans, msg);
945 break;
946 case GSM48_MMSMS_REL_IND:
947 case GSM48_MMSMS_ERR_IND:
948 LOGP(DLSMS, LOGL_INFO, "MM connection released.\n");
949 trans_free(trans);
950 break;
951 default:
952 LOGP(DLSMS, LOGL_NOTICE, "Message unhandled.\n");
953 rc = -ENOTSUP;
956 return rc;