blob: 5ce25f3dced81656015bde7f87828b0e50790971 [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 sms = talloc(tall_sms_ctx, struct sms_submit);
Harald Welte7e310b12009-03-30 20:56:32 +0000290 if (!sms)
Harald Welteb9c758b2009-07-05 14:02:46 +0200291 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000292 memset(sms, 0, sizeof(*sms));
293
Harald Welte2cf161b2009-06-20 22:36:41 +0200294 gsms = talloc(tall_gsms_ctx, struct gsm_sms);
Harald Welte7e310b12009-03-30 20:56:32 +0000295 if (!gsms) {
Harald Welte2cf161b2009-06-20 22:36:41 +0200296 talloc_free(sms);
Harald Welteb9c758b2009-07-05 14:02:46 +0200297 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000298 }
299 memset(gsms, 0, sizeof(*gsms));
300
301 /* invert those fields where 0 means active/present */
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000302 sms->mti = *smsp & 0x03;
303 sms->mms = !!(*smsp & 0x04);
304 sms->vpf = (*smsp & 0x18) >> 3;
Harald Weltef3efc592009-07-27 20:11:35 +0200305 sms->srr = (*smsp & 0x20);
306 sms->udhi= (*smsp & 0x40);
307 sms->rp = (*smsp & 0x80);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000308
309 smsp++;
310 sms->msg_ref = *smsp++;
311
Harald Welte7e310b12009-03-30 20:56:32 +0000312 /* length in bytes of the destination address */
313 da_len_bytes = 2 + *smsp/2 + *smsp%2;
314 if (da_len_bytes > 12) {
315 DEBUGP(DSMS, "Destination Address > 12 bytes ?!?\n");
Harald Welteb9c758b2009-07-05 14:02:46 +0200316 rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
Harald Welte7e310b12009-03-30 20:56:32 +0000317 goto out;
318 }
Harald Welte3cfdb222009-06-12 02:42:11 +0800319 memset(address_lv, 0, sizeof(address_lv));
Harald Welte7e310b12009-03-30 20:56:32 +0000320 memcpy(address_lv, smsp, da_len_bytes);
321 /* mangle first byte to reflect length in bytes, not digits */
Harald Welte3cfdb222009-06-12 02:42:11 +0800322 address_lv[0] = da_len_bytes - 1;
Harald Welte7e310b12009-03-30 20:56:32 +0000323 /* convert to real number */
Harald Welte3cfdb222009-06-12 02:42:11 +0800324 decode_bcd_number(sms->dest_addr, sizeof(sms->dest_addr), address_lv, 1);
Harald Welte7e310b12009-03-30 20:56:32 +0000325
326 smsp += da_len_bytes;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000327
328 sms->pid = *smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000329
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000330 sms->dcs = *smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000331 sms->alphabet = gsm338_get_sms_alphabet(sms->dcs);
332
333 switch (sms->vpf) {
334 case GSM340_TP_VPF_RELATIVE:
335 sms->vp = smsp++;
336 break;
337 case GSM340_TP_VPF_ABSOLUTE:
338 case GSM340_TP_VPF_ENHANCED:
339 sms->vp = smsp;
340 smsp += 7;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000341 break;
342 default:
343 DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n",
344 sms->vpf);
345 }
346 sms->ud_len = *smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000347 if (sms->ud_len)
348 sms->user_data = smsp;
349 else
350 sms->user_data = NULL;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000351
Harald Welte7e310b12009-03-30 20:56:32 +0000352 if (sms->ud_len) {
353 switch (sms->alphabet) {
354 case DCS_7BIT_DEFAULT:
355 gsm_7bit_decode(sms->decoded, smsp, sms->ud_len);
356 break;
357 case DCS_8BIT_DATA:
358 case DCS_UCS2:
359 case DCS_NONE:
360 memcpy(sms->decoded, sms->user_data, sms->ud_len);
361 break;
362 }
363 }
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000364
Harald Welte7e310b12009-03-30 20:56:32 +0000365 DEBUGP(DSMS, "SMS:\nMTI: 0x%02x, VPF: 0x%02x, MR: 0x%02x "
366 "PID: 0x%02x, DCS: 0x%02x, DA: %s, UserDataLength: 0x%02x "
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000367 "UserData: \"%s\"\n", sms->mti, sms->vpf, sms->msg_ref,
Harald Welte7e310b12009-03-30 20:56:32 +0000368 sms->pid, sms->dcs, sms->dest_addr, sms->ud_len,
Harald Welteb9c758b2009-07-05 14:02:46 +0200369 sms->alphabet == DCS_7BIT_DEFAULT ? sms->decoded :
370 hexdump(sms->user_data, sms->ud_len));
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000371
Harald Welte595ad7b2009-02-16 22:05:44 +0000372 dispatch_signal(SS_SMS, 0, sms);
Holger Freyther9b177762009-02-16 19:07:18 +0000373
Harald Welteb9c758b2009-07-05 14:02:46 +0200374 /* now we've filled the 'sms' structure. Go on filling
375 * the gsms structure based on information from the sms */
376
Harald Welte7e310b12009-03-30 20:56:32 +0000377 gsms->sender = msg->lchan->subscr;
378 /* FIXME: sender refcount */
379
Harald Welteb9c758b2009-07-05 14:02:46 +0200380 gsms->validity_minutes = gsm340_validity_period(sms);
381
Harald Welte7e310b12009-03-30 20:56:32 +0000382 /* determine gsms->receiver based on dialled number */
Harald Welte9176bd42009-07-23 18:46:00 +0200383 gsms->receiver = subscr_get_by_extension(bts->network, sms->dest_addr);
Harald Welte7e310b12009-03-30 20:56:32 +0000384 if (!gsms->receiver) {
385 rc = 1; /* cause 1: unknown subscriber */
386 goto out;
387 }
388
Harald Weltef3efc592009-07-27 20:11:35 +0200389 if (sms->user_data) {
390 gsms->header_len = sms->ud_len;
Harald Welteb9c758b2009-07-05 14:02:46 +0200391 memcpy(gsms->header, sms->user_data, sms->ud_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200392 }
Harald Welteb9c758b2009-07-05 14:02:46 +0200393
394 if (sms->decoded)
Harald Welte7e310b12009-03-30 20:56:32 +0000395 strncpy(gsms->text, sms->decoded, sizeof(gsms->text));
396
397 switch (sms->mti) {
398 case GSM340_SMS_SUBMIT_MS2SC:
399 /* MS is submitting a SMS */
400 rc = gsm340_rx_sms_submit(msg, sms, gsms);
401 break;
402 case GSM340_SMS_COMMAND_MS2SC:
403 case GSM340_SMS_DELIVER_REP_MS2SC:
404 DEBUGP(DSMS, "Unimplemented MTI 0x%02x\n", sms->mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200405 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000406 break;
407 default:
408 DEBUGP(DSMS, "Undefined MTI 0x%02x\n", sms->mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200409 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000410 break;
411 }
412
Harald Welteb9c758b2009-07-05 14:02:46 +0200413 if (!rc && !gsms->receiver)
414 rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
415
Harald Welte7e310b12009-03-30 20:56:32 +0000416out:
Harald Welte2cf161b2009-06-20 22:36:41 +0200417 talloc_free(gsms);
418 talloc_free(sms);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000419
Harald Welte7e310b12009-03-30 20:56:32 +0000420 return rc;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000421}
422
Harald Weltef3efc592009-07-27 20:11:35 +0200423static int gsm411_send_rp_ack(struct gsm_trans *trans, u_int8_t msg_ref)
Daniel Willmann471712b2008-12-29 01:54:02 +0000424{
425 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000426
Daniel Willmann471712b2008-12-29 01:54:02 +0000427 DEBUGP(DSMS, "TX: SMS RP ACK\n");
428
Harald Weltef3efc592009-07-27 20:11:35 +0200429 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ACK_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000430}
431
Harald Weltef3efc592009-07-27 20:11:35 +0200432static int gsm411_send_rp_error(struct gsm_trans *trans,
433 u_int8_t msg_ref, u_int8_t cause)
Daniel Willmann471712b2008-12-29 01:54:02 +0000434{
435 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000436
Harald Welte7e310b12009-03-30 20:56:32 +0000437 msgb_tv_put(msg, 1, cause);
Daniel Willmann471712b2008-12-29 01:54:02 +0000438
Harald Welte7e310b12009-03-30 20:56:32 +0000439 DEBUGP(DSMS, "TX: SMS RP ERROR (cause %02d)\n", cause);
Daniel Willmann471712b2008-12-29 01:54:02 +0000440
Harald Weltef3efc592009-07-27 20:11:35 +0200441 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000442}
443
Harald Welte7e310b12009-03-30 20:56:32 +0000444/* Receive a 04.11 TPDU inside RP-DATA / user data */
Harald Weltef3efc592009-07-27 20:11:35 +0200445static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
446 struct gsm411_rp_hdr *rph,
Harald Welte7e310b12009-03-30 20:56:32 +0000447 u_int8_t src_len, u_int8_t *src,
448 u_int8_t dst_len, u_int8_t *dst,
449 u_int8_t tpdu_len, u_int8_t *tpdu)
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000450{
451 struct gsm48_hdr *gh = msgb_l3(msg);
452 int rc = 0;
453
Harald Welte7e310b12009-03-30 20:56:32 +0000454 if (src_len && src)
455 DEBUGP(DSMS, "RP-DATA (MO) with SRC ?!?\n");
456
457 if (!dst_len || !dst || !tpdu_len || !tpdu) {
458 DEBUGP(DSMS, "RP-DATA (MO) without DST or TPDU ?!?\n");
Harald Weltef3efc592009-07-27 20:11:35 +0200459 gsm411_send_rp_error(trans, rph->msg_ref,
Harald Welteb9c758b2009-07-05 14:02:46 +0200460 GSM411_RP_CAUSE_INV_MAND_INF);
Harald Welte7e310b12009-03-30 20:56:32 +0000461 return -EIO;
462 }
463 msg->smsh = tpdu;
464
465 DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
Harald Welte7e310b12009-03-30 20:56:32 +0000466
467 rc = gsm340_rx_tpdu(msg);
468 if (rc == 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200469 return gsm411_send_rp_ack(trans, rph->msg_ref);
Harald Welte7e310b12009-03-30 20:56:32 +0000470 else if (rc > 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200471 return gsm411_send_rp_error(trans, rph->msg_ref, rc);
Harald Welte7e310b12009-03-30 20:56:32 +0000472 else
473 return rc;
474}
475
476/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
Harald Weltef3efc592009-07-27 20:11:35 +0200477static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
478 struct gsm411_rp_hdr *rph)
Harald Welte7e310b12009-03-30 20:56:32 +0000479{
480 u_int8_t src_len, dst_len, rpud_len;
481 u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
482
483 /* in the MO case, this should always be zero length */
484 src_len = rph->data[0];
485 if (src_len)
486 src = &rph->data[1];
487
488 dst_len = rph->data[1+src_len];
489 if (dst_len)
490 dst = &rph->data[1+src_len+1];
491
492 rpud_len = rph->data[1+src_len+1+dst_len];
493 if (rpud_len)
494 rp_ud = &rph->data[1+src_len+1+dst_len+1];
495
Harald Welteb9c758b2009-07-05 14:02:46 +0200496 DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
497 src_len, dst_len, rpud_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200498 return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst,
Harald Welte7e310b12009-03-30 20:56:32 +0000499 rpud_len, rp_ud);
500}
501
Harald Welteb9c758b2009-07-05 14:02:46 +0200502
Harald Weltef3efc592009-07-27 20:11:35 +0200503static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
504 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200505{
506 /* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
507 * successfully received a SMS. We can now safely mark it as
508 * transmitted */
509
Harald Welte3e0f6172009-07-09 23:52:59 +0200510 /* we need to look-up the transaction based on rph->msg_ref to
511 * identify which particular RP_DATA/SMS-submit was ACKed */
512
Harald Welteb9c758b2009-07-05 14:02:46 +0200513}
514
Harald Weltef3efc592009-07-27 20:11:35 +0200515static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
516 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200517{
Harald Weltef3efc592009-07-27 20:11:35 +0200518 u_int8_t cause_len = rph->data[0];
519 u_int8_t cause = rph->data[1];
520
Harald Welteb9c758b2009-07-05 14:02:46 +0200521 /* Error in response to MT RP_DATA, i.e. the MS did not
522 * successfully receive the SMS. We need to investigate
523 * the cause and take action depending on it */
524
Harald Weltef3efc592009-07-27 20:11:35 +0200525 DEBUGP(DSMS, "RX SMS RP-ERROR Cause=0x%02x\n", cause);
526
Harald Welte3e0f6172009-07-09 23:52:59 +0200527 /* we need to look-up the transaction based on rph->msg_ref to
528 * identify which particular RP_DATA/SMS-submit failed */
529
Harald Weltef3efc592009-07-27 20:11:35 +0200530 return 0;
Harald Welteb9c758b2009-07-05 14:02:46 +0200531}
532
Harald Weltef3efc592009-07-27 20:11:35 +0200533static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans,
534 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200535{
Harald Weltef3efc592009-07-27 20:11:35 +0200536 int rc;
537
Harald Welteb9c758b2009-07-05 14:02:46 +0200538 /* MS tells us that it has memory for more SMS, we need
539 * to check if we have any pending messages for it and then
540 * transfer those */
Harald Weltef3efc592009-07-27 20:11:35 +0200541
542 rc = gsm411_send_rp_ack(trans, rph->msg_ref);
543 trans->sms.rp_state = GSM411_RPS_IDLE;
544
545 return rc;
Harald Welteb9c758b2009-07-05 14:02:46 +0200546}
547
Harald Weltef3efc592009-07-27 20:11:35 +0200548static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
549 struct gsm_trans *trans)
Harald Welte7e310b12009-03-30 20:56:32 +0000550{
Daniel Willmann471712b2008-12-29 01:54:02 +0000551 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000552 u_int8_t msg_type = rp_data->msg_type & 0x07;
Harald Welte7e310b12009-03-30 20:56:32 +0000553 int rc = 0;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000554
555 switch (msg_type) {
556 case GSM411_MT_RP_DATA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200557 DEBUGP(DSMS, "RX SMS RP-DATA (MO)\n");
558 /* start TR2N and enter 'wait to send RP-ACK state' */
559 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
560 rc = gsm411_rx_rp_data(msg, trans, rp_data);
Harald Welte7e310b12009-03-30 20:56:32 +0000561 break;
562 case GSM411_MT_RP_ACK_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200563 DEBUGP(DSMS,"RX SMS RP-ACK (MO)\n");
564 rc = gsm411_rx_rp_ack(msg, trans, rp_data);
Harald Welteb9c758b2009-07-05 14:02:46 +0200565 break;
Harald Welte7e310b12009-03-30 20:56:32 +0000566 case GSM411_MT_RP_SMMA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200567 DEBUGP(DSMS, "RX SMS RP-SMMA\n");
568 /* start TR2N and enter 'wait to send RP-ACK state' */
569 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
570 rc = gsm411_rx_rp_smma(msg, trans, rp_data);
571 break;
572 case GSM411_MT_RP_ERROR_MO:
573 rc = gsm411_rx_rp_error(msg, trans, rp_data);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000574 break;
575 default:
Harald Welte7e310b12009-03-30 20:56:32 +0000576 DEBUGP(DSMS, "Invalid RP type 0x%02x\n", msg_type);
Harald Weltef3efc592009-07-27 20:11:35 +0200577 rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
578 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000579 break;
580 }
581
582 return rc;
583}
584
Harald Weltef3efc592009-07-27 20:11:35 +0200585/* send CP-ACK to given transaction */
586static int gsm411_tx_cp_ack(struct gsm_trans *trans)
587{
588 struct msgb *msg = gsm411_msgb_alloc();
589
590 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ACK);
591}
592
593static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
594{
595 struct msgb *msg = gsm411_msgb_alloc();
596 u_int8_t *causep;
597
598 cause = msgb_put(msg, 1);
599 *causep = cause;
600
601 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ERROR);
602}
603
604/* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000605int gsm0411_rcv_sms(struct msgb *msg)
606{
607 struct gsm48_hdr *gh = msgb_l3(msg);
608 u_int8_t msg_type = gh->msg_type;
Harald Weltef3efc592009-07-27 20:11:35 +0200609 u_int8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
610 struct gsm_lchan *lchan = msg->lchan;
611 struct gsm_trans *trans;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000612 int rc = 0;
613
Harald Weltef3efc592009-07-27 20:11:35 +0200614 if (!lchan->subscr)
615 return -EIO;
616 /* FIXME: send some error message */
617
618 trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS,
619 transaction_id);
620 if (!trans) {
621 DEBUGP(DSMS, "Unknown transaction ID %x, "
622 "creating new trans\n", transaction_id);
623 trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
624 transaction_id, new_callref++);
625 if (!trans) {
626 DEBUGP(DSMS, "No memory for trans\n");
627 /* FIXME: send some error message */
628 return -ENOMEM;
629 }
630 trans->sms.cp_state = GSM411_CPS_IDLE;
631 trans->sms.rp_state = GSM411_RPS_IDLE;
632 trans->sms.is_mt = 0;
633
634 trans->lchan = lchan;
635 use_lchan(lchan);
636 }
637
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000638 switch(msg_type) {
639 case GSM411_MT_CP_DATA:
Harald Weltef3efc592009-07-27 20:11:35 +0200640 DEBUGP(DSMS, "RX SMS CP-DATA\n");
641 if (!trans->sms.is_mt) {
642 /* 5.2.3.1.3: MO state exists when SMC has received
643 * CP-DATA, including sending of the assoc. CP-ACK */
644 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
645 }
646
647 rc = gsm411_rx_cp_data(msg, gh, trans);
648 /* Send CP-ACK or CP-ERORR in response */
649 if (rc < 0) {
650 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_NET_FAIL);
651 } else
652 rc = gsm411_tx_cp_ack(trans);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000653 break;
654 case GSM411_MT_CP_ACK:
Harald Weltef3efc592009-07-27 20:11:35 +0200655 /* previous CP-DATA in this transaction was confirmed */
656 DEBUGP(DSMS, "RX SMS CP-ACK\n");
657 if (!trans->sms.is_mt) {
658 /* 5.2.3.1.3: MO state exists when SMC has received
659 * CP-ACK */
660 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
661 /* FIXME: we have sont one CP-DATA, which was now
662 * acknowledged. Check if we want to transfer more,
663 * i.e. multi-part message */
664 trans->sms.cp_state = GSM411_CPS_IDLE;
665 trans_free(trans);
666 }
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000667 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000668 case GSM411_MT_CP_ERROR:
Harald Weltef3efc592009-07-27 20:11:35 +0200669 DEBUGP(DSMS, "RX SMS CP-ERROR, cause 0x%02x\n", gh->data[0]);
670 trans->sms.cp_state = GSM411_CPS_IDLE;
671 trans_free(trans);
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000672 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000673 default:
Harald Weltef3efc592009-07-27 20:11:35 +0200674 DEBUGP(DSMS, "RX Unimplemented CP msg_type: 0x%02x\n", msg_type);
675 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
676 trans_free(trans);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000677 break;
678 }
679
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000680 return rc;
681}
682
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000683/* Test TPDU - 25c3 welcome */
Harald Welte8c2e36e2008-12-30 15:00:14 +0000684#if 0
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000685static u_int8_t tpdu_test[] = {
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000686 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x92, 0x90, 0x32,
687 0x24, 0x40, 0x4D, 0xB2, 0xDA, 0x70, 0xD6, 0x9A, 0x97, 0xE5, 0xF6, 0xF4,
688 0xB8, 0x0C, 0x0A, 0xBB, 0xDD, 0xEF, 0xBA, 0x7B, 0x5C, 0x6E, 0x97, 0xDD,
689 0x74, 0x1D, 0x08, 0xCA, 0x2E, 0x87, 0xE7, 0x65, 0x50, 0x98, 0x4E, 0x2F,
690 0xBB, 0xC9, 0x20, 0x3A, 0xBA, 0x0C, 0x3A, 0x4E, 0x9B, 0x20, 0x7A, 0x98,
691 0xBD, 0x06, 0x85, 0xE9, 0xA0, 0x58, 0x4C, 0x37, 0x83, 0x81, 0xD2, 0x6E,
692 0xD0, 0x34, 0x1C, 0x66, 0x83, 0x62, 0x21, 0x90, 0xAE, 0x95, 0x02
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000693};
Harald Welte8c2e36e2008-12-30 15:00:14 +0000694#else
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000695/* Test TPDU - ALL YOUR */
696static u_int8_t tpdu_test[] = {
697 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
698 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
699 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
700 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
Daniel Willmanne2a728d2008-12-30 14:03:09 +0000701};
Harald Welte8c2e36e2008-12-30 15:00:14 +0000702#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000703
704int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms)
705{
706 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltef3efc592009-07-27 20:11:35 +0200707 struct gsm_trans *trans;
Holger Freytherca362a62009-01-04 21:05:01 +0000708 u_int8_t *data;
Harald Welte87f5d632009-07-04 17:39:00 +0200709 u_int8_t msg_ref = 42;
710 u_int8_t trans_id = 23;
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000711
712 msg->lchan = lchan;
713
Harald Weltef3efc592009-07-27 20:11:35 +0200714 /* FIXME: allocate trans */
715
Harald Welte87f5d632009-07-04 17:39:00 +0200716 /* Hardcode Originating Address for now */
Daniel Willmanna3e29842008-12-29 16:03:54 +0000717 data = (u_int8_t *)msgb_put(msg, 8);
Harald Welte87f5d632009-07-04 17:39:00 +0200718 data[0] = 0x07; /* originator length == 7 */
Harald Welteb9c758b2009-07-05 14:02:46 +0200719 data[1] = 0x91; /* type of number: international, ISDN */
720 data[2] = 0x44; /* 447785016005 */
Daniel Willmanna3e29842008-12-29 16:03:54 +0000721 data[3] = 0x77;
722 data[4] = 0x58;
723 data[5] = 0x10;
724 data[6] = 0x06;
725 data[7] = 0x50;
Harald Welte87f5d632009-07-04 17:39:00 +0200726
727 /* Hardcoded Destination Address */
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000728 data = (u_int8_t *)msgb_put(msg, 1);
Harald Welte87f5d632009-07-04 17:39:00 +0200729 data[0] = 0; /* destination length == 0 */
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000730
731 /* FIXME: Hardcoded for now */
Daniel Willmann4a1e8792008-12-29 06:23:56 +0000732 //smslen = gsm0411_tpdu_from_sms(tpdu, sms);
733
734 /* RPDU length */
735 data = (u_int8_t *)msgb_put(msg, 1);
736 data[0] = sizeof(tpdu_test);
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000737
738 data = (u_int8_t *)msgb_put(msg, sizeof(tpdu_test));
739
740 //memcpy(data, tpdu, smslen);
741 memcpy(data, tpdu_test, sizeof(tpdu_test));
742
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000743 DEBUGP(DSMS, "TX: SMS SUBMIT\n");
744
Harald Weltef3efc592009-07-27 20:11:35 +0200745 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
746 /* FIXME: enter 'wait for RP-ACK' state, start TR1N */
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000747}
Harald Weltef3efc592009-07-27 20:11:35 +0200748
749
750#if 0
751{
752 struct sms_deliver *smsd;
753
754 smsd->mti = GSM340_SMS_DELIVER_SC2MS;
755 smsd->mms = 0; /* FIXME: determine if there are more */
756 smsd->rp = FIXME;
757 smsd->udhi = FIXME;
758 smsd->sri = 1;
759 smsd->oa = FIXME;
760 smsd->pid = FIXME;
761 smsd->dcs = FIXME;
762 smsd->scts = FIXME;
763 smsd->ud_len = FIXME;
764 smsd->ud = FIXME;
765}
766#endif
Harald Welte3366a942009-07-28 00:44:49 +0200767
Harald Welte7bfc2672009-07-28 00:41:45 +0200768static __attribute__((constructor)) void on_dso_load_sms(void)
769{
770 tall_sms_ctx = talloc_named_const(tall_bsc_ctx, 1, "sms_submit");
771 tall_gsms_ctx = talloc_named_const(tall_bsc_ctx, 1, "sms");
772}