blob: 1260eee1c316ef8e7eb0f6f0907d6878cb314aba [file] [log] [blame]
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001/* 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>
Harald Welte7e310b12009-03-30 20:56:32 +00006 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
Daniel Willmann8b3390e2008-12-28 00:31:09 +00007 *
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>
Harald Weltef3efc592009-07-27 20:11:35 +020031#include <time.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000032#include <netinet/in.h>
33
34#include <openbsc/msgb.h>
Harald Welte7e310b12009-03-30 20:56:32 +000035#include <openbsc/tlv.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000036#include <openbsc/debug.h>
Daniel Willmann471712b2008-12-29 01:54:02 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/gsm_subscriber.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000039#include <openbsc/gsm_04_11.h>
40#include <openbsc/gsm_04_08.h>
Holger Freyther76c95692009-02-17 20:31:30 +000041#include <openbsc/gsm_utils.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000042#include <openbsc/abis_rsl.h>
Holger Freyther9b177762009-02-16 19:07:18 +000043#include <openbsc/signal.h>
Harald Welte7e310b12009-03-30 20:56:32 +000044#include <openbsc/db.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020045#include <openbsc/talloc.h>
Harald Weltef3efc592009-07-27 20:11:35 +020046#include <openbsc/transaction.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000047
Daniel Willmann471712b2008-12-29 01:54:02 +000048#define GSM411_ALLOC_SIZE 1024
49#define GSM411_ALLOC_HEADROOM 128
50
Harald Welte2cf161b2009-06-20 22:36:41 +020051static void *tall_sms_ctx;
52static void *tall_gsms_ctx;
53
Harald Weltef3efc592009-07-27 20:11:35 +020054static u_int32_t new_callref = 0x40000001;
55
Holger Freythera553d092009-01-04 20:16:25 +000056struct msgb *gsm411_msgb_alloc(void)
Daniel Willmann471712b2008-12-29 01:54:02 +000057{
Harald Welte966636f2009-06-26 19:39:35 +020058 return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
59 "GSM 04.11");
Daniel Willmann471712b2008-12-29 01:54:02 +000060}
61
Harald Welte87f5d632009-07-04 17:39:00 +020062static int gsm411_sendmsg(struct msgb *msg)
Daniel Willmann471712b2008-12-29 01:54:02 +000063{
64 if (msg->lchan)
65 msg->trx = msg->lchan->ts->trx;
66
67 msg->l3h = msg->data;
68
69 return rsl_data_request(msg, 0);
70}
71
Harald Welte87f5d632009-07-04 17:39:00 +020072/* Prefix msg with a 04.08/04.11 CP header */
Harald Weltef3efc592009-07-27 20:11:35 +020073static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
74 u_int8_t msg_type)
Harald Welte87f5d632009-07-04 17:39:00 +020075{
76 struct gsm48_hdr *gh;
77
78 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
79 /* Outgoing needs the highest bit set */
Harald Weltef3efc592009-07-27 20:11:35 +020080 gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
Harald Welte87f5d632009-07-04 17:39:00 +020081 gh->msg_type = msg_type;
82
Harald Weltef3efc592009-07-27 20:11:35 +020083 /* assign the outgoing lchan */
84 msg->lchan = trans->lchan;
85
86 /* mobile originating */
87 switch (gh->msg_type) {
88 case GSM411_MT_CP_DATA:
89 /* 5.2.3.1.2: enter MO-wait for CP-ack */
90 trans->sms.cp_state = GSM411_CPS_WAIT_CP_ACK;
91 break;
92 }
93
Harald Welte87f5d632009-07-04 17:39:00 +020094 return gsm411_sendmsg(msg);
95}
96
97/* Prefix msg with a RP-DATA header and send as CP-DATA */
Harald Weltef3efc592009-07-27 20:11:35 +020098static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
99 u_int8_t rp_msg_type, u_int8_t rp_msg_ref)
Harald Welte87f5d632009-07-04 17:39:00 +0200100{
101 struct gsm411_rp_hdr *rp;
102
103 /* GSM 04.11 RP-DATA header */
104 rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
105 rp->len = msg->len;
106 rp->msg_type = rp_msg_type;
107 rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */
108
Harald Weltef3efc592009-07-27 20:11:35 +0200109 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA);
Harald Welte87f5d632009-07-04 17:39:00 +0200110}
111
Holger Freytherca362a62009-01-04 21:05:01 +0000112#if 0
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000113static u_int8_t gsm0411_tpdu_from_sms(u_int8_t *tpdu, struct sms_deliver *sms)
114{
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000115}
Holger Freytherca362a62009-01-04 21:05:01 +0000116#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000117
Harald Welte7e310b12009-03-30 20:56:32 +0000118static unsigned long gsm340_validity_period(struct sms_submit *sms)
119{
120 u_int8_t vp;
121 unsigned long minutes;
122
123 switch (sms->vpf) {
124 case GSM340_TP_VPF_RELATIVE:
125 /* Chapter 9.2.3.12.1 */
126 vp = *(sms->vp);
127 if (vp <= 143)
128 minutes = vp + 1 * 5;
129 else if (vp <= 167)
130 minutes = 12*60 + (vp-143) * 30;
131 else if (vp <= 196)
132 minutes = vp-166 * 60 * 24;
133 else
134 minutes = vp-192 * 60 * 24 * 7;
135 break;
136 case GSM340_TP_VPF_ABSOLUTE:
137 /* Chapter 9.2.3.12.2 */
138 /* FIXME: like service center time stamp */
139 DEBUGP(DSMS, "VPI absolute not implemented yet\n");
140 break;
141 case GSM340_TP_VPF_ENHANCED:
142 /* Chapter 9.2.3.12.3 */
143 /* FIXME: implementation */
144 DEBUGP(DSMS, "VPI enhanced not implemented yet\n");
145 break;
146 }
147 return minutes;
148}
149
150/* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */
151enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
152{
153 u_int8_t cgbits = dcs >> 4;
154 enum sms_alphabet alpha = DCS_NONE;
155
156 if ((cgbits & 0xc) == 0) {
157 if (cgbits & 2)
158 DEBUGP(DSMS, "Compressed SMS not supported yet\n");
159
160 switch (dcs & 3) {
161 case 0:
162 alpha = DCS_7BIT_DEFAULT;
163 break;
164 case 1:
165 alpha = DCS_8BIT_DATA;
166 break;
167 case 2:
168 alpha = DCS_UCS2;
169 break;
170 }
171 } else if (cgbits == 0xc || cgbits == 0xd)
172 alpha = DCS_7BIT_DEFAULT;
173 else if (cgbits == 0xe)
174 alpha = DCS_UCS2;
175 else if (cgbits == 0xf) {
176 if (dcs & 4)
177 alpha = DCS_8BIT_DATA;
178 else
179 alpha = DCS_7BIT_DEFAULT;
180 }
181
182 return alpha;
183}
184
185static int gsm340_rx_sms_submit(struct msgb *msg, struct sms_submit *sms,
186 struct gsm_sms *gsms)
187{
188 if (db_sms_store(gsms) != 0) {
189 DEBUGP(DSMS, "Failed to store SMS in Database\n");
Harald Welteb9c758b2009-07-05 14:02:46 +0200190 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000191 }
192 return 0;
193}
194
Harald Weltef3efc592009-07-27 20:11:35 +0200195static int gsm340_gen_oa(u_int8_t *oa, struct gsm_subscriber *subscr)
196{
197 int len = 0;
198
199}
200
201static u_int8_t bcdify(u_int8_t value)
202{
203 u_int8_t ret;
204
205 ret = value % 10;
206 ret |= (value / 10) << 4;
207
208 return ret;
209}
210
211/* Generate 03.40 TP-SCTS */
212static void gsm340_gen_scts(u_int8_t *scts, time_t time)
213{
214 struct tm *tm = localtime(&time);
215 u_int8_t digit;
216
217 *scts++ = bcdify(tm->tm_year % 100);
218 *scts++ = bcdify(tm->tm_mon);
219 *scts++ = bcdify(tm->tm_mday);
220 *scts++ = bcdify(tm->tm_hour);
221 *scts++ = bcdify(tm->tm_min);
222 *scts++ = bcdify(tm->tm_sec);
223 *scts++ = 0; /* FIXME: timezone */
224}
225
226static struct msgb *gsm340_gen_tpdu(struct gsm_sms *sms)
227{
228 struct msgb *msg = gsm411_msgb_alloc();
229 u_int8_t *smsp;
230 u_int8_t oa[12]; /* max len per 03.40 */
231 u_int8_t oa_len = 0;
232
233 /* generate first octet with masked bits */
234 smsp = msgb_put(msg, 1);
235 *smsp = GSM340_SMS_DELIVER_SC2MS;
236 if (0 /* FIXME: MMS */)
237 *smsp |= 0x04;
238 /* two bits empty */
239 if (sms->status_rep_req)
240 *smsp |= 0x20;
241#if 0
242 if (sms->header_len)
243 *smsp |= 0x40;
244 if (sms->
245 *smsp |= 0x80;
246#endif
247
248 /* generate originator address */
249 smsp = msgb_put(msg, oa_len);
250 oa_len = gsm340_gen_oa(&oa, sms->sender);
251 memcpy(smsp, oa, oa_len);
252
253 /* generate TP-PID */
254 smsp = msgb_put(msg, 1);
255 *smsp = sms->protocol_id;
256
257 /* generate TP-DCS */
258 smsp = msgb_put(msg, 1);
259 *smsp = sms->data_coding_scheme;
260
261 /* generate TP-SCTS */
262 smsp = msgb_put(msg, 7);
263 gsm340_gen_scts(smsp, time(NULL));
264#if 0
265 /* generate TP-UDL */
266 smsp = msgb_put(msg, 1);
267 *smsp = ud_len;
268
269 /* generate TP-UD */
270 smsp = msgb_put(msg, ud_len);
271 memcpy(smsp, FIXME, ud_len);
272#endif
273
274 return msg;
275}
276
Harald Welteb9c758b2009-07-05 14:02:46 +0200277/* process an incoming TPDU (called from RP-DATA)
278 * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
Harald Welte7e310b12009-03-30 20:56:32 +0000279static int gsm340_rx_tpdu(struct msgb *msg)
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000280{
Harald Welte9176bd42009-07-23 18:46:00 +0200281 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000282 u_int8_t *smsp = msgb_sms(msg);
283 struct sms_submit *sms;
Harald Welte7e310b12009-03-30 20:56:32 +0000284 struct gsm_sms *gsms;
285 u_int8_t da_len_bytes;
286 u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
287 int rc = 0;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000288
Harald Welte2cf161b2009-06-20 22:36:41 +0200289 if (!tall_sms_ctx)
290 tall_sms_ctx = talloc_named_const(tall_bsc_ctx, 1,
291 "sms_submit");
292
293 sms = talloc(tall_sms_ctx, struct sms_submit);
Harald Welte7e310b12009-03-30 20:56:32 +0000294 if (!sms)
Harald Welteb9c758b2009-07-05 14:02:46 +0200295 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000296 memset(sms, 0, sizeof(*sms));
297
Harald Welte2cf161b2009-06-20 22:36:41 +0200298 if (!tall_gsms_ctx)
299 tall_gsms_ctx = talloc_named_const(tall_bsc_ctx, 1,
300 "sms");
301
302 gsms = talloc(tall_gsms_ctx, struct gsm_sms);
Harald Welte7e310b12009-03-30 20:56:32 +0000303 if (!gsms) {
Harald Welte2cf161b2009-06-20 22:36:41 +0200304 talloc_free(sms);
Harald Welteb9c758b2009-07-05 14:02:46 +0200305 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000306 }
307 memset(gsms, 0, sizeof(*gsms));
308
309 /* invert those fields where 0 means active/present */
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000310 sms->mti = *smsp & 0x03;
311 sms->mms = !!(*smsp & 0x04);
312 sms->vpf = (*smsp & 0x18) >> 3;
Harald Weltef3efc592009-07-27 20:11:35 +0200313 sms->srr = (*smsp & 0x20);
314 sms->udhi= (*smsp & 0x40);
315 sms->rp = (*smsp & 0x80);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000316
317 smsp++;
318 sms->msg_ref = *smsp++;
319
Harald Welte7e310b12009-03-30 20:56:32 +0000320 /* length in bytes of the destination address */
321 da_len_bytes = 2 + *smsp/2 + *smsp%2;
322 if (da_len_bytes > 12) {
323 DEBUGP(DSMS, "Destination Address > 12 bytes ?!?\n");
Harald Welteb9c758b2009-07-05 14:02:46 +0200324 rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
Harald Welte7e310b12009-03-30 20:56:32 +0000325 goto out;
326 }
Harald Welte3cfdb222009-06-12 02:42:11 +0800327 memset(address_lv, 0, sizeof(address_lv));
Harald Welte7e310b12009-03-30 20:56:32 +0000328 memcpy(address_lv, smsp, da_len_bytes);
329 /* mangle first byte to reflect length in bytes, not digits */
Harald Welte3cfdb222009-06-12 02:42:11 +0800330 address_lv[0] = da_len_bytes - 1;
Harald Welte7e310b12009-03-30 20:56:32 +0000331 /* convert to real number */
Harald Welte3cfdb222009-06-12 02:42:11 +0800332 decode_bcd_number(sms->dest_addr, sizeof(sms->dest_addr), address_lv, 1);
Harald Welte7e310b12009-03-30 20:56:32 +0000333
334 smsp += da_len_bytes;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000335
336 sms->pid = *smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000337
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000338 sms->dcs = *smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000339 sms->alphabet = gsm338_get_sms_alphabet(sms->dcs);
340
341 switch (sms->vpf) {
342 case GSM340_TP_VPF_RELATIVE:
343 sms->vp = smsp++;
344 break;
345 case GSM340_TP_VPF_ABSOLUTE:
346 case GSM340_TP_VPF_ENHANCED:
347 sms->vp = smsp;
348 smsp += 7;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000349 break;
350 default:
351 DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n",
352 sms->vpf);
353 }
354 sms->ud_len = *smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000355 if (sms->ud_len)
356 sms->user_data = smsp;
357 else
358 sms->user_data = NULL;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000359
Harald Welte7e310b12009-03-30 20:56:32 +0000360 if (sms->ud_len) {
361 switch (sms->alphabet) {
362 case DCS_7BIT_DEFAULT:
363 gsm_7bit_decode(sms->decoded, smsp, sms->ud_len);
364 break;
365 case DCS_8BIT_DATA:
366 case DCS_UCS2:
367 case DCS_NONE:
368 memcpy(sms->decoded, sms->user_data, sms->ud_len);
369 break;
370 }
371 }
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000372
Harald Welte7e310b12009-03-30 20:56:32 +0000373 DEBUGP(DSMS, "SMS:\nMTI: 0x%02x, VPF: 0x%02x, MR: 0x%02x "
374 "PID: 0x%02x, DCS: 0x%02x, DA: %s, UserDataLength: 0x%02x "
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000375 "UserData: \"%s\"\n", sms->mti, sms->vpf, sms->msg_ref,
Harald Welte7e310b12009-03-30 20:56:32 +0000376 sms->pid, sms->dcs, sms->dest_addr, sms->ud_len,
Harald Welteb9c758b2009-07-05 14:02:46 +0200377 sms->alphabet == DCS_7BIT_DEFAULT ? sms->decoded :
378 hexdump(sms->user_data, sms->ud_len));
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000379
Harald Welte595ad7b2009-02-16 22:05:44 +0000380 dispatch_signal(SS_SMS, 0, sms);
Holger Freyther9b177762009-02-16 19:07:18 +0000381
Harald Welteb9c758b2009-07-05 14:02:46 +0200382 /* now we've filled the 'sms' structure. Go on filling
383 * the gsms structure based on information from the sms */
384
Harald Welte7e310b12009-03-30 20:56:32 +0000385 gsms->sender = msg->lchan->subscr;
386 /* FIXME: sender refcount */
387
Harald Welteb9c758b2009-07-05 14:02:46 +0200388 gsms->validity_minutes = gsm340_validity_period(sms);
389
Harald Welte7e310b12009-03-30 20:56:32 +0000390 /* determine gsms->receiver based on dialled number */
Harald Welte9176bd42009-07-23 18:46:00 +0200391 gsms->receiver = subscr_get_by_extension(bts->network, sms->dest_addr);
Harald Welte7e310b12009-03-30 20:56:32 +0000392 if (!gsms->receiver) {
393 rc = 1; /* cause 1: unknown subscriber */
394 goto out;
395 }
396
Harald Weltef3efc592009-07-27 20:11:35 +0200397 if (sms->user_data) {
398 gsms->header_len = sms->ud_len;
Harald Welteb9c758b2009-07-05 14:02:46 +0200399 memcpy(gsms->header, sms->user_data, sms->ud_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200400 }
Harald Welteb9c758b2009-07-05 14:02:46 +0200401
402 if (sms->decoded)
Harald Welte7e310b12009-03-30 20:56:32 +0000403 strncpy(gsms->text, sms->decoded, sizeof(gsms->text));
404
405 switch (sms->mti) {
406 case GSM340_SMS_SUBMIT_MS2SC:
407 /* MS is submitting a SMS */
408 rc = gsm340_rx_sms_submit(msg, sms, gsms);
409 break;
410 case GSM340_SMS_COMMAND_MS2SC:
411 case GSM340_SMS_DELIVER_REP_MS2SC:
412 DEBUGP(DSMS, "Unimplemented MTI 0x%02x\n", sms->mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200413 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000414 break;
415 default:
416 DEBUGP(DSMS, "Undefined MTI 0x%02x\n", sms->mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200417 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000418 break;
419 }
420
Harald Welteb9c758b2009-07-05 14:02:46 +0200421 if (!rc && !gsms->receiver)
422 rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
423
Harald Welte7e310b12009-03-30 20:56:32 +0000424out:
Harald Welte2cf161b2009-06-20 22:36:41 +0200425 talloc_free(gsms);
426 talloc_free(sms);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000427
Harald Welte7e310b12009-03-30 20:56:32 +0000428 return rc;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000429}
430
Harald Weltef3efc592009-07-27 20:11:35 +0200431static int gsm411_send_rp_ack(struct gsm_trans *trans, u_int8_t msg_ref)
Daniel Willmann471712b2008-12-29 01:54:02 +0000432{
433 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000434
Daniel Willmann471712b2008-12-29 01:54:02 +0000435 DEBUGP(DSMS, "TX: SMS RP ACK\n");
436
Harald Weltef3efc592009-07-27 20:11:35 +0200437 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ACK_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000438}
439
Harald Weltef3efc592009-07-27 20:11:35 +0200440static int gsm411_send_rp_error(struct gsm_trans *trans,
441 u_int8_t msg_ref, u_int8_t cause)
Daniel Willmann471712b2008-12-29 01:54:02 +0000442{
443 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000444
Harald Welte7e310b12009-03-30 20:56:32 +0000445 msgb_tv_put(msg, 1, cause);
Daniel Willmann471712b2008-12-29 01:54:02 +0000446
Harald Welte7e310b12009-03-30 20:56:32 +0000447 DEBUGP(DSMS, "TX: SMS RP ERROR (cause %02d)\n", cause);
Daniel Willmann471712b2008-12-29 01:54:02 +0000448
Harald Weltef3efc592009-07-27 20:11:35 +0200449 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000450}
451
Harald Welte7e310b12009-03-30 20:56:32 +0000452/* Receive a 04.11 TPDU inside RP-DATA / user data */
Harald Weltef3efc592009-07-27 20:11:35 +0200453static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
454 struct gsm411_rp_hdr *rph,
Harald Welte7e310b12009-03-30 20:56:32 +0000455 u_int8_t src_len, u_int8_t *src,
456 u_int8_t dst_len, u_int8_t *dst,
457 u_int8_t tpdu_len, u_int8_t *tpdu)
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000458{
459 struct gsm48_hdr *gh = msgb_l3(msg);
460 int rc = 0;
461
Harald Welte7e310b12009-03-30 20:56:32 +0000462 if (src_len && src)
463 DEBUGP(DSMS, "RP-DATA (MO) with SRC ?!?\n");
464
465 if (!dst_len || !dst || !tpdu_len || !tpdu) {
466 DEBUGP(DSMS, "RP-DATA (MO) without DST or TPDU ?!?\n");
Harald Weltef3efc592009-07-27 20:11:35 +0200467 gsm411_send_rp_error(trans, rph->msg_ref,
Harald Welteb9c758b2009-07-05 14:02:46 +0200468 GSM411_RP_CAUSE_INV_MAND_INF);
Harald Welte7e310b12009-03-30 20:56:32 +0000469 return -EIO;
470 }
471 msg->smsh = tpdu;
472
473 DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
Harald Welte7e310b12009-03-30 20:56:32 +0000474
475 rc = gsm340_rx_tpdu(msg);
476 if (rc == 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200477 return gsm411_send_rp_ack(trans, rph->msg_ref);
Harald Welte7e310b12009-03-30 20:56:32 +0000478 else if (rc > 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200479 return gsm411_send_rp_error(trans, rph->msg_ref, rc);
Harald Welte7e310b12009-03-30 20:56:32 +0000480 else
481 return rc;
482}
483
484/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
Harald Weltef3efc592009-07-27 20:11:35 +0200485static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
486 struct gsm411_rp_hdr *rph)
Harald Welte7e310b12009-03-30 20:56:32 +0000487{
488 u_int8_t src_len, dst_len, rpud_len;
489 u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
490
491 /* in the MO case, this should always be zero length */
492 src_len = rph->data[0];
493 if (src_len)
494 src = &rph->data[1];
495
496 dst_len = rph->data[1+src_len];
497 if (dst_len)
498 dst = &rph->data[1+src_len+1];
499
500 rpud_len = rph->data[1+src_len+1+dst_len];
501 if (rpud_len)
502 rp_ud = &rph->data[1+src_len+1+dst_len+1];
503
Harald Welteb9c758b2009-07-05 14:02:46 +0200504 DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
505 src_len, dst_len, rpud_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200506 return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst,
Harald Welte7e310b12009-03-30 20:56:32 +0000507 rpud_len, rp_ud);
508}
509
Harald Welteb9c758b2009-07-05 14:02:46 +0200510
Harald Weltef3efc592009-07-27 20:11:35 +0200511static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
512 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200513{
514 /* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
515 * successfully received a SMS. We can now safely mark it as
516 * transmitted */
517
Harald Welte3e0f6172009-07-09 23:52:59 +0200518 /* we need to look-up the transaction based on rph->msg_ref to
519 * identify which particular RP_DATA/SMS-submit was ACKed */
520
Harald Welteb9c758b2009-07-05 14:02:46 +0200521}
522
Harald Weltef3efc592009-07-27 20:11:35 +0200523static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
524 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200525{
Harald Weltef3efc592009-07-27 20:11:35 +0200526 u_int8_t cause_len = rph->data[0];
527 u_int8_t cause = rph->data[1];
528
Harald Welteb9c758b2009-07-05 14:02:46 +0200529 /* Error in response to MT RP_DATA, i.e. the MS did not
530 * successfully receive the SMS. We need to investigate
531 * the cause and take action depending on it */
532
Harald Weltef3efc592009-07-27 20:11:35 +0200533 DEBUGP(DSMS, "RX SMS RP-ERROR Cause=0x%02x\n", cause);
534
Harald Welte3e0f6172009-07-09 23:52:59 +0200535 /* we need to look-up the transaction based on rph->msg_ref to
536 * identify which particular RP_DATA/SMS-submit failed */
537
Harald Weltef3efc592009-07-27 20:11:35 +0200538 return 0;
Harald Welteb9c758b2009-07-05 14:02:46 +0200539}
540
Harald Weltef3efc592009-07-27 20:11:35 +0200541static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans,
542 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200543{
Harald Weltef3efc592009-07-27 20:11:35 +0200544 int rc;
545
Harald Welteb9c758b2009-07-05 14:02:46 +0200546 /* MS tells us that it has memory for more SMS, we need
547 * to check if we have any pending messages for it and then
548 * transfer those */
Harald Weltef3efc592009-07-27 20:11:35 +0200549
550 rc = gsm411_send_rp_ack(trans, rph->msg_ref);
551 trans->sms.rp_state = GSM411_RPS_IDLE;
552
553 return rc;
Harald Welteb9c758b2009-07-05 14:02:46 +0200554}
555
Harald Weltef3efc592009-07-27 20:11:35 +0200556static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
557 struct gsm_trans *trans)
Harald Welte7e310b12009-03-30 20:56:32 +0000558{
Daniel Willmann471712b2008-12-29 01:54:02 +0000559 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000560 u_int8_t msg_type = rp_data->msg_type & 0x07;
Harald Welte7e310b12009-03-30 20:56:32 +0000561 int rc = 0;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000562
563 switch (msg_type) {
564 case GSM411_MT_RP_DATA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200565 DEBUGP(DSMS, "RX SMS RP-DATA (MO)\n");
566 /* start TR2N and enter 'wait to send RP-ACK state' */
567 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
568 rc = gsm411_rx_rp_data(msg, trans, rp_data);
Harald Welte7e310b12009-03-30 20:56:32 +0000569 break;
570 case GSM411_MT_RP_ACK_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200571 DEBUGP(DSMS,"RX SMS RP-ACK (MO)\n");
572 rc = gsm411_rx_rp_ack(msg, trans, rp_data);
Harald Welteb9c758b2009-07-05 14:02:46 +0200573 break;
Harald Welte7e310b12009-03-30 20:56:32 +0000574 case GSM411_MT_RP_SMMA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200575 DEBUGP(DSMS, "RX SMS RP-SMMA\n");
576 /* start TR2N and enter 'wait to send RP-ACK state' */
577 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
578 rc = gsm411_rx_rp_smma(msg, trans, rp_data);
579 break;
580 case GSM411_MT_RP_ERROR_MO:
581 rc = gsm411_rx_rp_error(msg, trans, rp_data);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000582 break;
583 default:
Harald Welte7e310b12009-03-30 20:56:32 +0000584 DEBUGP(DSMS, "Invalid RP type 0x%02x\n", msg_type);
Harald Weltef3efc592009-07-27 20:11:35 +0200585 rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
586 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000587 break;
588 }
589
590 return rc;
591}
592
Harald Weltef3efc592009-07-27 20:11:35 +0200593/* send CP-ACK to given transaction */
594static int gsm411_tx_cp_ack(struct gsm_trans *trans)
595{
596 struct msgb *msg = gsm411_msgb_alloc();
597
598 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ACK);
599}
600
601static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
602{
603 struct msgb *msg = gsm411_msgb_alloc();
604 u_int8_t *causep;
605
606 cause = msgb_put(msg, 1);
607 *causep = cause;
608
609 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ERROR);
610}
611
612/* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000613int gsm0411_rcv_sms(struct msgb *msg)
614{
615 struct gsm48_hdr *gh = msgb_l3(msg);
616 u_int8_t msg_type = gh->msg_type;
Harald Weltef3efc592009-07-27 20:11:35 +0200617 u_int8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
618 struct gsm_lchan *lchan = msg->lchan;
619 struct gsm_trans *trans;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000620 int rc = 0;
621
Harald Weltef3efc592009-07-27 20:11:35 +0200622 if (!lchan->subscr)
623 return -EIO;
624 /* FIXME: send some error message */
625
626 trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS,
627 transaction_id);
628 if (!trans) {
629 DEBUGP(DSMS, "Unknown transaction ID %x, "
630 "creating new trans\n", transaction_id);
631 trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
632 transaction_id, new_callref++);
633 if (!trans) {
634 DEBUGP(DSMS, "No memory for trans\n");
635 /* FIXME: send some error message */
636 return -ENOMEM;
637 }
638 trans->sms.cp_state = GSM411_CPS_IDLE;
639 trans->sms.rp_state = GSM411_RPS_IDLE;
640 trans->sms.is_mt = 0;
641
642 trans->lchan = lchan;
643 use_lchan(lchan);
644 }
645
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000646 switch(msg_type) {
647 case GSM411_MT_CP_DATA:
Harald Weltef3efc592009-07-27 20:11:35 +0200648 DEBUGP(DSMS, "RX SMS CP-DATA\n");
649 if (!trans->sms.is_mt) {
650 /* 5.2.3.1.3: MO state exists when SMC has received
651 * CP-DATA, including sending of the assoc. CP-ACK */
652 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
653 }
654
655 rc = gsm411_rx_cp_data(msg, gh, trans);
656 /* Send CP-ACK or CP-ERORR in response */
657 if (rc < 0) {
658 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_NET_FAIL);
659 } else
660 rc = gsm411_tx_cp_ack(trans);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000661 break;
662 case GSM411_MT_CP_ACK:
Harald Weltef3efc592009-07-27 20:11:35 +0200663 /* previous CP-DATA in this transaction was confirmed */
664 DEBUGP(DSMS, "RX SMS CP-ACK\n");
665 if (!trans->sms.is_mt) {
666 /* 5.2.3.1.3: MO state exists when SMC has received
667 * CP-ACK */
668 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
669 /* FIXME: we have sont one CP-DATA, which was now
670 * acknowledged. Check if we want to transfer more,
671 * i.e. multi-part message */
672 trans->sms.cp_state = GSM411_CPS_IDLE;
673 trans_free(trans);
674 }
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000675 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000676 case GSM411_MT_CP_ERROR:
Harald Weltef3efc592009-07-27 20:11:35 +0200677 DEBUGP(DSMS, "RX SMS CP-ERROR, cause 0x%02x\n", gh->data[0]);
678 trans->sms.cp_state = GSM411_CPS_IDLE;
679 trans_free(trans);
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000680 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000681 default:
Harald Weltef3efc592009-07-27 20:11:35 +0200682 DEBUGP(DSMS, "RX Unimplemented CP msg_type: 0x%02x\n", msg_type);
683 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
684 trans_free(trans);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000685 break;
686 }
687
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000688 return rc;
689}
690
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000691/* Test TPDU - 25c3 welcome */
Harald Welte8c2e36e2008-12-30 15:00:14 +0000692#if 0
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000693static u_int8_t tpdu_test[] = {
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000694 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x92, 0x90, 0x32,
695 0x24, 0x40, 0x4D, 0xB2, 0xDA, 0x70, 0xD6, 0x9A, 0x97, 0xE5, 0xF6, 0xF4,
696 0xB8, 0x0C, 0x0A, 0xBB, 0xDD, 0xEF, 0xBA, 0x7B, 0x5C, 0x6E, 0x97, 0xDD,
697 0x74, 0x1D, 0x08, 0xCA, 0x2E, 0x87, 0xE7, 0x65, 0x50, 0x98, 0x4E, 0x2F,
698 0xBB, 0xC9, 0x20, 0x3A, 0xBA, 0x0C, 0x3A, 0x4E, 0x9B, 0x20, 0x7A, 0x98,
699 0xBD, 0x06, 0x85, 0xE9, 0xA0, 0x58, 0x4C, 0x37, 0x83, 0x81, 0xD2, 0x6E,
700 0xD0, 0x34, 0x1C, 0x66, 0x83, 0x62, 0x21, 0x90, 0xAE, 0x95, 0x02
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000701};
Harald Welte8c2e36e2008-12-30 15:00:14 +0000702#else
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000703/* Test TPDU - ALL YOUR */
704static u_int8_t tpdu_test[] = {
705 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
706 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
707 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
708 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
Daniel Willmanne2a728d2008-12-30 14:03:09 +0000709};
Harald Welte8c2e36e2008-12-30 15:00:14 +0000710#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000711
712int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms)
713{
714 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltef3efc592009-07-27 20:11:35 +0200715 struct gsm_trans *trans;
Holger Freytherca362a62009-01-04 21:05:01 +0000716 u_int8_t *data;
Harald Welte87f5d632009-07-04 17:39:00 +0200717 u_int8_t msg_ref = 42;
718 u_int8_t trans_id = 23;
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000719
720 msg->lchan = lchan;
721
Harald Weltef3efc592009-07-27 20:11:35 +0200722 /* FIXME: allocate trans */
723
Harald Welte87f5d632009-07-04 17:39:00 +0200724 /* Hardcode Originating Address for now */
Daniel Willmanna3e29842008-12-29 16:03:54 +0000725 data = (u_int8_t *)msgb_put(msg, 8);
Harald Welte87f5d632009-07-04 17:39:00 +0200726 data[0] = 0x07; /* originator length == 7 */
Harald Welteb9c758b2009-07-05 14:02:46 +0200727 data[1] = 0x91; /* type of number: international, ISDN */
728 data[2] = 0x44; /* 447785016005 */
Daniel Willmanna3e29842008-12-29 16:03:54 +0000729 data[3] = 0x77;
730 data[4] = 0x58;
731 data[5] = 0x10;
732 data[6] = 0x06;
733 data[7] = 0x50;
Harald Welte87f5d632009-07-04 17:39:00 +0200734
735 /* Hardcoded Destination Address */
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000736 data = (u_int8_t *)msgb_put(msg, 1);
Harald Welte87f5d632009-07-04 17:39:00 +0200737 data[0] = 0; /* destination length == 0 */
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000738
739 /* FIXME: Hardcoded for now */
Daniel Willmann4a1e8792008-12-29 06:23:56 +0000740 //smslen = gsm0411_tpdu_from_sms(tpdu, sms);
741
742 /* RPDU length */
743 data = (u_int8_t *)msgb_put(msg, 1);
744 data[0] = sizeof(tpdu_test);
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000745
746 data = (u_int8_t *)msgb_put(msg, sizeof(tpdu_test));
747
748 //memcpy(data, tpdu, smslen);
749 memcpy(data, tpdu_test, sizeof(tpdu_test));
750
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000751 DEBUGP(DSMS, "TX: SMS SUBMIT\n");
752
Harald Weltef3efc592009-07-27 20:11:35 +0200753 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
754 /* FIXME: enter 'wait for RP-ACK' state, start TR1N */
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000755}
Harald Weltef3efc592009-07-27 20:11:35 +0200756
757
758#if 0
759{
760 struct sms_deliver *smsd;
761
762 smsd->mti = GSM340_SMS_DELIVER_SC2MS;
763 smsd->mms = 0; /* FIXME: determine if there are more */
764 smsd->rp = FIXME;
765 smsd->udhi = FIXME;
766 smsd->sri = 1;
767 smsd->oa = FIXME;
768 smsd->pid = FIXME;
769 smsd->dcs = FIXME;
770 smsd->scts = FIXME;
771 smsd->ud_len = FIXME;
772 smsd->ud = FIXME;
773}
774#endif