blob: 4f19e2ce7114ce92321780d7e5e49c6a4d05d9ca [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>
Harald Welte76042182009-08-08 16:03:15 +020047#include <openbsc/paging.h>
Harald Weltecb8f4432009-08-09 14:59:02 +020048#include <openbsc/bsc_rll.h>
Holger Hans Peter Freyther34e97492009-08-10 07:54:02 +020049#include <openbsc/chan_alloc.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000050
Daniel Willmann471712b2008-12-29 01:54:02 +000051#define GSM411_ALLOC_SIZE 1024
52#define GSM411_ALLOC_HEADROOM 128
53
Harald Weltecb8f4432009-08-09 14:59:02 +020054#define UM_SAPI_SMS 3 /* See GSM 04.05/04.06 */
55
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020056void *tall_gsms_ctx;
Harald Weltef3efc592009-07-27 20:11:35 +020057static u_int32_t new_callref = 0x40000001;
58
Harald Welte (local)c89a5112009-08-14 10:42:43 +020059static const struct value_string cp_cause_strs[] = {
60 { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
61 { GSM411_CP_CAUSE_CONGESTION, "Congestion" },
62 { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
63 { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
64 { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
65 { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
66 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
67 "Message incompatible with protocol state" },
68 { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
69 { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
70 { 0, 0 }
71};
72
73static const struct value_string rp_cause_strs[] = {
74 { GSM411_RP_CAUSE_MO_NUM_UNASSIGNED, "(MO) Number not assigned" },
75 { GSM411_RP_CAUSE_MO_OP_DET_BARR, "(MO) Operator determined barring" },
76 { GSM411_RP_CAUSE_MO_CALL_BARRED, "(MO) Call barred" },
77 { GSM411_RP_CAUSE_MO_SMS_REJECTED, "(MO) SMS rejected" },
78 { GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER, "(MO) Destination out of order" },
79 { GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR, "(MO) Unidentified subscriber" },
80 { GSM411_RP_CAUSE_MO_FACILITY_REJ, "(MO) Facility reject" },
81 { GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR, "(MO) Unknown subscriber" },
82 { GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER, "(MO) Network out of order" },
83 { GSM411_RP_CAUSE_MO_TEMP_FAIL, "(MO) Temporary failure" },
84 { GSM411_RP_CAUSE_MO_CONGESTION, "(MO) Congestion" },
85 { GSM411_RP_CAUSE_MO_RES_UNAVAIL, "(MO) Resource unavailable" },
86 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR, "(MO) Requested facility not subscribed" },
87 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL, "(MO) Requested facility not implemented" },
88 { GSM411_RP_CAUSE_MO_INTERWORKING, "(MO) Interworking" },
89 /* valid only for MT */
90 { GSM411_RP_CAUSE_MT_MEM_EXCEEDED, "(MT) Memory Exceeded" },
91 /* valid for both directions */
92 { GSM411_RP_CAUSE_INV_TRANS_REF, "Invalid Transaction Reference" },
93 { GSM411_RP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
94 { GSM411_RP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
95 { GSM411_RP_CAUSE_MSGTYPE_NOTEXIST, "Message Type non-existant" },
96 { GSM411_RP_CAUSE_MSG_INCOMP_STATE, "Message incompatible with protocol state" },
97 { GSM411_RP_CAUSE_IE_NOTEXIST, "Information Element not existing" },
98 { GSM411_RP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
99 { 0, NULL }
100};
101
Harald Welte76042182009-08-08 16:03:15 +0200102struct gsm_sms *sms_alloc(void)
103{
104 return talloc_zero(tall_gsms_ctx, struct gsm_sms);
105}
106
107void sms_free(struct gsm_sms *sms)
108{
109 /* drop references to subscriber structure */
110 if (sms->sender)
111 subscr_put(sms->sender);
112 if (sms->receiver)
113 subscr_put(sms->receiver);
114
115 talloc_free(sms);
116}
117
Holger Freythera553d092009-01-04 20:16:25 +0000118struct msgb *gsm411_msgb_alloc(void)
Daniel Willmann471712b2008-12-29 01:54:02 +0000119{
Harald Welte966636f2009-06-26 19:39:35 +0200120 return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
121 "GSM 04.11");
Daniel Willmann471712b2008-12-29 01:54:02 +0000122}
123
Harald Welte (local)daef6062009-08-14 11:41:12 +0200124static int gsm411_sendmsg(struct msgb *msg, u_int8_t link_id)
Daniel Willmann471712b2008-12-29 01:54:02 +0000125{
126 if (msg->lchan)
127 msg->trx = msg->lchan->ts->trx;
128
129 msg->l3h = msg->data;
130
Harald Welte76042182009-08-08 16:03:15 +0200131 DEBUGP(DSMS, "GSM4.11 TX %s\n", hexdump(msg->data, msg->len));
132
Harald Welte (local)daef6062009-08-14 11:41:12 +0200133 return rsl_data_request(msg, link_id);
Daniel Willmann471712b2008-12-29 01:54:02 +0000134}
135
Harald Welte41985612009-08-10 00:24:32 +0200136/* SMC TC1* is expired */
137static void cp_timer_expired(void *data)
138{
139 struct gsm_trans *trans = data;
140
141 DEBUGP(DSMS, "SMC Timer TC1* is expired, calling trans_free()\n");
142 /* FIXME: we need to re-transmit the last CP-DATA 1..3 times */
143 trans_free(trans);
144}
145
Harald Welte87f5d632009-07-04 17:39:00 +0200146/* Prefix msg with a 04.08/04.11 CP header */
Harald Weltef3efc592009-07-27 20:11:35 +0200147static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
148 u_int8_t msg_type)
Harald Welte87f5d632009-07-04 17:39:00 +0200149{
150 struct gsm48_hdr *gh;
151
152 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
153 /* Outgoing needs the highest bit set */
Harald Weltef3efc592009-07-27 20:11:35 +0200154 gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
Harald Welte87f5d632009-07-04 17:39:00 +0200155 gh->msg_type = msg_type;
156
Harald Weltef3efc592009-07-27 20:11:35 +0200157 /* assign the outgoing lchan */
158 msg->lchan = trans->lchan;
159
160 /* mobile originating */
161 switch (gh->msg_type) {
162 case GSM411_MT_CP_DATA:
163 /* 5.2.3.1.2: enter MO-wait for CP-ack */
Harald Weltecb8f4432009-08-09 14:59:02 +0200164 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
Harald Weltef3efc592009-07-27 20:11:35 +0200165 trans->sms.cp_state = GSM411_CPS_WAIT_CP_ACK;
Harald Welte41985612009-08-10 00:24:32 +0200166 trans->sms.cp_timer.data = trans;
167 trans->sms.cp_timer.cb = cp_timer_expired;
168 /* 5.3.2.1: Set Timer TC1A */
169 bsc_schedule_timer(&trans->sms.cp_timer, GSM411_TMR_TC1A);
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200170 DEBUGP(DSMS, "TX: CP-DATA ");
171 break;
172 case GSM411_MT_CP_ACK:
173 DEBUGP(DSMS, "TX: CP-ACK ");
174 break;
175 case GSM411_MT_CP_ERROR:
Sylvain Munaut1d9efd62009-12-18 18:28:07 +0100176 DEBUGP(DSMS, "TX: CP-ERROR ");
Harald Weltef3efc592009-07-27 20:11:35 +0200177 break;
178 }
179
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200180 DEBUGPC(DSMS, "trans=%x\n", trans->transaction_id);
181
Harald Welte (local)daef6062009-08-14 11:41:12 +0200182 return gsm411_sendmsg(msg, trans->sms.link_id);
Harald Welte87f5d632009-07-04 17:39:00 +0200183}
184
185/* Prefix msg with a RP-DATA header and send as CP-DATA */
Harald Weltef3efc592009-07-27 20:11:35 +0200186static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
187 u_int8_t rp_msg_type, u_int8_t rp_msg_ref)
Harald Welte87f5d632009-07-04 17:39:00 +0200188{
189 struct gsm411_rp_hdr *rp;
Harald Welte0d544e72009-08-10 00:22:19 +0200190 u_int8_t len = msg->len;
Harald Welte87f5d632009-07-04 17:39:00 +0200191
192 /* GSM 04.11 RP-DATA header */
193 rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
Harald Welte0d544e72009-08-10 00:22:19 +0200194 rp->len = len + 2;
Harald Welte87f5d632009-07-04 17:39:00 +0200195 rp->msg_type = rp_msg_type;
196 rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */
197
Harald Weltef3efc592009-07-27 20:11:35 +0200198 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA);
Harald Welte87f5d632009-07-04 17:39:00 +0200199}
200
Steffen Neubauerf3262672009-11-26 12:28:41 +0100201/* Turn int into semi-octet representation: 98 => 0x89 */
202static u_int8_t bcdify(u_int8_t value)
203{
204 u_int8_t ret;
Steffen Neubauer5727cf42009-11-11 23:02:07 +0900205
Steffen Neubauerf3262672009-11-26 12:28:41 +0100206 ret = value / 10;
207 ret |= (value % 10) << 4;
208
209 return ret;
210}
211
212/* Turn semi-octet representation into int: 0x89 => 98 */
213static u_int8_t unbcdify(u_int8_t value)
214{
215 u_int8_t ret;
216
217 if ((value & 0x0F) > 9 || (value >> 4) > 9)
Harald Welted0cf7ba2009-12-24 15:08:18 +0100218 LOGP(DSMS, LOGL_ERROR,
219 "unbcdify got too big nibble: 0x%02X\n", value);
Steffen Neubauerf3262672009-11-26 12:28:41 +0100220
221 ret = (value&0x0F)*10;
Steffen Neubauerad69d7f2009-11-26 23:38:41 +0100222 ret += value>>4;
Steffen Neubauerf3262672009-11-26 12:28:41 +0100223
224 return ret;
225}
226
227/* Generate 03.40 TP-SCTS */
228static void gsm340_gen_scts(u_int8_t *scts, time_t time)
229{
230 struct tm *tm = localtime(&time);
231
232 *scts++ = bcdify(tm->tm_year % 100);
233 *scts++ = bcdify(tm->tm_mon + 1);
234 *scts++ = bcdify(tm->tm_mday);
235 *scts++ = bcdify(tm->tm_hour);
236 *scts++ = bcdify(tm->tm_min);
237 *scts++ = bcdify(tm->tm_sec);
238 *scts++ = bcdify(tm->tm_gmtoff/(60*15));
239}
240
241/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */
242static time_t gsm340_scts(u_int8_t *scts)
243{
244 struct tm tm;
245
246 u_int8_t yr = unbcdify(*scts++);
247
248 if (yr <= 80)
249 tm.tm_year = 100 + yr;
250 else
251 tm.tm_year = yr;
252 tm.tm_mon = unbcdify(*scts++) - 1;
253 tm.tm_mday = unbcdify(*scts++);
254 tm.tm_hour = unbcdify(*scts++);
255 tm.tm_min = unbcdify(*scts++);
256 tm.tm_sec = unbcdify(*scts++);
257 /* according to gsm 03.40 time zone is
258 "expressed in quarters of an hour" */
259 tm.tm_gmtoff = unbcdify(*scts++) * 15*60;
260
261 return mktime(&tm);
262}
263
264/* Return the default validity period in minutes */
265static unsigned long gsm340_vp_default(void)
266{
267 unsigned long minutes;
268 /* Default validity: two days */
269 minutes = 24 * 60 * 2;
270 return minutes;
271}
272
273/* Decode validity period format 'relative' */
274static unsigned long gsm340_vp_relative(u_int8_t *sms_vp)
275{
276 /* Chapter 9.2.3.12.1 */
277 u_int8_t vp;
278 unsigned long minutes;
279
280 vp = *(sms_vp);
281 if (vp <= 143)
282 minutes = vp + 1 * 5;
283 else if (vp <= 167)
284 minutes = 12*60 + (vp-143) * 30;
285 else if (vp <= 196)
286 minutes = vp-166 * 60 * 24;
287 else
288 minutes = vp-192 * 60 * 24 * 7;
289 return minutes;
290}
291
292/* Decode validity period format 'absolute' */
293static unsigned long gsm340_vp_absolute(u_int8_t *sms_vp)
294{
295 /* Chapter 9.2.3.12.2 */
296 time_t expires, now;
297 unsigned long minutes;
298
299 expires = gsm340_scts(sms_vp);
300 now = mktime(gmtime(NULL));
301 if (expires <= now)
302 minutes = 0;
303 else
304 minutes = (expires-now)/60;
305 return minutes;
306}
307
308/* Decode validity period format 'relative in integer representation' */
309static unsigned long gsm340_vp_relative_integer(u_int8_t *sms_vp)
Harald Welte7e310b12009-03-30 20:56:32 +0000310{
311 u_int8_t vp;
312 unsigned long minutes;
Steffen Neubauerf3262672009-11-26 12:28:41 +0100313 vp = *(sms_vp);
314 if (vp == 0) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100315 LOGP(DSMS, LOGL_ERROR,
316 "reserved relative_integer validity period\n");
Steffen Neubauerf3262672009-11-26 12:28:41 +0100317 return gsm340_vp_default();
318 }
319 minutes = vp/60;
320 return minutes;
321}
322
323/* Decode validity period format 'relative in semi-octet representation' */
324static unsigned long gsm340_vp_relative_semioctet(u_int8_t *sms_vp)
325{
326 unsigned long minutes;
327 minutes = unbcdify(*sms_vp++)*60; /* hours */
328 minutes += unbcdify(*sms_vp++); /* minutes */
329 minutes += unbcdify(*sms_vp++)/60; /* seconds */
330 return minutes;
331}
332
333/* decode validity period. return minutes */
334static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp)
335{
336 u_int8_t fi; /* functionality indicator */
Harald Welte7e310b12009-03-30 20:56:32 +0000337
Harald Welte76042182009-08-08 16:03:15 +0200338 switch (sms_vpf) {
Harald Welte7e310b12009-03-30 20:56:32 +0000339 case GSM340_TP_VPF_RELATIVE:
Steffen Neubauerf3262672009-11-26 12:28:41 +0100340 return gsm340_vp_relative(sms_vp);
Harald Welte7e310b12009-03-30 20:56:32 +0000341 case GSM340_TP_VPF_ABSOLUTE:
Steffen Neubauerf3262672009-11-26 12:28:41 +0100342 return gsm340_vp_absolute(sms_vp);
Harald Welte7e310b12009-03-30 20:56:32 +0000343 case GSM340_TP_VPF_ENHANCED:
344 /* Chapter 9.2.3.12.3 */
Steffen Neubauerf3262672009-11-26 12:28:41 +0100345 fi = *sms_vp++;
346 /* ignore additional fi */
347 if (fi & (1<<7)) sms_vp++;
348 /* read validity period format */
349 switch (fi & 0b111) {
350 case 0b000:
351 return gsm340_vp_default(); /* no vpf specified */
352 case 0b001:
353 return gsm340_vp_relative(sms_vp);
354 case 0b010:
355 return gsm340_vp_relative_integer(sms_vp);
356 case 0b011:
357 return gsm340_vp_relative_semioctet(sms_vp);
358 default:
359 /* The GSM spec says that the SC should reject any
360 unsupported and/or undefined values. FIXME */
Harald Welted0cf7ba2009-12-24 15:08:18 +0100361 LOGP(DSMS, LOGL_ERROR,
362 "Reserved enhanced validity period format\n");
Steffen Neubauerf3262672009-11-26 12:28:41 +0100363 return gsm340_vp_default();
364 }
Daniel Willmann58c83d82009-08-13 03:40:49 +0200365 case GSM340_TP_VPF_NONE:
Steffen Neubauerf3262672009-11-26 12:28:41 +0100366 default:
367 return gsm340_vp_default();
Harald Welte7e310b12009-03-30 20:56:32 +0000368 }
Harald Welte7e310b12009-03-30 20:56:32 +0000369}
370
371/* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */
372enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
373{
374 u_int8_t cgbits = dcs >> 4;
375 enum sms_alphabet alpha = DCS_NONE;
376
377 if ((cgbits & 0xc) == 0) {
378 if (cgbits & 2)
Harald Welted0cf7ba2009-12-24 15:08:18 +0100379 LOGP(DSMS, LOGL_NOTICE,
380 "Compressed SMS not supported yet\n");
Harald Welte7e310b12009-03-30 20:56:32 +0000381
Daniel Willmannd5d5e1d2009-08-15 03:01:17 +0200382 switch ((dcs >> 2)&0x03) {
Harald Welte7e310b12009-03-30 20:56:32 +0000383 case 0:
384 alpha = DCS_7BIT_DEFAULT;
385 break;
386 case 1:
387 alpha = DCS_8BIT_DATA;
388 break;
389 case 2:
390 alpha = DCS_UCS2;
391 break;
392 }
393 } else if (cgbits == 0xc || cgbits == 0xd)
394 alpha = DCS_7BIT_DEFAULT;
395 else if (cgbits == 0xe)
396 alpha = DCS_UCS2;
397 else if (cgbits == 0xf) {
398 if (dcs & 4)
399 alpha = DCS_8BIT_DATA;
400 else
401 alpha = DCS_7BIT_DEFAULT;
402 }
403
404 return alpha;
405}
406
Harald Welte76042182009-08-08 16:03:15 +0200407static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms)
Harald Welte7e310b12009-03-30 20:56:32 +0000408{
409 if (db_sms_store(gsms) != 0) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100410 LOGP(DSMS, LOGL_ERROR, "Failed to store SMS in Database\n");
Harald Welteb9c758b2009-07-05 14:02:46 +0200411 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000412 }
Harald Welte76042182009-08-08 16:03:15 +0200413 /* dispatch a signal to tell higher level about it */
414 dispatch_signal(SS_SMS, S_SMS_SUBMITTED, gsms);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200415 /* try delivering the SMS right now */
416 //gsm411_send_sms_subscr(gsms->receiver, gsms);
417
Harald Welte7e310b12009-03-30 20:56:32 +0000418 return 0;
419}
420
Harald Welte76042182009-08-08 16:03:15 +0200421/* generate a TPDU address field compliant with 03.40 sec. 9.1.2.5 */
422static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len,
423 struct gsm_subscriber *subscr)
Harald Weltef3efc592009-07-27 20:11:35 +0200424{
Harald Welte76042182009-08-08 16:03:15 +0200425 int len_in_bytes;
Harald Weltef3efc592009-07-27 20:11:35 +0200426
Harald Welte76042182009-08-08 16:03:15 +0200427 oa[1] = 0xb9; /* networks-specific number, private numbering plan */
428
429 len_in_bytes = encode_bcd_number(oa, oa_len, 1, subscr->extension);
430
431 /* GSM 03.40 tells us the length is in 'useful semi-octets' */
432 oa[0] = strlen(subscr->extension) & 0xff;
433
434 return len_in_bytes;
Harald Weltef3efc592009-07-27 20:11:35 +0200435}
436
Harald Welte76042182009-08-08 16:03:15 +0200437/* generate a msgb containing a TPDU derived from struct gsm_sms,
438 * returns total size of TPDU */
439static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
Harald Weltef3efc592009-07-27 20:11:35 +0200440{
Harald Weltef3efc592009-07-27 20:11:35 +0200441 u_int8_t *smsp;
442 u_int8_t oa[12]; /* max len per 03.40 */
443 u_int8_t oa_len = 0;
Daniel Willmann9aef1452009-08-13 03:39:07 +0200444 u_int8_t octet_len;
Harald Welte76042182009-08-08 16:03:15 +0200445 unsigned int old_msg_len = msg->len;
Harald Weltef3efc592009-07-27 20:11:35 +0200446
447 /* generate first octet with masked bits */
448 smsp = msgb_put(msg, 1);
Harald Welte76042182009-08-08 16:03:15 +0200449 /* TP-MTI (message type indicator) */
Harald Weltef3efc592009-07-27 20:11:35 +0200450 *smsp = GSM340_SMS_DELIVER_SC2MS;
Harald Welte76042182009-08-08 16:03:15 +0200451 /* TP-MMS (more messages to send) */
452 if (0 /* FIXME */)
Harald Weltef3efc592009-07-27 20:11:35 +0200453 *smsp |= 0x04;
Harald Welte76042182009-08-08 16:03:15 +0200454 /* TP-SRI(deliver)/SRR(submit) */
Harald Weltef3efc592009-07-27 20:11:35 +0200455 if (sms->status_rep_req)
456 *smsp |= 0x20;
Harald Welte76042182009-08-08 16:03:15 +0200457 /* TP-UDHI (indicating TP-UD contains a header) */
458 if (sms->ud_hdr_ind)
Harald Weltef3efc592009-07-27 20:11:35 +0200459 *smsp |= 0x40;
Harald Welte76042182009-08-08 16:03:15 +0200460#if 0
461 /* TP-RP (indicating that a reply path exists) */
Harald Weltef3efc592009-07-27 20:11:35 +0200462 if (sms->
463 *smsp |= 0x80;
464#endif
465
466 /* generate originator address */
Harald Welte76042182009-08-08 16:03:15 +0200467 oa_len = gsm340_gen_oa(oa, sizeof(oa), sms->sender);
Harald Weltef3efc592009-07-27 20:11:35 +0200468 smsp = msgb_put(msg, oa_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200469 memcpy(smsp, oa, oa_len);
470
471 /* generate TP-PID */
472 smsp = msgb_put(msg, 1);
473 *smsp = sms->protocol_id;
474
475 /* generate TP-DCS */
476 smsp = msgb_put(msg, 1);
477 *smsp = sms->data_coding_scheme;
478
479 /* generate TP-SCTS */
480 smsp = msgb_put(msg, 7);
481 gsm340_gen_scts(smsp, time(NULL));
Harald Welte76042182009-08-08 16:03:15 +0200482
Harald Weltef3efc592009-07-27 20:11:35 +0200483 /* generate TP-UDL */
484 smsp = msgb_put(msg, 1);
Harald Welte76042182009-08-08 16:03:15 +0200485 *smsp = sms->user_data_len;
Harald Weltef3efc592009-07-27 20:11:35 +0200486
487 /* generate TP-UD */
Daniel Willmann6b024cb2009-08-15 03:01:46 +0200488 switch (gsm338_get_sms_alphabet(sms->data_coding_scheme)) {
489 case DCS_7BIT_DEFAULT:
Daniel Willmann9aef1452009-08-13 03:39:07 +0200490 octet_len = sms->user_data_len*7/8;
491 if (sms->user_data_len*7%8 != 0)
492 octet_len++;
Daniel Willmann6b1e8222009-08-12 21:17:06 +0200493 /* Warning, user_data_len indicates the amount of septets
494 * (characters), we need amount of octets occupied */
Daniel Willmann9aef1452009-08-13 03:39:07 +0200495 smsp = msgb_put(msg, octet_len);
496 memcpy(smsp, sms->user_data, octet_len);
Daniel Willmann6b024cb2009-08-15 03:01:46 +0200497 break;
498 case DCS_UCS2:
499 case DCS_8BIT_DATA:
500 smsp = msgb_put(msg, sms->user_data_len);
501 memcpy(smsp, sms->user_data, sms->user_data_len);
502 break;
503 default:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100504 LOGP(DSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: 0x%02X\n",
505 sms->data_coding_scheme);
Daniel Willmann6b024cb2009-08-15 03:01:46 +0200506 break;
Daniel Willmann6b1e8222009-08-12 21:17:06 +0200507 }
Harald Weltef3efc592009-07-27 20:11:35 +0200508
Harald Welte76042182009-08-08 16:03:15 +0200509 return msg->len - old_msg_len;
Harald Weltef3efc592009-07-27 20:11:35 +0200510}
511
Harald Welteb9c758b2009-07-05 14:02:46 +0200512/* process an incoming TPDU (called from RP-DATA)
513 * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
Harald Welte7e310b12009-03-30 20:56:32 +0000514static int gsm340_rx_tpdu(struct msgb *msg)
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000515{
Harald Welte9176bd42009-07-23 18:46:00 +0200516 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000517 u_int8_t *smsp = msgb_sms(msg);
Harald Welte7e310b12009-03-30 20:56:32 +0000518 struct gsm_sms *gsms;
Harald Welte76042182009-08-08 16:03:15 +0200519 u_int8_t sms_mti, sms_mms, sms_vpf, sms_alphabet, sms_rp;
520 u_int8_t *sms_vp;
Harald Welte7e310b12009-03-30 20:56:32 +0000521 u_int8_t da_len_bytes;
522 u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
523 int rc = 0;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000524
Harald Welteffa55a42009-12-22 19:07:32 +0100525 counter_inc(bts->network->stats.sms.submitted);
Harald Welte24ff6ee2009-12-22 00:41:05 +0100526
Harald Welte76042182009-08-08 16:03:15 +0200527 gsms = sms_alloc();
528 if (!gsms)
Harald Welteb9c758b2009-07-05 14:02:46 +0200529 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000530
531 /* invert those fields where 0 means active/present */
Harald Welte76042182009-08-08 16:03:15 +0200532 sms_mti = *smsp & 0x03;
533 sms_mms = !!(*smsp & 0x04);
534 sms_vpf = (*smsp & 0x18) >> 3;
535 gsms->status_rep_req = (*smsp & 0x20);
536 gsms->ud_hdr_ind = (*smsp & 0x40);
537 sms_rp = (*smsp & 0x80);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000538
539 smsp++;
Harald Welte76042182009-08-08 16:03:15 +0200540 gsms->msg_ref = *smsp++;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000541
Harald Welte7e310b12009-03-30 20:56:32 +0000542 /* length in bytes of the destination address */
543 da_len_bytes = 2 + *smsp/2 + *smsp%2;
544 if (da_len_bytes > 12) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100545 LOGP(DSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n");
Harald Welteb9c758b2009-07-05 14:02:46 +0200546 rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
Harald Welte7e310b12009-03-30 20:56:32 +0000547 goto out;
548 }
Harald Welte3cfdb222009-06-12 02:42:11 +0800549 memset(address_lv, 0, sizeof(address_lv));
Harald Welte7e310b12009-03-30 20:56:32 +0000550 memcpy(address_lv, smsp, da_len_bytes);
551 /* mangle first byte to reflect length in bytes, not digits */
Harald Welte3cfdb222009-06-12 02:42:11 +0800552 address_lv[0] = da_len_bytes - 1;
Harald Welte7e310b12009-03-30 20:56:32 +0000553 /* convert to real number */
Harald Welte76042182009-08-08 16:03:15 +0200554 decode_bcd_number(gsms->dest_addr, sizeof(gsms->dest_addr), address_lv, 1);
Harald Welte7e310b12009-03-30 20:56:32 +0000555 smsp += da_len_bytes;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000556
Harald Welte76042182009-08-08 16:03:15 +0200557 gsms->protocol_id = *smsp++;
558 gsms->data_coding_scheme = *smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000559
Harald Welte76042182009-08-08 16:03:15 +0200560 sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
Harald Welte7e310b12009-03-30 20:56:32 +0000561
Harald Welte76042182009-08-08 16:03:15 +0200562 switch (sms_vpf) {
Harald Welte7e310b12009-03-30 20:56:32 +0000563 case GSM340_TP_VPF_RELATIVE:
Harald Welte76042182009-08-08 16:03:15 +0200564 sms_vp = smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000565 break;
566 case GSM340_TP_VPF_ABSOLUTE:
567 case GSM340_TP_VPF_ENHANCED:
Harald Welte76042182009-08-08 16:03:15 +0200568 sms_vp = smsp;
Steffen Neubauerf3262672009-11-26 12:28:41 +0100569 /* the additional functionality indicator... */
Steffen Neubauerac0c13c2009-12-05 12:44:41 +0100570 if (sms_vpf == GSM340_TP_VPF_ENHANCED && *smsp & (1<<7))
571 smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000572 smsp += 7;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000573 break;
Daniel Willmann58c83d82009-08-13 03:40:49 +0200574 case GSM340_TP_VPF_NONE:
575 sms_vp = 0;
576 break;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000577 default:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100578 LOGP(DSMS, LOGL_NOTICE,
579 "SMS Validity period not implemented: 0x%02x\n", sms_vpf);
Harald Welte76042182009-08-08 16:03:15 +0200580 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000581 }
Harald Welte76042182009-08-08 16:03:15 +0200582 gsms->user_data_len = *smsp++;
583 if (gsms->user_data_len) {
584 memcpy(gsms->user_data, smsp, gsms->user_data_len);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000585
Harald Welte76042182009-08-08 16:03:15 +0200586 switch (sms_alphabet) {
Harald Welte7e310b12009-03-30 20:56:32 +0000587 case DCS_7BIT_DEFAULT:
Harald Welte76042182009-08-08 16:03:15 +0200588 gsm_7bit_decode(gsms->text, smsp, gsms->user_data_len);
Harald Welte7e310b12009-03-30 20:56:32 +0000589 break;
590 case DCS_8BIT_DATA:
591 case DCS_UCS2:
592 case DCS_NONE:
Harald Welte7e310b12009-03-30 20:56:32 +0000593 break;
594 }
595 }
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000596
Harald Welted0cf7ba2009-12-24 15:08:18 +0100597 gsms->sender = subscr_get(msg->lchan->subscr);
598
599 LOGP(DSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, "
600 "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, "
601 "UserDataLength: 0x%02x, UserData: \"%s\"\n",
602 subscr_name(gsms->sender), sms_mti, sms_vpf, gsms->msg_ref,
603 gsms->protocol_id, gsms->data_coding_scheme, gsms->dest_addr,
604 gsms->user_data_len,
Harald Welte76042182009-08-08 16:03:15 +0200605 sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
606 hexdump(gsms->user_data, gsms->user_data_len));
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000607
Harald Welte76042182009-08-08 16:03:15 +0200608 gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
Harald Welteb9c758b2009-07-05 14:02:46 +0200609
Harald Welte76042182009-08-08 16:03:15 +0200610 dispatch_signal(SS_SMS, 0, gsms);
Harald Welteb9c758b2009-07-05 14:02:46 +0200611
Harald Welte7e310b12009-03-30 20:56:32 +0000612 /* determine gsms->receiver based on dialled number */
Harald Welte76042182009-08-08 16:03:15 +0200613 gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr);
Harald Welte7e310b12009-03-30 20:56:32 +0000614 if (!gsms->receiver) {
615 rc = 1; /* cause 1: unknown subscriber */
Harald Welteffa55a42009-12-22 19:07:32 +0100616 counter_inc(bts->network->stats.sms.no_receiver);
Harald Welte7e310b12009-03-30 20:56:32 +0000617 goto out;
618 }
619
Harald Welte76042182009-08-08 16:03:15 +0200620 switch (sms_mti) {
Harald Welte7e310b12009-03-30 20:56:32 +0000621 case GSM340_SMS_SUBMIT_MS2SC:
622 /* MS is submitting a SMS */
Harald Welte76042182009-08-08 16:03:15 +0200623 rc = gsm340_rx_sms_submit(msg, gsms);
Harald Welte7e310b12009-03-30 20:56:32 +0000624 break;
625 case GSM340_SMS_COMMAND_MS2SC:
626 case GSM340_SMS_DELIVER_REP_MS2SC:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100627 LOGP(DSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200628 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000629 break;
630 default:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100631 LOGP(DSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200632 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000633 break;
634 }
635
Harald Welteb9c758b2009-07-05 14:02:46 +0200636 if (!rc && !gsms->receiver)
637 rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
638
Harald Welte7e310b12009-03-30 20:56:32 +0000639out:
Harald Welte76042182009-08-08 16:03:15 +0200640 sms_free(gsms);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000641
Harald Welte7e310b12009-03-30 20:56:32 +0000642 return rc;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000643}
644
Harald Weltef3efc592009-07-27 20:11:35 +0200645static int gsm411_send_rp_ack(struct gsm_trans *trans, u_int8_t msg_ref)
Daniel Willmann471712b2008-12-29 01:54:02 +0000646{
647 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000648
Daniel Willmann471712b2008-12-29 01:54:02 +0000649 DEBUGP(DSMS, "TX: SMS RP ACK\n");
650
Harald Weltef3efc592009-07-27 20:11:35 +0200651 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ACK_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000652}
653
Harald Weltef3efc592009-07-27 20:11:35 +0200654static int gsm411_send_rp_error(struct gsm_trans *trans,
655 u_int8_t msg_ref, u_int8_t cause)
Daniel Willmann471712b2008-12-29 01:54:02 +0000656{
657 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000658
Harald Welte7e310b12009-03-30 20:56:32 +0000659 msgb_tv_put(msg, 1, cause);
Daniel Willmann471712b2008-12-29 01:54:02 +0000660
Harald Welted0cf7ba2009-12-24 15:08:18 +0100661 LOGP(DSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200662 get_value_string(rp_cause_strs, cause));
Daniel Willmann471712b2008-12-29 01:54:02 +0000663
Harald Weltef3efc592009-07-27 20:11:35 +0200664 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000665}
666
Harald Welte7e310b12009-03-30 20:56:32 +0000667/* Receive a 04.11 TPDU inside RP-DATA / user data */
Harald Weltef3efc592009-07-27 20:11:35 +0200668static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
669 struct gsm411_rp_hdr *rph,
Harald Welte7e310b12009-03-30 20:56:32 +0000670 u_int8_t src_len, u_int8_t *src,
671 u_int8_t dst_len, u_int8_t *dst,
672 u_int8_t tpdu_len, u_int8_t *tpdu)
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000673{
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000674 int rc = 0;
675
Harald Welte7e310b12009-03-30 20:56:32 +0000676 if (src_len && src)
Harald Welted0cf7ba2009-12-24 15:08:18 +0100677 LOGP(DSMS, LOGL_ERROR, "RP-DATA (MO) with SRC ?!?\n");
Harald Welte7e310b12009-03-30 20:56:32 +0000678
679 if (!dst_len || !dst || !tpdu_len || !tpdu) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100680 LOGP(DSMS, LOGL_ERROR,
681 "RP-DATA (MO) without DST or TPDU ?!?\n");
Harald Weltef3efc592009-07-27 20:11:35 +0200682 gsm411_send_rp_error(trans, rph->msg_ref,
Harald Welteb9c758b2009-07-05 14:02:46 +0200683 GSM411_RP_CAUSE_INV_MAND_INF);
Harald Welte7e310b12009-03-30 20:56:32 +0000684 return -EIO;
685 }
686 msg->smsh = tpdu;
687
688 DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
Harald Welte7e310b12009-03-30 20:56:32 +0000689
690 rc = gsm340_rx_tpdu(msg);
691 if (rc == 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200692 return gsm411_send_rp_ack(trans, rph->msg_ref);
Harald Welte7e310b12009-03-30 20:56:32 +0000693 else if (rc > 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200694 return gsm411_send_rp_error(trans, rph->msg_ref, rc);
Harald Welte7e310b12009-03-30 20:56:32 +0000695 else
696 return rc;
697}
698
699/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
Harald Weltef3efc592009-07-27 20:11:35 +0200700static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
701 struct gsm411_rp_hdr *rph)
Harald Welte7e310b12009-03-30 20:56:32 +0000702{
703 u_int8_t src_len, dst_len, rpud_len;
704 u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
705
706 /* in the MO case, this should always be zero length */
707 src_len = rph->data[0];
708 if (src_len)
709 src = &rph->data[1];
710
711 dst_len = rph->data[1+src_len];
712 if (dst_len)
713 dst = &rph->data[1+src_len+1];
714
715 rpud_len = rph->data[1+src_len+1+dst_len];
716 if (rpud_len)
717 rp_ud = &rph->data[1+src_len+1+dst_len+1];
718
Harald Welteb9c758b2009-07-05 14:02:46 +0200719 DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
720 src_len, dst_len, rpud_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200721 return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst,
Harald Welte7e310b12009-03-30 20:56:32 +0000722 rpud_len, rp_ud);
723}
724
Harald Weltecb8f4432009-08-09 14:59:02 +0200725/* Receive a 04.11 RP-ACK message (response to RP-DATA from us) */
Harald Weltef3efc592009-07-27 20:11:35 +0200726static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
727 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200728{
Harald Welte76042182009-08-08 16:03:15 +0200729 struct gsm_sms *sms = trans->sms.sms;
730
Harald Welteb9c758b2009-07-05 14:02:46 +0200731 /* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
732 * successfully received a SMS. We can now safely mark it as
733 * transmitted */
734
Harald Weltecb8f4432009-08-09 14:59:02 +0200735 if (!trans->sms.is_mt) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100736 LOGP(DSMS, LOGL_ERROR, "RX RP-ACK on a MO transfer ?\n");
Harald Weltecb8f4432009-08-09 14:59:02 +0200737 return gsm411_send_rp_error(trans, rph->msg_ref,
738 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
739 }
Harald Welte3e0f6172009-07-09 23:52:59 +0200740
Harald Welte76042182009-08-08 16:03:15 +0200741 if (!sms) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100742 LOGP(DSMS, LOGL_ERROR, "RX RP-ACK but no sms in transaction?!?\n");
Harald Weltecb8f4432009-08-09 14:59:02 +0200743 return gsm411_send_rp_error(trans, rph->msg_ref,
744 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte76042182009-08-08 16:03:15 +0200745 }
746
747 /* mark this SMS as sent in database */
748 db_sms_mark_sent(sms);
749
750 dispatch_signal(SS_SMS, S_SMS_DELIVERED, sms);
751
752 sms_free(sms);
753 trans->sms.sms = NULL;
754
Sylvain Munaut6b0b1032009-09-27 11:16:22 +0200755 /* free the transaction here */
756 trans_free(trans);
Harald Weltecf6a3812009-08-09 19:07:41 +0200757
758 /* check for more messages for this subscriber */
759 sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr);
760 if (sms)
761 gsm411_send_sms_lchan(msg->lchan, sms);
762 else
Harald Welte (local)daef6062009-08-14 11:41:12 +0200763 rsl_release_request(msg->lchan, trans->sms.link_id);
Harald Welte76042182009-08-08 16:03:15 +0200764
765 return 0;
Harald Welteb9c758b2009-07-05 14:02:46 +0200766}
767
Harald Weltef3efc592009-07-27 20:11:35 +0200768static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
769 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200770{
Harald Welteffa55a42009-12-22 19:07:32 +0100771 struct gsm_network *net = trans->lchan->ts->trx->bts->network;
Harald Welte76042182009-08-08 16:03:15 +0200772 struct gsm_sms *sms = trans->sms.sms;
Harald Weltef3efc592009-07-27 20:11:35 +0200773 u_int8_t cause_len = rph->data[0];
774 u_int8_t cause = rph->data[1];
775
Harald Welteb9c758b2009-07-05 14:02:46 +0200776 /* Error in response to MT RP_DATA, i.e. the MS did not
777 * successfully receive the SMS. We need to investigate
778 * the cause and take action depending on it */
779
Harald Welted0cf7ba2009-12-24 15:08:18 +0100780 LOGP(DSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
781 subscr_name(msg->lchan->subscr), cause_len, cause,
782 get_value_string(rp_cause_strs, cause));
Harald Weltef3efc592009-07-27 20:11:35 +0200783
Harald Weltecb8f4432009-08-09 14:59:02 +0200784 if (!trans->sms.is_mt) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100785 LOGP(DSMS, LOGL_ERROR, "RX RP-ERR on a MO transfer ?\n");
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200786#if 0
Harald Weltecb8f4432009-08-09 14:59:02 +0200787 return gsm411_send_rp_error(trans, rph->msg_ref,
788 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200789#endif
Harald Weltecb8f4432009-08-09 14:59:02 +0200790 }
Harald Welte3e0f6172009-07-09 23:52:59 +0200791
Harald Welte76042182009-08-08 16:03:15 +0200792 if (!sms) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100793 LOGP(DSMS, LOGL_ERROR,
794 "RX RP-ERR, but no sms in transaction?!?\n");
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200795 return -EINVAL;
796#if 0
Harald Weltecb8f4432009-08-09 14:59:02 +0200797 return gsm411_send_rp_error(trans, rph->msg_ref,
798 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200799#endif
Harald Weltecb8f4432009-08-09 14:59:02 +0200800 }
801
802 if (cause == GSM411_RP_CAUSE_MT_MEM_EXCEEDED) {
803 /* MS has not enough memory to store the message. We need
804 * to store this in our database and wati for a SMMA message */
805 /* FIXME */
806 dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr);
Harald Welteffa55a42009-12-22 19:07:32 +0100807 counter_inc(net->stats.sms.rp_err_mem);
Harald Welte24ff6ee2009-12-22 00:41:05 +0100808 } else
Harald Welteffa55a42009-12-22 19:07:32 +0100809 counter_inc(net->stats.sms.rp_err_other);
Harald Welte76042182009-08-08 16:03:15 +0200810
811 sms_free(sms);
812 trans->sms.sms = NULL;
813
Harald Welte (local)86b17172009-08-14 14:52:17 +0200814 //trans_free(trans);
Harald Welte76042182009-08-08 16:03:15 +0200815
Harald Weltef3efc592009-07-27 20:11:35 +0200816 return 0;
Harald Welteb9c758b2009-07-05 14:02:46 +0200817}
818
Harald Weltef3efc592009-07-27 20:11:35 +0200819static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans,
820 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200821{
Harald Weltecf6a3812009-08-09 19:07:41 +0200822 struct gsm_sms *sms;
Harald Weltef3efc592009-07-27 20:11:35 +0200823 int rc;
824
Harald Weltecf6a3812009-08-09 19:07:41 +0200825 rc = gsm411_send_rp_ack(trans, rph->msg_ref);
826 trans->sms.rp_state = GSM411_RPS_IDLE;
827
Harald Welteb9c758b2009-07-05 14:02:46 +0200828 /* MS tells us that it has memory for more SMS, we need
829 * to check if we have any pending messages for it and then
830 * transfer those */
Harald Welte76042182009-08-08 16:03:15 +0200831 dispatch_signal(SS_SMS, S_SMS_SMMA, trans->subscr);
Harald Weltef3efc592009-07-27 20:11:35 +0200832
Harald Weltecf6a3812009-08-09 19:07:41 +0200833 /* check for more messages for this subscriber */
834 sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr);
835 if (sms)
836 gsm411_send_sms_lchan(msg->lchan, sms);
837 else
Harald Welte (local)daef6062009-08-14 11:41:12 +0200838 rsl_release_request(msg->lchan, trans->sms.link_id);
Harald Weltef3efc592009-07-27 20:11:35 +0200839
840 return rc;
Harald Welteb9c758b2009-07-05 14:02:46 +0200841}
842
Harald Weltef3efc592009-07-27 20:11:35 +0200843static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
844 struct gsm_trans *trans)
Harald Welte7e310b12009-03-30 20:56:32 +0000845{
Daniel Willmann471712b2008-12-29 01:54:02 +0000846 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000847 u_int8_t msg_type = rp_data->msg_type & 0x07;
Harald Welte7e310b12009-03-30 20:56:32 +0000848 int rc = 0;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000849
850 switch (msg_type) {
851 case GSM411_MT_RP_DATA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200852 DEBUGP(DSMS, "RX SMS RP-DATA (MO)\n");
853 /* start TR2N and enter 'wait to send RP-ACK state' */
854 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
855 rc = gsm411_rx_rp_data(msg, trans, rp_data);
Harald Welte7e310b12009-03-30 20:56:32 +0000856 break;
857 case GSM411_MT_RP_ACK_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200858 DEBUGP(DSMS,"RX SMS RP-ACK (MO)\n");
859 rc = gsm411_rx_rp_ack(msg, trans, rp_data);
Harald Welteb9c758b2009-07-05 14:02:46 +0200860 break;
Harald Welte7e310b12009-03-30 20:56:32 +0000861 case GSM411_MT_RP_SMMA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200862 DEBUGP(DSMS, "RX SMS RP-SMMA\n");
863 /* start TR2N and enter 'wait to send RP-ACK state' */
864 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
865 rc = gsm411_rx_rp_smma(msg, trans, rp_data);
866 break;
867 case GSM411_MT_RP_ERROR_MO:
868 rc = gsm411_rx_rp_error(msg, trans, rp_data);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000869 break;
870 default:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100871 LOGP(DSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type);
Harald Weltef3efc592009-07-27 20:11:35 +0200872 rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
873 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000874 break;
875 }
876
877 return rc;
878}
879
Harald Weltef3efc592009-07-27 20:11:35 +0200880/* send CP-ACK to given transaction */
881static int gsm411_tx_cp_ack(struct gsm_trans *trans)
882{
883 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltecf6a3812009-08-09 19:07:41 +0200884 int rc;
Harald Weltef3efc592009-07-27 20:11:35 +0200885
Harald Weltecf6a3812009-08-09 19:07:41 +0200886 rc = gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ACK);
887
888 if (trans->sms.is_mt) {
889 /* If this is a MT SMS DELIVER, we can clear transaction here */
890 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Welte (local)86b17172009-08-14 14:52:17 +0200891 //trans_free(trans);
Harald Weltecf6a3812009-08-09 19:07:41 +0200892 }
Holger Hans Peter Freyther09e364b2009-08-10 07:59:27 +0200893
894 return rc;
Harald Weltef3efc592009-07-27 20:11:35 +0200895}
896
897static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
898{
899 struct msgb *msg = gsm411_msgb_alloc();
900 u_int8_t *causep;
901
Harald Welted0cf7ba2009-12-24 15:08:18 +0100902 LOGP(DSMS, LOGL_NOTICE, "TX CP-ERROR, cause %d (%s)\n", cause,
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200903 get_value_string(cp_cause_strs, cause));
904
Harald Welte76042182009-08-08 16:03:15 +0200905 causep = msgb_put(msg, 1);
Harald Weltef3efc592009-07-27 20:11:35 +0200906 *causep = cause;
907
908 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ERROR);
909}
910
911/* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */
Harald Welte (local)daef6062009-08-14 11:41:12 +0200912int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id)
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000913{
914 struct gsm48_hdr *gh = msgb_l3(msg);
915 u_int8_t msg_type = gh->msg_type;
Harald Weltef3efc592009-07-27 20:11:35 +0200916 u_int8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
917 struct gsm_lchan *lchan = msg->lchan;
918 struct gsm_trans *trans;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000919 int rc = 0;
920
Harald Weltef3efc592009-07-27 20:11:35 +0200921 if (!lchan->subscr)
922 return -EIO;
923 /* FIXME: send some error message */
924
Sylvain Munautc56a1412009-12-18 18:28:08 +0100925 DEBUGP(DSMS, "trans_id=%x ", transaction_id);
Harald Weltef3efc592009-07-27 20:11:35 +0200926 trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS,
927 transaction_id);
928 if (!trans) {
Sylvain Munautfeaca922009-12-18 18:28:09 +0100929 DEBUGPC(DSMS, "(new) ");
Harald Weltef3efc592009-07-27 20:11:35 +0200930 trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
931 transaction_id, new_callref++);
932 if (!trans) {
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200933 DEBUGPC(DSMS, "No memory for trans\n");
Harald Weltef3efc592009-07-27 20:11:35 +0200934 /* FIXME: send some error message */
935 return -ENOMEM;
936 }
937 trans->sms.cp_state = GSM411_CPS_IDLE;
938 trans->sms.rp_state = GSM411_RPS_IDLE;
939 trans->sms.is_mt = 0;
Harald Welte (local)daef6062009-08-14 11:41:12 +0200940 trans->sms.link_id = link_id;
Harald Weltef3efc592009-07-27 20:11:35 +0200941
942 trans->lchan = lchan;
943 use_lchan(lchan);
944 }
945
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000946 switch(msg_type) {
947 case GSM411_MT_CP_DATA:
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200948 DEBUGPC(DSMS, "RX SMS CP-DATA\n");
Harald Weltecb8f4432009-08-09 14:59:02 +0200949 /* 5.2.3.1.3: MO state exists when SMC has received
950 * CP-DATA, including sending of the assoc. CP-ACK */
951 /* 5.2.3.2.4: MT state exists when SMC has received
952 * CP-DATA, including sending of the assoc. CP-ACK */
953 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Weltef3efc592009-07-27 20:11:35 +0200954
Harald Welte (local)daef6062009-08-14 11:41:12 +0200955 /* SMC instance acknowledges the CP-DATA frame */
956 gsm411_tx_cp_ack(trans);
957
Harald Weltef3efc592009-07-27 20:11:35 +0200958 rc = gsm411_rx_cp_data(msg, gh, trans);
Harald Welte (local)daef6062009-08-14 11:41:12 +0200959#if 0
Harald Weltef3efc592009-07-27 20:11:35 +0200960 /* Send CP-ACK or CP-ERORR in response */
961 if (rc < 0) {
962 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_NET_FAIL);
963 } else
964 rc = gsm411_tx_cp_ack(trans);
Harald Welte (local)daef6062009-08-14 11:41:12 +0200965#endif
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000966 break;
967 case GSM411_MT_CP_ACK:
Harald Weltef3efc592009-07-27 20:11:35 +0200968 /* previous CP-DATA in this transaction was confirmed */
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200969 DEBUGPC(DSMS, "RX SMS CP-ACK\n");
Harald Weltecb8f4432009-08-09 14:59:02 +0200970 /* 5.2.3.1.3: MO state exists when SMC has received CP-ACK */
971 /* 5.2.3.2.4: MT state exists when SMC has received CP-ACK */
972 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Welte41985612009-08-10 00:24:32 +0200973 /* Stop TC1* after CP-ACK has been received */
974 bsc_del_timer(&trans->sms.cp_timer);
Harald Weltecb8f4432009-08-09 14:59:02 +0200975
Harald Weltef3efc592009-07-27 20:11:35 +0200976 if (!trans->sms.is_mt) {
Harald Weltef3efc592009-07-27 20:11:35 +0200977 /* FIXME: we have sont one CP-DATA, which was now
978 * acknowledged. Check if we want to transfer more,
979 * i.e. multi-part message */
980 trans->sms.cp_state = GSM411_CPS_IDLE;
981 trans_free(trans);
982 }
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000983 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000984 case GSM411_MT_CP_ERROR:
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200985 DEBUGPC(DSMS, "RX SMS CP-ERROR, cause %d (%s)\n", gh->data[0],
986 get_value_string(cp_cause_strs, gh->data[0]));
Harald Welte41985612009-08-10 00:24:32 +0200987 bsc_del_timer(&trans->sms.cp_timer);
Harald Weltef3efc592009-07-27 20:11:35 +0200988 trans->sms.cp_state = GSM411_CPS_IDLE;
989 trans_free(trans);
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000990 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000991 default:
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200992 DEBUGPC(DSMS, "RX Unimplemented CP msg_type: 0x%02x\n", msg_type);
Harald Weltef3efc592009-07-27 20:11:35 +0200993 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
Harald Weltecb8f4432009-08-09 14:59:02 +0200994 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Weltef3efc592009-07-27 20:11:35 +0200995 trans_free(trans);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000996 break;
997 }
998
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000999 return rc;
1000}
1001
Harald Welte8c2e36e2008-12-30 15:00:14 +00001002#if 0
Daniel Willmann3b3f0012008-12-30 13:56:46 +00001003/* Test TPDU - ALL YOUR */
1004static u_int8_t tpdu_test[] = {
1005 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
1006 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
1007 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
1008 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
Daniel Willmanne2a728d2008-12-30 14:03:09 +00001009};
Harald Welte8c2e36e2008-12-30 15:00:14 +00001010#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001011
Harald Weltecf6a3812009-08-09 19:07:41 +02001012/* Take a SMS in gsm_sms structure and send it through an already
1013 * existing lchan. We also assume that the caller ensured this lchan already
1014 * has a SAPI3 RLL connection! */
Harald Welte76042182009-08-08 16:03:15 +02001015int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001016{
1017 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltef3efc592009-07-27 20:11:35 +02001018 struct gsm_trans *trans;
Harald Welte76042182009-08-08 16:03:15 +02001019 u_int8_t *data, *rp_ud_len;
Harald Welte87f5d632009-07-04 17:39:00 +02001020 u_int8_t msg_ref = 42;
Harald Weltecf6a3812009-08-09 19:07:41 +02001021 u_int8_t transaction_id;
Harald Welte76042182009-08-08 16:03:15 +02001022 int rc;
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001023
Harald Welte49839212009-12-22 13:45:58 +01001024 transaction_id = trans_assign_trans_id(lchan->subscr, GSM48_PDISC_SMS, 0);
1025 if (transaction_id == -1) {
Harald Welted0cf7ba2009-12-24 15:08:18 +01001026 LOGP(DSMS, LOGL_ERROR, "No available transaction ids\n");
Harald Welte49839212009-12-22 13:45:58 +01001027 return -EBUSY;
1028 }
Harald Weltecf6a3812009-08-09 19:07:41 +02001029
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001030 msg->lchan = lchan;
1031
Harald Welte76042182009-08-08 16:03:15 +02001032 DEBUGP(DSMS, "send_sms_lchan()\n");
Harald Weltef3efc592009-07-27 20:11:35 +02001033
Harald Welte76042182009-08-08 16:03:15 +02001034 /* FIXME: allocate transaction with message reference */
1035 trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
1036 transaction_id, new_callref++);
1037 if (!trans) {
Harald Welted0cf7ba2009-12-24 15:08:18 +01001038 LOGP(DSMS, LOGL_ERROR, "No memory for trans\n");
Harald Welte76042182009-08-08 16:03:15 +02001039 /* FIXME: send some error message */
1040 return -ENOMEM;
1041 }
1042 trans->sms.cp_state = GSM411_CPS_IDLE;
1043 trans->sms.rp_state = GSM411_RPS_IDLE;
1044 trans->sms.is_mt = 1;
1045 trans->sms.sms = sms;
Harald Welte (local)daef6062009-08-14 11:41:12 +02001046 trans->sms.link_id = UM_SAPI_SMS; /* FIXME: main or SACCH ? */
Harald Welte76042182009-08-08 16:03:15 +02001047
1048 trans->lchan = lchan;
1049 use_lchan(lchan);
1050
1051 /* Hardcode SMSC Originating Address for now */
Daniel Willmanna3e29842008-12-29 16:03:54 +00001052 data = (u_int8_t *)msgb_put(msg, 8);
Harald Welte87f5d632009-07-04 17:39:00 +02001053 data[0] = 0x07; /* originator length == 7 */
Harald Welteb9c758b2009-07-05 14:02:46 +02001054 data[1] = 0x91; /* type of number: international, ISDN */
1055 data[2] = 0x44; /* 447785016005 */
Daniel Willmanna3e29842008-12-29 16:03:54 +00001056 data[3] = 0x77;
1057 data[4] = 0x58;
1058 data[5] = 0x10;
1059 data[6] = 0x06;
1060 data[7] = 0x50;
Harald Welte87f5d632009-07-04 17:39:00 +02001061
1062 /* Hardcoded Destination Address */
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001063 data = (u_int8_t *)msgb_put(msg, 1);
Harald Welte87f5d632009-07-04 17:39:00 +02001064 data[0] = 0; /* destination length == 0 */
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001065
Harald Welte76042182009-08-08 16:03:15 +02001066 /* obtain a pointer for the rp_ud_len, so we can fill it later */
1067 rp_ud_len = (u_int8_t *)msgb_put(msg, 1);
Daniel Willmann4a1e8792008-12-29 06:23:56 +00001068
Harald Welte76042182009-08-08 16:03:15 +02001069#if 1
1070 /* generate the 03.40 TPDU */
1071 rc = gsm340_gen_tpdu(msg, sms);
1072 if (rc < 0) {
1073 msgb_free(msg);
1074 return rc;
1075 }
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001076
Harald Welte76042182009-08-08 16:03:15 +02001077 *rp_ud_len = rc;
1078#else
1079 data = msgb_put(msg, sizeof(tpdu_test));
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001080 memcpy(data, tpdu_test, sizeof(tpdu_test));
Harald Welte76042182009-08-08 16:03:15 +02001081 *rp_ud_len = sizeof(tpdu_test);
1082#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001083
Harald Welte76042182009-08-08 16:03:15 +02001084 DEBUGP(DSMS, "TX: SMS DELIVER\n");
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001085
Harald Welteffa55a42009-12-22 19:07:32 +01001086 counter_inc(lchan->ts->trx->bts->network->stats.sms.delivered);
Harald Welte24ff6ee2009-12-22 00:41:05 +01001087
Harald Weltef3efc592009-07-27 20:11:35 +02001088 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
1089 /* FIXME: enter 'wait for RP-ACK' state, start TR1N */
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001090}
Harald Weltef3efc592009-07-27 20:11:35 +02001091
Harald Weltecf6a3812009-08-09 19:07:41 +02001092/* RLL SAPI3 establish callback. Now we have a RLL connection and
1093 * can deliver the actual message */
Harald Weltecb8f4432009-08-09 14:59:02 +02001094static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
1095 void *_sms, enum bsc_rllr_ind type)
1096{
1097 struct gsm_sms *sms = _sms;
1098
1099 DEBUGP(DSMS, "rll_ind_cb(lchan=%p, link_id=%u, sms=%p, type=%u\n",
1100 lchan, link_id, sms, type);
1101
1102 switch (type) {
1103 case BSC_RLLR_IND_EST_CONF:
1104 gsm411_send_sms_lchan(lchan, sms);
1105 break;
1106 case BSC_RLLR_IND_REL_IND:
1107 case BSC_RLLR_IND_ERR_IND:
1108 case BSC_RLLR_IND_TIMEOUT:
1109 sms_free(sms);
1110 break;
1111 }
1112}
1113
Harald Weltecf6a3812009-08-09 19:07:41 +02001114/* paging callback. Here we get called if paging a subscriber has
1115 * succeeded or failed. */
Harald Welte76042182009-08-08 16:03:15 +02001116static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
1117 struct msgb *msg, void *_lchan, void *_sms)
Harald Weltef3efc592009-07-27 20:11:35 +02001118{
Harald Welte76042182009-08-08 16:03:15 +02001119 struct gsm_lchan *lchan = _lchan;
1120 struct gsm_sms *sms = _sms;
1121 int rc;
Harald Weltef3efc592009-07-27 20:11:35 +02001122
Harald Welte76042182009-08-08 16:03:15 +02001123 DEBUGP(DSMS, "paging_cb_send_sms(hooknum=%u, event=%u, msg=%p,"
1124 "lchan=%p, sms=%p)\n", hooknum, event, msg, lchan, sms);
1125
1126 if (hooknum != GSM_HOOK_RR_PAGING)
1127 return -EINVAL;
1128
1129 switch (event) {
1130 case GSM_PAGING_SUCCEEDED:
1131 /* Paging aborted without lchan ?!? */
1132 if (!lchan) {
1133 sms_free(sms);
1134 rc = -EIO;
1135 break;
1136 }
Harald Weltecf6a3812009-08-09 19:07:41 +02001137 /* Establish a SAPI3 RLL connection for SMS */
Harald Weltecb8f4432009-08-09 14:59:02 +02001138 rc = rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
Harald Welte76042182009-08-08 16:03:15 +02001139 break;
1140 case GSM_PAGING_EXPIRED:
1141 sms_free(sms);
1142 rc = -ETIMEDOUT;
1143 break;
1144 default:
1145 rc = -EINVAL;
1146 break;
1147 }
1148
1149 return rc;
1150}
1151
Harald Weltecf6a3812009-08-09 19:07:41 +02001152/* high-level function to send a SMS to a given subscriber. The function
1153 * will take care of paging the subscriber, establishing the RLL SAPI3
1154 * connection, etc. */
Harald Welte76042182009-08-08 16:03:15 +02001155int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
1156 struct gsm_sms *sms)
1157{
Harald Weltecf6a3812009-08-09 19:07:41 +02001158 struct gsm_lchan *lchan;
Harald Weltee903edf2009-08-15 03:16:17 +02001159 int rc;
Harald Weltecf6a3812009-08-09 19:07:41 +02001160
Harald Welte76042182009-08-08 16:03:15 +02001161 /* check if we already have an open lchan to the subscriber.
1162 * if yes, send the SMS this way */
Harald Weltecf6a3812009-08-09 19:07:41 +02001163 lchan = lchan_for_subscr(subscr);
1164 if (lchan)
1165 return rll_establish(lchan, UM_SAPI_SMS,
1166 rll_ind_cb, sms);
Harald Welte76042182009-08-08 16:03:15 +02001167
1168 /* if not, we have to start paging */
Harald Weltee903edf2009-08-15 03:16:17 +02001169 rc = paging_request(subscr->net, subscr, RSL_CHANNEED_SDCCH,
1170 paging_cb_send_sms, sms);
Harald Welte (local)0abaf332009-08-15 11:25:45 +02001171 if (rc <= 0)
Harald Weltee903edf2009-08-15 03:16:17 +02001172 sms_free(sms);
Harald Welte76042182009-08-08 16:03:15 +02001173
1174 return 0;
1175}
Harald Welte3366a942009-07-28 00:44:49 +02001176
Harald Weltecf6a3812009-08-09 19:07:41 +02001177static int subscr_sig_cb(unsigned int subsys, unsigned int signal,
1178 void *handler_data, void *signal_data)
1179{
1180 struct gsm_subscriber *subscr;
1181 struct gsm_lchan *lchan;
1182 struct gsm_sms *sms;
1183
1184 switch (signal) {
1185 case S_SUBSCR_ATTACHED:
1186 /* A subscriber has attached. Check if there are
1187 * any pending SMS for him to be delivered */
1188 subscr = signal_data;
1189 lchan = lchan_for_subscr(subscr);
1190 if (!lchan)
1191 break;
1192 sms = db_sms_get_unsent_for_subscr(subscr);
1193 if (!sms)
1194 break;
1195 /* Establish a SAPI3 RLL connection for SMS */
1196 rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
1197 break;
1198 default:
1199 break;
1200 }
1201 return 0;
1202}
1203
Harald Welte (local)86b17172009-08-14 14:52:17 +02001204void _gsm411_sms_trans_free(struct gsm_trans *trans)
1205{
1206 bsc_del_timer(&trans->sms.cp_timer);
1207}
1208
Harald Welte7bfc2672009-07-28 00:41:45 +02001209static __attribute__((constructor)) void on_dso_load_sms(void)
1210{
Harald Weltecf6a3812009-08-09 19:07:41 +02001211 register_signal_handler(SS_SUBSCR, subscr_sig_cb, NULL);
Harald Welte7bfc2672009-07-28 00:41:45 +02001212}