blob: 351a5fc506a9897dd5e159b001f438d13d7d8526 [file] [log] [blame]
Harald Welte59b04682009-06-10 05:40:52 +08001/* Point-to-Point (PP) Short Message Service (SMS)
2 * Support on Mobile Radio Interface
3 * 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0 */
4
5/* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
6 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
7 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 *
24 */
25
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <errno.h>
31#include <netinet/in.h>
32
33#include <openbsc/msgb.h>
34#include <openbsc/tlv.h>
35#include <openbsc/debug.h>
36#include <openbsc/gsm_data.h>
37#include <openbsc/gsm_subscriber.h>
38#include <openbsc/gsm_04_11.h>
39#include <openbsc/gsm_04_08.h>
40#include <openbsc/gsm_utils.h>
41#include <openbsc/abis_rsl.h>
42#include <openbsc/signal.h>
43#include <openbsc/db.h>
Harald Weltea8379772009-06-20 22:36:41 +020044#include <openbsc/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080045
46#define GSM411_ALLOC_SIZE 1024
47#define GSM411_ALLOC_HEADROOM 128
48
Harald Weltea8379772009-06-20 22:36:41 +020049static void *tall_sms_ctx;
50static void *tall_gsms_ctx;
51
Harald Welte59b04682009-06-10 05:40:52 +080052struct msgb *gsm411_msgb_alloc(void)
53{
Harald Welte9cfc9352009-06-26 19:39:35 +020054 return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
55 "GSM 04.11");
Harald Welte59b04682009-06-10 05:40:52 +080056}
57
Harald Welte7e2f57d2009-07-04 17:39:00 +020058static int gsm411_sendmsg(struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +080059{
60 if (msg->lchan)
61 msg->trx = msg->lchan->ts->trx;
62
63 msg->l3h = msg->data;
64
65 return rsl_data_request(msg, 0);
66}
67
Harald Welte7e2f57d2009-07-04 17:39:00 +020068/* Prefix msg with a 04.08/04.11 CP header */
69static int gsm411_cp_sendmsg(struct msgb *msg, u_int8_t msg_type,
70 u_int8_t trans_id)
71{
72 struct gsm48_hdr *gh;
73
74 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
75 /* Outgoing needs the highest bit set */
76 gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
77 gh->msg_type = msg_type;
78
79 return gsm411_sendmsg(msg);
80}
81
82/* Prefix msg with a RP-DATA header and send as CP-DATA */
83static int gsm411_rp_sendmsg(struct msgb *msg, u_int8_t rp_msg_type,
84 u_int8_t rp_msg_ref, u_int8_t cp_trans_id)
85{
86 struct gsm411_rp_hdr *rp;
87
88 /* GSM 04.11 RP-DATA header */
89 rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
90 rp->len = msg->len;
91 rp->msg_type = rp_msg_type;
92 rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */
93
94 return gsm411_cp_sendmsg(msg, GSM411_MT_CP_DATA, cp_trans_id);
95}
96
Harald Welte59b04682009-06-10 05:40:52 +080097
98#if 0
99static u_int8_t gsm0411_tpdu_from_sms(u_int8_t *tpdu, struct sms_deliver *sms)
100{
101}
102#endif
103
104static unsigned long gsm340_validity_period(struct sms_submit *sms)
105{
106 u_int8_t vp;
107 unsigned long minutes;
108
109 switch (sms->vpf) {
110 case GSM340_TP_VPF_RELATIVE:
111 /* Chapter 9.2.3.12.1 */
112 vp = *(sms->vp);
113 if (vp <= 143)
114 minutes = vp + 1 * 5;
115 else if (vp <= 167)
116 minutes = 12*60 + (vp-143) * 30;
117 else if (vp <= 196)
118 minutes = vp-166 * 60 * 24;
119 else
120 minutes = vp-192 * 60 * 24 * 7;
121 break;
122 case GSM340_TP_VPF_ABSOLUTE:
123 /* Chapter 9.2.3.12.2 */
124 /* FIXME: like service center time stamp */
125 DEBUGP(DSMS, "VPI absolute not implemented yet\n");
126 break;
127 case GSM340_TP_VPF_ENHANCED:
128 /* Chapter 9.2.3.12.3 */
129 /* FIXME: implementation */
130 DEBUGP(DSMS, "VPI enhanced not implemented yet\n");
131 break;
132 }
133 return minutes;
134}
135
136/* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */
137enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
138{
139 u_int8_t cgbits = dcs >> 4;
140 enum sms_alphabet alpha = DCS_NONE;
141
142 if ((cgbits & 0xc) == 0) {
143 if (cgbits & 2)
144 DEBUGP(DSMS, "Compressed SMS not supported yet\n");
145
146 switch (dcs & 3) {
147 case 0:
148 alpha = DCS_7BIT_DEFAULT;
149 break;
150 case 1:
151 alpha = DCS_8BIT_DATA;
152 break;
153 case 2:
154 alpha = DCS_UCS2;
155 break;
156 }
157 } else if (cgbits == 0xc || cgbits == 0xd)
158 alpha = DCS_7BIT_DEFAULT;
159 else if (cgbits == 0xe)
160 alpha = DCS_UCS2;
161 else if (cgbits == 0xf) {
162 if (dcs & 4)
163 alpha = DCS_8BIT_DATA;
164 else
165 alpha = DCS_7BIT_DEFAULT;
166 }
167
168 return alpha;
169}
170
171static int gsm340_rx_sms_submit(struct msgb *msg, struct sms_submit *sms,
172 struct gsm_sms *gsms)
173{
174 if (db_sms_store(gsms) != 0) {
175 DEBUGP(DSMS, "Failed to store SMS in Database\n");
Harald Weltea8379772009-06-20 22:36:41 +0200176 talloc_free(sms);
177 talloc_free(gsms);
Harald Welte59b04682009-06-10 05:40:52 +0800178 return -EIO;
179 }
180 return 0;
181}
182
183/* process an incoming TPDU (called from RP-DATA) */
184static int gsm340_rx_tpdu(struct msgb *msg)
185{
186 u_int8_t *smsp = msgb_sms(msg);
187 struct sms_submit *sms;
188 struct gsm_sms *gsms;
189 u_int8_t da_len_bytes;
190 u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
191 int rc = 0;
192
Harald Weltea8379772009-06-20 22:36:41 +0200193 if (!tall_sms_ctx)
194 tall_sms_ctx = talloc_named_const(tall_bsc_ctx, 1,
195 "sms_submit");
196
197 sms = talloc(tall_sms_ctx, struct sms_submit);
Harald Welte59b04682009-06-10 05:40:52 +0800198 if (!sms)
199 return -ENOMEM;
200 memset(sms, 0, sizeof(*sms));
201
Harald Weltea8379772009-06-20 22:36:41 +0200202 if (!tall_gsms_ctx)
203 tall_gsms_ctx = talloc_named_const(tall_bsc_ctx, 1,
204 "sms");
205
206 gsms = talloc(tall_gsms_ctx, struct gsm_sms);
Harald Welte59b04682009-06-10 05:40:52 +0800207 if (!gsms) {
Harald Weltea8379772009-06-20 22:36:41 +0200208 talloc_free(sms);
Harald Welte59b04682009-06-10 05:40:52 +0800209 return -ENOMEM;
210 }
211 memset(gsms, 0, sizeof(*gsms));
212
213 /* invert those fields where 0 means active/present */
214 sms->mti = *smsp & 0x03;
215 sms->mms = !!(*smsp & 0x04);
216 sms->vpf = (*smsp & 0x18) >> 3;
217 sms->sri = !!(*smsp & 0x20);
218 sms->udhi= !!(*smsp & 0x40);
219 sms->rp = !!(*smsp & 0x80);
220
221 smsp++;
222 sms->msg_ref = *smsp++;
223
224 /* length in bytes of the destination address */
225 da_len_bytes = 2 + *smsp/2 + *smsp%2;
226 if (da_len_bytes > 12) {
227 DEBUGP(DSMS, "Destination Address > 12 bytes ?!?\n");
228 rc = -EIO;
229 goto out;
230 }
Harald Welte3794e152009-06-12 02:42:11 +0800231 memset(address_lv, 0, sizeof(address_lv));
Harald Welte59b04682009-06-10 05:40:52 +0800232 memcpy(address_lv, smsp, da_len_bytes);
233 /* mangle first byte to reflect length in bytes, not digits */
Harald Welte3794e152009-06-12 02:42:11 +0800234 address_lv[0] = da_len_bytes - 1;
Harald Welte59b04682009-06-10 05:40:52 +0800235 /* convert to real number */
Harald Welte3794e152009-06-12 02:42:11 +0800236 decode_bcd_number(sms->dest_addr, sizeof(sms->dest_addr), address_lv, 1);
Harald Welte59b04682009-06-10 05:40:52 +0800237
238 smsp += da_len_bytes;
239
240 sms->pid = *smsp++;
241
242 sms->dcs = *smsp++;
243 sms->alphabet = gsm338_get_sms_alphabet(sms->dcs);
244
245 switch (sms->vpf) {
246 case GSM340_TP_VPF_RELATIVE:
247 sms->vp = smsp++;
248 break;
249 case GSM340_TP_VPF_ABSOLUTE:
250 case GSM340_TP_VPF_ENHANCED:
251 sms->vp = smsp;
252 smsp += 7;
253 break;
254 default:
255 DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n",
256 sms->vpf);
257 }
258 sms->ud_len = *smsp++;
259 if (sms->ud_len)
260 sms->user_data = smsp;
261 else
262 sms->user_data = NULL;
263
264 if (sms->ud_len) {
265 switch (sms->alphabet) {
266 case DCS_7BIT_DEFAULT:
267 gsm_7bit_decode(sms->decoded, smsp, sms->ud_len);
268 break;
269 case DCS_8BIT_DATA:
270 case DCS_UCS2:
271 case DCS_NONE:
272 memcpy(sms->decoded, sms->user_data, sms->ud_len);
273 break;
274 }
275 }
276
277 DEBUGP(DSMS, "SMS:\nMTI: 0x%02x, VPF: 0x%02x, MR: 0x%02x "
278 "PID: 0x%02x, DCS: 0x%02x, DA: %s, UserDataLength: 0x%02x "
279 "UserData: \"%s\"\n", sms->mti, sms->vpf, sms->msg_ref,
280 sms->pid, sms->dcs, sms->dest_addr, sms->ud_len,
281 sms->alphabet == DCS_7BIT_DEFAULT ? sms->decoded : hexdump(sms->user_data, sms->ud_len));
282
283 dispatch_signal(SS_SMS, 0, sms);
284
285 gsms->sender = msg->lchan->subscr;
286 /* FIXME: sender refcount */
287
288 /* determine gsms->receiver based on dialled number */
289 gsms->receiver = subscr_get_by_extension(sms->dest_addr);
290 if (!gsms->receiver) {
291 rc = 1; /* cause 1: unknown subscriber */
292 goto out;
293 }
294
295 if (sms->user_data)
296 strncpy(gsms->text, sms->decoded, sizeof(gsms->text));
297
298 switch (sms->mti) {
299 case GSM340_SMS_SUBMIT_MS2SC:
300 /* MS is submitting a SMS */
301 rc = gsm340_rx_sms_submit(msg, sms, gsms);
302 break;
303 case GSM340_SMS_COMMAND_MS2SC:
304 case GSM340_SMS_DELIVER_REP_MS2SC:
305 DEBUGP(DSMS, "Unimplemented MTI 0x%02x\n", sms->mti);
306 break;
307 default:
308 DEBUGP(DSMS, "Undefined MTI 0x%02x\n", sms->mti);
309 break;
310 }
311
312out:
Harald Weltea8379772009-06-20 22:36:41 +0200313 talloc_free(gsms);
314 talloc_free(sms);
Harald Welte59b04682009-06-10 05:40:52 +0800315
316 return rc;
317}
318
319static int gsm411_send_rp_ack(struct gsm_lchan *lchan, u_int8_t trans_id,
320 u_int8_t msg_ref)
321{
322 struct msgb *msg = gsm411_msgb_alloc();
Harald Welte59b04682009-06-10 05:40:52 +0800323
324 msg->lchan = lchan;
325
Harald Welte59b04682009-06-10 05:40:52 +0800326 DEBUGP(DSMS, "TX: SMS RP ACK\n");
327
Harald Welte7e2f57d2009-07-04 17:39:00 +0200328 return gsm411_rp_sendmsg(msg, GSM411_MT_RP_ACK_MT, msg_ref, trans_id);
Harald Welte59b04682009-06-10 05:40:52 +0800329}
330
331static int gsm411_send_rp_error(struct gsm_lchan *lchan, u_int8_t trans_id,
332 u_int8_t msg_ref, u_int8_t cause)
333{
334 struct msgb *msg = gsm411_msgb_alloc();
Harald Welte59b04682009-06-10 05:40:52 +0800335
336 msg->lchan = lchan;
337
Harald Welte59b04682009-06-10 05:40:52 +0800338 msgb_tv_put(msg, 1, cause);
339
340 DEBUGP(DSMS, "TX: SMS RP ERROR (cause %02d)\n", cause);
341
Harald Welte7e2f57d2009-07-04 17:39:00 +0200342 return gsm411_rp_sendmsg(msg, GSM411_MT_RP_ERROR_MT, msg_ref, trans_id);
Harald Welte59b04682009-06-10 05:40:52 +0800343}
344
345/* Receive a 04.11 TPDU inside RP-DATA / user data */
346static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm411_rp_hdr *rph,
347 u_int8_t src_len, u_int8_t *src,
348 u_int8_t dst_len, u_int8_t *dst,
349 u_int8_t tpdu_len, u_int8_t *tpdu)
350{
351 struct gsm48_hdr *gh = msgb_l3(msg);
352 u_int8_t trans_id = gh->proto_discr >> 4;
353 int rc = 0;
354
355 if (src_len && src)
356 DEBUGP(DSMS, "RP-DATA (MO) with SRC ?!?\n");
357
358 if (!dst_len || !dst || !tpdu_len || !tpdu) {
359 DEBUGP(DSMS, "RP-DATA (MO) without DST or TPDU ?!?\n");
360 return -EIO;
361 }
362 msg->smsh = tpdu;
363
364 DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
365 //return gsm411_send_rp_error(msg->lchan, trans_id, rph->msg_ref, rc);
366
367 rc = gsm340_rx_tpdu(msg);
368 if (rc == 0)
369 return gsm411_send_rp_ack(msg->lchan, trans_id, rph->msg_ref);
370 else if (rc > 0)
371 return gsm411_send_rp_error(msg->lchan, trans_id, rph->msg_ref, rc);
372 else
373 return rc;
374}
375
376/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
377static int gsm411_rx_rp_data(struct msgb *msg, struct gsm411_rp_hdr *rph)
378{
379 u_int8_t src_len, dst_len, rpud_len;
380 u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
381
382 /* in the MO case, this should always be zero length */
383 src_len = rph->data[0];
384 if (src_len)
385 src = &rph->data[1];
386
387 dst_len = rph->data[1+src_len];
388 if (dst_len)
389 dst = &rph->data[1+src_len+1];
390
391 rpud_len = rph->data[1+src_len+1+dst_len];
392 if (rpud_len)
393 rp_ud = &rph->data[1+src_len+1+dst_len+1];
394
395 DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n", src_len, dst_len, rpud_len);
396 return gsm411_rx_rp_ud(msg, rph, src_len, src, dst_len, dst,
397 rpud_len, rp_ud);
398}
399
400static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh)
401{
402 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
403 u_int8_t msg_type = rp_data->msg_type & 0x07;
404 int rc = 0;
405
406 switch (msg_type) {
407 case GSM411_MT_RP_DATA_MO:
408 DEBUGP(DSMS, "SMS RP-DATA (MO)\n");
409 rc = gsm411_rx_rp_data(msg, rp_data);
410 break;
411 case GSM411_MT_RP_ACK_MO:
412 /* Acnkowledgement to MT RP_DATA */
413 case GSM411_MT_RP_ERROR_MO:
414 /* Error in response to MT RP_DATA */
415 case GSM411_MT_RP_SMMA_MO:
416 /* MS tells us that it has memory for more SMS, we need
417 * to check if we have any pending messages for it and then
418 * transfer those */
419 DEBUGP(DSMS, "Unimplemented RP type 0x%02x\n", msg_type);
420 break;
421 default:
422 DEBUGP(DSMS, "Invalid RP type 0x%02x\n", msg_type);
423 break;
424 }
425
426 return rc;
427}
428
429int gsm0411_rcv_sms(struct msgb *msg)
430{
431 struct gsm48_hdr *gh = msgb_l3(msg);
432 u_int8_t msg_type = gh->msg_type;
433 int rc = 0;
434
435 switch(msg_type) {
436 case GSM411_MT_CP_DATA:
437 DEBUGP(DSMS, "SMS CP-DATA\n");
438 rc = gsm411_rx_cp_data(msg, gh);
439 break;
440 case GSM411_MT_CP_ACK:
441 DEBUGP(DSMS, "SMS CP-ACK\n");
442 break;
443 case GSM411_MT_CP_ERROR:
444 DEBUGP(DSMS, "SMS CP-ERROR, cause 0x%02x\n", gh->data[0]);
445 break;
446 default:
447 DEBUGP(DSMS, "Unimplemented CP msg_type: 0x%02x\n", msg_type);
448 break;
449 }
450
451
452 return rc;
453}
454
455/* Test TPDU - 25c3 welcome */
456#if 0
457static u_int8_t tpdu_test[] = {
458 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x92, 0x90, 0x32,
459 0x24, 0x40, 0x4D, 0xB2, 0xDA, 0x70, 0xD6, 0x9A, 0x97, 0xE5, 0xF6, 0xF4,
460 0xB8, 0x0C, 0x0A, 0xBB, 0xDD, 0xEF, 0xBA, 0x7B, 0x5C, 0x6E, 0x97, 0xDD,
461 0x74, 0x1D, 0x08, 0xCA, 0x2E, 0x87, 0xE7, 0x65, 0x50, 0x98, 0x4E, 0x2F,
462 0xBB, 0xC9, 0x20, 0x3A, 0xBA, 0x0C, 0x3A, 0x4E, 0x9B, 0x20, 0x7A, 0x98,
463 0xBD, 0x06, 0x85, 0xE9, 0xA0, 0x58, 0x4C, 0x37, 0x83, 0x81, 0xD2, 0x6E,
464 0xD0, 0x34, 0x1C, 0x66, 0x83, 0x62, 0x21, 0x90, 0xAE, 0x95, 0x02
465};
466#else
467/* Test TPDU - ALL YOUR */
468static u_int8_t tpdu_test[] = {
469 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
470 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
471 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
472 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
473};
474#endif
475
476int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms)
477{
478 struct msgb *msg = gsm411_msgb_alloc();
Harald Welte59b04682009-06-10 05:40:52 +0800479 u_int8_t *data;
Harald Welte7e2f57d2009-07-04 17:39:00 +0200480 u_int8_t msg_ref = 42;
481 u_int8_t trans_id = 23;
Harald Welte59b04682009-06-10 05:40:52 +0800482
483 msg->lchan = lchan;
484
Harald Welte7e2f57d2009-07-04 17:39:00 +0200485 /* Hardcode Originating Address for now */
Harald Welte59b04682009-06-10 05:40:52 +0800486 data = (u_int8_t *)msgb_put(msg, 8);
Harald Welte7e2f57d2009-07-04 17:39:00 +0200487 data[0] = 0x07; /* originator length == 7 */
488 data[1] = 0x91; /* type of number */
Harald Welte59b04682009-06-10 05:40:52 +0800489 data[2] = 0x44;
490 data[3] = 0x77;
491 data[4] = 0x58;
492 data[5] = 0x10;
493 data[6] = 0x06;
494 data[7] = 0x50;
Harald Welte7e2f57d2009-07-04 17:39:00 +0200495
496 /* Hardcoded Destination Address */
Harald Welte59b04682009-06-10 05:40:52 +0800497 data = (u_int8_t *)msgb_put(msg, 1);
Harald Welte7e2f57d2009-07-04 17:39:00 +0200498 data[0] = 0; /* destination length == 0 */
Harald Welte59b04682009-06-10 05:40:52 +0800499
500 /* FIXME: Hardcoded for now */
501 //smslen = gsm0411_tpdu_from_sms(tpdu, sms);
502
503 /* RPDU length */
504 data = (u_int8_t *)msgb_put(msg, 1);
505 data[0] = sizeof(tpdu_test);
506
507 data = (u_int8_t *)msgb_put(msg, sizeof(tpdu_test));
508
509 //memcpy(data, tpdu, smslen);
510 memcpy(data, tpdu_test, sizeof(tpdu_test));
511
512 DEBUGP(DSMS, "TX: SMS SUBMIT\n");
513
Harald Welte7e2f57d2009-07-04 17:39:00 +0200514 return gsm411_rp_sendmsg(msg, GSM411_MT_RP_DATA_MT, msg_ref, trans_id);
Harald Welte59b04682009-06-10 05:40:52 +0800515}