blob: a3469137582380521a9291bd4363687e586f3ff0 [file] [log] [blame]
Harald Welte59b04682009-06-10 05:40:52 +08001/* Point-to-Point (PP) Short Message Service (SMS)
2 * Support on Mobile Radio Interface
3 * 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0 */
4
5/* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
6 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
7 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 *
24 */
25
26
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +010027#include <assert.h>
Harald Welte59b04682009-06-10 05:40:52 +080028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <errno.h>
Harald Welteb78996d2009-07-27 20:11:35 +020032#include <time.h>
Harald Welte59b04682009-06-10 05:40:52 +080033#include <netinet/in.h>
34
Harald Weltef4625b12010-02-20 16:24:02 +010035#include <osmocore/msgb.h>
36#include <osmocore/tlv.h>
Harald Welte59b04682009-06-10 05:40:52 +080037#include <openbsc/debug.h>
38#include <openbsc/gsm_data.h>
39#include <openbsc/gsm_subscriber.h>
40#include <openbsc/gsm_04_11.h>
41#include <openbsc/gsm_04_08.h>
Harald Weltef4625b12010-02-20 16:24:02 +010042#include <osmocore/gsm_utils.h>
Harald Welte59b04682009-06-10 05:40:52 +080043#include <openbsc/abis_rsl.h>
44#include <openbsc/signal.h>
45#include <openbsc/db.h>
Harald Weltef4625b12010-02-20 16:24:02 +010046#include <osmocore/talloc.h>
Harald Welteb78996d2009-07-27 20:11:35 +020047#include <openbsc/transaction.h>
Harald Welte68b7df22009-08-08 16:03:15 +020048#include <openbsc/paging.h>
Harald Welte09421d32009-08-09 14:59:02 +020049#include <openbsc/bsc_rll.h>
Holger Hans Peter Freyther735cd9e2009-08-10 07:54:02 +020050#include <openbsc/chan_alloc.h>
Holger Hans Peter Freyther8b820fe2010-05-23 21:05:18 +080051#include <openbsc/bsc_api.h>
Harald Welte59b04682009-06-10 05:40:52 +080052
53#define GSM411_ALLOC_SIZE 1024
54#define GSM411_ALLOC_HEADROOM 128
55
Harald Welte09421d32009-08-09 14:59:02 +020056#define UM_SAPI_SMS 3 /* See GSM 04.05/04.06 */
57
Harald Welte (local)8751ee92009-08-15 02:30:58 +020058void *tall_gsms_ctx;
Harald Welteb78996d2009-07-27 20:11:35 +020059static u_int32_t new_callref = 0x40000001;
60
Harald Welte (local)cb4715c2009-08-14 10:42:43 +020061static const struct value_string cp_cause_strs[] = {
62 { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
63 { GSM411_CP_CAUSE_CONGESTION, "Congestion" },
64 { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
65 { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
66 { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
67 { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +020068 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
Harald Welte (local)cb4715c2009-08-14 10:42:43 +020069 "Message incompatible with protocol state" },
70 { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
71 { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
72 { 0, 0 }
73};
74
75static const struct value_string rp_cause_strs[] = {
76 { GSM411_RP_CAUSE_MO_NUM_UNASSIGNED, "(MO) Number not assigned" },
77 { GSM411_RP_CAUSE_MO_OP_DET_BARR, "(MO) Operator determined barring" },
78 { GSM411_RP_CAUSE_MO_CALL_BARRED, "(MO) Call barred" },
79 { GSM411_RP_CAUSE_MO_SMS_REJECTED, "(MO) SMS rejected" },
80 { GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER, "(MO) Destination out of order" },
81 { GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR, "(MO) Unidentified subscriber" },
82 { GSM411_RP_CAUSE_MO_FACILITY_REJ, "(MO) Facility reject" },
83 { GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR, "(MO) Unknown subscriber" },
84 { GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER, "(MO) Network out of order" },
85 { GSM411_RP_CAUSE_MO_TEMP_FAIL, "(MO) Temporary failure" },
86 { GSM411_RP_CAUSE_MO_CONGESTION, "(MO) Congestion" },
87 { GSM411_RP_CAUSE_MO_RES_UNAVAIL, "(MO) Resource unavailable" },
88 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR, "(MO) Requested facility not subscribed" },
89 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL, "(MO) Requested facility not implemented" },
90 { GSM411_RP_CAUSE_MO_INTERWORKING, "(MO) Interworking" },
91 /* valid only for MT */
92 { GSM411_RP_CAUSE_MT_MEM_EXCEEDED, "(MT) Memory Exceeded" },
93 /* valid for both directions */
94 { GSM411_RP_CAUSE_INV_TRANS_REF, "Invalid Transaction Reference" },
95 { GSM411_RP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
96 { GSM411_RP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
97 { GSM411_RP_CAUSE_MSGTYPE_NOTEXIST, "Message Type non-existant" },
98 { GSM411_RP_CAUSE_MSG_INCOMP_STATE, "Message incompatible with protocol state" },
99 { GSM411_RP_CAUSE_IE_NOTEXIST, "Information Element not existing" },
100 { GSM411_RP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
101 { 0, NULL }
102};
103
Harald Welte68b7df22009-08-08 16:03:15 +0200104struct gsm_sms *sms_alloc(void)
105{
106 return talloc_zero(tall_gsms_ctx, struct gsm_sms);
107}
108
109void sms_free(struct gsm_sms *sms)
110{
111 /* drop references to subscriber structure */
112 if (sms->sender)
113 subscr_put(sms->sender);
114 if (sms->receiver)
115 subscr_put(sms->receiver);
116
117 talloc_free(sms);
118}
119
Harald Welte59b04682009-06-10 05:40:52 +0800120struct msgb *gsm411_msgb_alloc(void)
121{
Harald Welte9cfc9352009-06-26 19:39:35 +0200122 return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
123 "GSM 04.11");
Harald Welte59b04682009-06-10 05:40:52 +0800124}
125
Holger Hans Peter Freyther7cdff242010-03-23 07:40:46 +0100126static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *msg, u_int8_t link_id)
Harald Welte59b04682009-06-10 05:40:52 +0800127{
Harald Welte68b7df22009-08-08 16:03:15 +0200128 DEBUGP(DSMS, "GSM4.11 TX %s\n", hexdump(msg->data, msg->len));
Holger Hans Peter Freyther7cdff242010-03-23 07:40:46 +0100129 msg->l3h = msg->data;
130 return gsm0808_submit_dtap(conn, msg, link_id);
Harald Welte59b04682009-06-10 05:40:52 +0800131}
132
Harald Welte5fa17a22009-08-10 00:24:32 +0200133/* SMC TC1* is expired */
134static void cp_timer_expired(void *data)
135{
136 struct gsm_trans *trans = data;
137
138 DEBUGP(DSMS, "SMC Timer TC1* is expired, calling trans_free()\n");
139 /* FIXME: we need to re-transmit the last CP-DATA 1..3 times */
140 trans_free(trans);
141}
142
Harald Welte7e2f57d2009-07-04 17:39:00 +0200143/* Prefix msg with a 04.08/04.11 CP header */
Harald Welteb78996d2009-07-27 20:11:35 +0200144static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
145 u_int8_t msg_type)
Harald Welte7e2f57d2009-07-04 17:39:00 +0200146{
147 struct gsm48_hdr *gh;
148
149 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
150 /* Outgoing needs the highest bit set */
Harald Welteb78996d2009-07-27 20:11:35 +0200151 gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
Harald Welte7e2f57d2009-07-04 17:39:00 +0200152 gh->msg_type = msg_type;
153
Harald Welteb78996d2009-07-27 20:11:35 +0200154 /* mobile originating */
155 switch (gh->msg_type) {
156 case GSM411_MT_CP_DATA:
157 /* 5.2.3.1.2: enter MO-wait for CP-ack */
Harald Welte09421d32009-08-09 14:59:02 +0200158 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
Harald Welteb78996d2009-07-27 20:11:35 +0200159 trans->sms.cp_state = GSM411_CPS_WAIT_CP_ACK;
Harald Welte5fa17a22009-08-10 00:24:32 +0200160 trans->sms.cp_timer.data = trans;
161 trans->sms.cp_timer.cb = cp_timer_expired;
162 /* 5.3.2.1: Set Timer TC1A */
163 bsc_schedule_timer(&trans->sms.cp_timer, GSM411_TMR_TC1A);
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200164 DEBUGP(DSMS, "TX: CP-DATA ");
165 break;
166 case GSM411_MT_CP_ACK:
167 DEBUGP(DSMS, "TX: CP-ACK ");
168 break;
169 case GSM411_MT_CP_ERROR:
Sylvain Munaut163a24a2009-12-18 18:28:07 +0100170 DEBUGP(DSMS, "TX: CP-ERROR ");
Harald Welteb78996d2009-07-27 20:11:35 +0200171 break;
172 }
173
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200174 DEBUGPC(DSMS, "trans=%x\n", trans->transaction_id);
175
Holger Hans Peter Freyther7cdff242010-03-23 07:40:46 +0100176 return gsm411_sendmsg(trans->conn, msg, trans->sms.link_id);
Harald Welte7e2f57d2009-07-04 17:39:00 +0200177}
178
179/* Prefix msg with a RP-DATA header and send as CP-DATA */
Harald Welteb78996d2009-07-27 20:11:35 +0200180static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
181 u_int8_t rp_msg_type, u_int8_t rp_msg_ref)
Harald Welte7e2f57d2009-07-04 17:39:00 +0200182{
183 struct gsm411_rp_hdr *rp;
Harald Weltef2e680b2009-08-10 00:22:19 +0200184 u_int8_t len = msg->len;
Harald Welte7e2f57d2009-07-04 17:39:00 +0200185
186 /* GSM 04.11 RP-DATA header */
187 rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
Harald Weltef2e680b2009-08-10 00:22:19 +0200188 rp->len = len + 2;
Harald Welte7e2f57d2009-07-04 17:39:00 +0200189 rp->msg_type = rp_msg_type;
190 rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */
191
Harald Welteb78996d2009-07-27 20:11:35 +0200192 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA);
Harald Welte7e2f57d2009-07-04 17:39:00 +0200193}
194
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100195/* Turn int into semi-octet representation: 98 => 0x89 */
196static u_int8_t bcdify(u_int8_t value)
197{
198 u_int8_t ret;
Steffen Neubauer94436952009-11-11 23:02:07 +0900199
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100200 ret = value / 10;
201 ret |= (value % 10) << 4;
202
203 return ret;
204}
205
206/* Turn semi-octet representation into int: 0x89 => 98 */
207static u_int8_t unbcdify(u_int8_t value)
208{
209 u_int8_t ret;
210
211 if ((value & 0x0F) > 9 || (value >> 4) > 9)
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200212 LOGP(DSMS, LOGL_ERROR,
Harald Welteced9a912009-12-24 15:08:18 +0100213 "unbcdify got too big nibble: 0x%02X\n", value);
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100214
215 ret = (value&0x0F)*10;
Steffen Neubauere5e0eb72009-11-26 23:38:41 +0100216 ret += value>>4;
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100217
218 return ret;
219}
220
221/* Generate 03.40 TP-SCTS */
222static void gsm340_gen_scts(u_int8_t *scts, time_t time)
223{
224 struct tm *tm = localtime(&time);
225
226 *scts++ = bcdify(tm->tm_year % 100);
227 *scts++ = bcdify(tm->tm_mon + 1);
228 *scts++ = bcdify(tm->tm_mday);
229 *scts++ = bcdify(tm->tm_hour);
230 *scts++ = bcdify(tm->tm_min);
231 *scts++ = bcdify(tm->tm_sec);
232 *scts++ = bcdify(tm->tm_gmtoff/(60*15));
233}
234
235/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */
236static time_t gsm340_scts(u_int8_t *scts)
237{
238 struct tm tm;
239
240 u_int8_t yr = unbcdify(*scts++);
241
242 if (yr <= 80)
243 tm.tm_year = 100 + yr;
244 else
245 tm.tm_year = yr;
246 tm.tm_mon = unbcdify(*scts++) - 1;
247 tm.tm_mday = unbcdify(*scts++);
248 tm.tm_hour = unbcdify(*scts++);
249 tm.tm_min = unbcdify(*scts++);
250 tm.tm_sec = unbcdify(*scts++);
251 /* according to gsm 03.40 time zone is
252 "expressed in quarters of an hour" */
253 tm.tm_gmtoff = unbcdify(*scts++) * 15*60;
254
255 return mktime(&tm);
256}
257
258/* Return the default validity period in minutes */
259static unsigned long gsm340_vp_default(void)
260{
261 unsigned long minutes;
262 /* Default validity: two days */
263 minutes = 24 * 60 * 2;
264 return minutes;
265}
266
267/* Decode validity period format 'relative' */
268static unsigned long gsm340_vp_relative(u_int8_t *sms_vp)
269{
270 /* Chapter 9.2.3.12.1 */
271 u_int8_t vp;
272 unsigned long minutes;
273
274 vp = *(sms_vp);
275 if (vp <= 143)
276 minutes = vp + 1 * 5;
277 else if (vp <= 167)
278 minutes = 12*60 + (vp-143) * 30;
279 else if (vp <= 196)
280 minutes = vp-166 * 60 * 24;
281 else
282 minutes = vp-192 * 60 * 24 * 7;
283 return minutes;
284}
285
286/* Decode validity period format 'absolute' */
287static unsigned long gsm340_vp_absolute(u_int8_t *sms_vp)
288{
289 /* Chapter 9.2.3.12.2 */
290 time_t expires, now;
291 unsigned long minutes;
292
293 expires = gsm340_scts(sms_vp);
294 now = mktime(gmtime(NULL));
295 if (expires <= now)
296 minutes = 0;
297 else
298 minutes = (expires-now)/60;
299 return minutes;
300}
301
302/* Decode validity period format 'relative in integer representation' */
303static unsigned long gsm340_vp_relative_integer(u_int8_t *sms_vp)
Harald Welte59b04682009-06-10 05:40:52 +0800304{
305 u_int8_t vp;
306 unsigned long minutes;
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100307 vp = *(sms_vp);
308 if (vp == 0) {
Harald Welteced9a912009-12-24 15:08:18 +0100309 LOGP(DSMS, LOGL_ERROR,
310 "reserved relative_integer validity period\n");
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100311 return gsm340_vp_default();
312 }
313 minutes = vp/60;
314 return minutes;
315}
316
317/* Decode validity period format 'relative in semi-octet representation' */
318static unsigned long gsm340_vp_relative_semioctet(u_int8_t *sms_vp)
319{
320 unsigned long minutes;
321 minutes = unbcdify(*sms_vp++)*60; /* hours */
322 minutes += unbcdify(*sms_vp++); /* minutes */
323 minutes += unbcdify(*sms_vp++)/60; /* seconds */
324 return minutes;
325}
326
327/* decode validity period. return minutes */
328static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp)
329{
330 u_int8_t fi; /* functionality indicator */
Harald Welte59b04682009-06-10 05:40:52 +0800331
Harald Welte68b7df22009-08-08 16:03:15 +0200332 switch (sms_vpf) {
Harald Welte59b04682009-06-10 05:40:52 +0800333 case GSM340_TP_VPF_RELATIVE:
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100334 return gsm340_vp_relative(sms_vp);
Harald Welte59b04682009-06-10 05:40:52 +0800335 case GSM340_TP_VPF_ABSOLUTE:
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100336 return gsm340_vp_absolute(sms_vp);
Harald Welte59b04682009-06-10 05:40:52 +0800337 case GSM340_TP_VPF_ENHANCED:
338 /* Chapter 9.2.3.12.3 */
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100339 fi = *sms_vp++;
340 /* ignore additional fi */
341 if (fi & (1<<7)) sms_vp++;
342 /* read validity period format */
343 switch (fi & 0b111) {
344 case 0b000:
345 return gsm340_vp_default(); /* no vpf specified */
346 case 0b001:
347 return gsm340_vp_relative(sms_vp);
348 case 0b010:
349 return gsm340_vp_relative_integer(sms_vp);
350 case 0b011:
351 return gsm340_vp_relative_semioctet(sms_vp);
352 default:
353 /* The GSM spec says that the SC should reject any
354 unsupported and/or undefined values. FIXME */
Harald Welteced9a912009-12-24 15:08:18 +0100355 LOGP(DSMS, LOGL_ERROR,
356 "Reserved enhanced validity period format\n");
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100357 return gsm340_vp_default();
358 }
Daniel Willmann426bb162009-08-13 03:40:49 +0200359 case GSM340_TP_VPF_NONE:
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100360 default:
361 return gsm340_vp_default();
Harald Welte59b04682009-06-10 05:40:52 +0800362 }
Harald Welte59b04682009-06-10 05:40:52 +0800363}
364
365/* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */
366enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
367{
368 u_int8_t cgbits = dcs >> 4;
369 enum sms_alphabet alpha = DCS_NONE;
370
371 if ((cgbits & 0xc) == 0) {
Harald Weltefb3a2322010-06-09 15:29:13 +0200372 if (cgbits & 2) {
Harald Welteced9a912009-12-24 15:08:18 +0100373 LOGP(DSMS, LOGL_NOTICE,
374 "Compressed SMS not supported yet\n");
Harald Weltefb3a2322010-06-09 15:29:13 +0200375 return 0xffffffff;
376 }
Harald Welte59b04682009-06-10 05:40:52 +0800377
Daniel Willmannf2861022009-08-15 03:01:17 +0200378 switch ((dcs >> 2)&0x03) {
Harald Welte59b04682009-06-10 05:40:52 +0800379 case 0:
380 alpha = DCS_7BIT_DEFAULT;
381 break;
382 case 1:
383 alpha = DCS_8BIT_DATA;
384 break;
385 case 2:
386 alpha = DCS_UCS2;
387 break;
388 }
389 } else if (cgbits == 0xc || cgbits == 0xd)
390 alpha = DCS_7BIT_DEFAULT;
391 else if (cgbits == 0xe)
392 alpha = DCS_UCS2;
393 else if (cgbits == 0xf) {
394 if (dcs & 4)
395 alpha = DCS_8BIT_DATA;
396 else
397 alpha = DCS_7BIT_DEFAULT;
398 }
399
400 return alpha;
401}
402
Harald Welte68b7df22009-08-08 16:03:15 +0200403static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms)
Harald Welte59b04682009-06-10 05:40:52 +0800404{
405 if (db_sms_store(gsms) != 0) {
Harald Welteced9a912009-12-24 15:08:18 +0100406 LOGP(DSMS, LOGL_ERROR, "Failed to store SMS in Database\n");
Harald Welte156c5e62009-07-05 14:02:46 +0200407 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte59b04682009-06-10 05:40:52 +0800408 }
Harald Welte68b7df22009-08-08 16:03:15 +0200409 /* dispatch a signal to tell higher level about it */
410 dispatch_signal(SS_SMS, S_SMS_SUBMITTED, gsms);
Harald Welte (local)ced09ed2009-08-17 09:39:55 +0200411 /* try delivering the SMS right now */
412 //gsm411_send_sms_subscr(gsms->receiver, gsms);
413
Harald Welte59b04682009-06-10 05:40:52 +0800414 return 0;
415}
416
Harald Welte68b7df22009-08-08 16:03:15 +0200417/* generate a TPDU address field compliant with 03.40 sec. 9.1.2.5 */
418static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len,
419 struct gsm_subscriber *subscr)
Harald Welteb78996d2009-07-27 20:11:35 +0200420{
Harald Welte68b7df22009-08-08 16:03:15 +0200421 int len_in_bytes;
Harald Welteb78996d2009-07-27 20:11:35 +0200422
Harald Welte68b7df22009-08-08 16:03:15 +0200423 oa[1] = 0xb9; /* networks-specific number, private numbering plan */
424
Harald Weltefdc93d92010-03-07 23:40:35 +0100425 len_in_bytes = gsm48_encode_bcd_number(oa, oa_len, 1, subscr->extension);
Harald Welte68b7df22009-08-08 16:03:15 +0200426
427 /* GSM 03.40 tells us the length is in 'useful semi-octets' */
428 oa[0] = strlen(subscr->extension) & 0xff;
429
430 return len_in_bytes;
Harald Welteb78996d2009-07-27 20:11:35 +0200431}
432
Harald Welte68b7df22009-08-08 16:03:15 +0200433/* generate a msgb containing a TPDU derived from struct gsm_sms,
434 * returns total size of TPDU */
435static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
Harald Welteb78996d2009-07-27 20:11:35 +0200436{
Harald Welteb78996d2009-07-27 20:11:35 +0200437 u_int8_t *smsp;
438 u_int8_t oa[12]; /* max len per 03.40 */
439 u_int8_t oa_len = 0;
Daniel Willmanna31ed622009-08-13 03:39:07 +0200440 u_int8_t octet_len;
Harald Welte68b7df22009-08-08 16:03:15 +0200441 unsigned int old_msg_len = msg->len;
Harald Welteb78996d2009-07-27 20:11:35 +0200442
443 /* generate first octet with masked bits */
444 smsp = msgb_put(msg, 1);
Harald Welte68b7df22009-08-08 16:03:15 +0200445 /* TP-MTI (message type indicator) */
Harald Welteb78996d2009-07-27 20:11:35 +0200446 *smsp = GSM340_SMS_DELIVER_SC2MS;
Harald Welte68b7df22009-08-08 16:03:15 +0200447 /* TP-MMS (more messages to send) */
448 if (0 /* FIXME */)
Harald Welteb78996d2009-07-27 20:11:35 +0200449 *smsp |= 0x04;
Harald Welte68b7df22009-08-08 16:03:15 +0200450 /* TP-SRI(deliver)/SRR(submit) */
Harald Welteb78996d2009-07-27 20:11:35 +0200451 if (sms->status_rep_req)
452 *smsp |= 0x20;
Harald Welte68b7df22009-08-08 16:03:15 +0200453 /* TP-UDHI (indicating TP-UD contains a header) */
454 if (sms->ud_hdr_ind)
Harald Welteb78996d2009-07-27 20:11:35 +0200455 *smsp |= 0x40;
Harald Welte68b7df22009-08-08 16:03:15 +0200456#if 0
457 /* TP-RP (indicating that a reply path exists) */
Harald Welteb78996d2009-07-27 20:11:35 +0200458 if (sms->
459 *smsp |= 0x80;
460#endif
461
462 /* generate originator address */
Harald Welte68b7df22009-08-08 16:03:15 +0200463 oa_len = gsm340_gen_oa(oa, sizeof(oa), sms->sender);
Harald Welteb78996d2009-07-27 20:11:35 +0200464 smsp = msgb_put(msg, oa_len);
Harald Welteb78996d2009-07-27 20:11:35 +0200465 memcpy(smsp, oa, oa_len);
466
467 /* generate TP-PID */
468 smsp = msgb_put(msg, 1);
469 *smsp = sms->protocol_id;
470
471 /* generate TP-DCS */
472 smsp = msgb_put(msg, 1);
473 *smsp = sms->data_coding_scheme;
474
475 /* generate TP-SCTS */
476 smsp = msgb_put(msg, 7);
477 gsm340_gen_scts(smsp, time(NULL));
Harald Welte68b7df22009-08-08 16:03:15 +0200478
Harald Welteb78996d2009-07-27 20:11:35 +0200479 /* generate TP-UDL */
480 smsp = msgb_put(msg, 1);
Harald Welte68b7df22009-08-08 16:03:15 +0200481 *smsp = sms->user_data_len;
Harald Welteb78996d2009-07-27 20:11:35 +0200482
483 /* generate TP-UD */
Daniel Willmann8d786602009-08-15 03:01:46 +0200484 switch (gsm338_get_sms_alphabet(sms->data_coding_scheme)) {
485 case DCS_7BIT_DEFAULT:
Daniel Willmanna31ed622009-08-13 03:39:07 +0200486 octet_len = sms->user_data_len*7/8;
487 if (sms->user_data_len*7%8 != 0)
488 octet_len++;
Daniel Willmann8f31ed92009-08-12 21:17:06 +0200489 /* Warning, user_data_len indicates the amount of septets
490 * (characters), we need amount of octets occupied */
Daniel Willmanna31ed622009-08-13 03:39:07 +0200491 smsp = msgb_put(msg, octet_len);
492 memcpy(smsp, sms->user_data, octet_len);
Daniel Willmann8d786602009-08-15 03:01:46 +0200493 break;
494 case DCS_UCS2:
495 case DCS_8BIT_DATA:
496 smsp = msgb_put(msg, sms->user_data_len);
497 memcpy(smsp, sms->user_data, sms->user_data_len);
498 break;
499 default:
Harald Welteced9a912009-12-24 15:08:18 +0100500 LOGP(DSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: 0x%02X\n",
501 sms->data_coding_scheme);
Daniel Willmann8d786602009-08-15 03:01:46 +0200502 break;
Daniel Willmann8f31ed92009-08-12 21:17:06 +0200503 }
Harald Welteb78996d2009-07-27 20:11:35 +0200504
Harald Welte68b7df22009-08-08 16:03:15 +0200505 return msg->len - old_msg_len;
Harald Welteb78996d2009-07-27 20:11:35 +0200506}
507
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200508/* process an incoming TPDU (called from RP-DATA)
509 * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100510static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800511{
512 u_int8_t *smsp = msgb_sms(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800513 struct gsm_sms *gsms;
Harald Welte68b7df22009-08-08 16:03:15 +0200514 u_int8_t sms_mti, sms_mms, sms_vpf, sms_alphabet, sms_rp;
515 u_int8_t *sms_vp;
Harald Welte59b04682009-06-10 05:40:52 +0800516 u_int8_t da_len_bytes;
517 u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
518 int rc = 0;
519
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100520 counter_inc(conn->bts->network->stats.sms.submitted);
Harald Welte3edc5a92009-12-22 00:41:05 +0100521
Harald Welte68b7df22009-08-08 16:03:15 +0200522 gsms = sms_alloc();
523 if (!gsms)
Harald Welte156c5e62009-07-05 14:02:46 +0200524 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte59b04682009-06-10 05:40:52 +0800525
526 /* invert those fields where 0 means active/present */
Harald Welte68b7df22009-08-08 16:03:15 +0200527 sms_mti = *smsp & 0x03;
528 sms_mms = !!(*smsp & 0x04);
529 sms_vpf = (*smsp & 0x18) >> 3;
530 gsms->status_rep_req = (*smsp & 0x20);
531 gsms->ud_hdr_ind = (*smsp & 0x40);
532 sms_rp = (*smsp & 0x80);
Harald Welte59b04682009-06-10 05:40:52 +0800533
534 smsp++;
Harald Welte68b7df22009-08-08 16:03:15 +0200535 gsms->msg_ref = *smsp++;
Harald Welte59b04682009-06-10 05:40:52 +0800536
537 /* length in bytes of the destination address */
538 da_len_bytes = 2 + *smsp/2 + *smsp%2;
539 if (da_len_bytes > 12) {
Harald Welteced9a912009-12-24 15:08:18 +0100540 LOGP(DSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n");
Harald Welte156c5e62009-07-05 14:02:46 +0200541 rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
Harald Welte59b04682009-06-10 05:40:52 +0800542 goto out;
543 }
Harald Welte3794e152009-06-12 02:42:11 +0800544 memset(address_lv, 0, sizeof(address_lv));
Harald Welte59b04682009-06-10 05:40:52 +0800545 memcpy(address_lv, smsp, da_len_bytes);
546 /* mangle first byte to reflect length in bytes, not digits */
Harald Welte3794e152009-06-12 02:42:11 +0800547 address_lv[0] = da_len_bytes - 1;
Harald Welte59b04682009-06-10 05:40:52 +0800548 /* convert to real number */
Harald Weltefdc93d92010-03-07 23:40:35 +0100549 gsm48_decode_bcd_number(gsms->dest_addr, sizeof(gsms->dest_addr), address_lv, 1);
Harald Welte59b04682009-06-10 05:40:52 +0800550 smsp += da_len_bytes;
551
Harald Welte68b7df22009-08-08 16:03:15 +0200552 gsms->protocol_id = *smsp++;
553 gsms->data_coding_scheme = *smsp++;
Harald Welte59b04682009-06-10 05:40:52 +0800554
Harald Welte68b7df22009-08-08 16:03:15 +0200555 sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
Harald Weltefb3a2322010-06-09 15:29:13 +0200556 if (sms_alphabet == 0xffffffff)
557 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte59b04682009-06-10 05:40:52 +0800558
Harald Welte68b7df22009-08-08 16:03:15 +0200559 switch (sms_vpf) {
Harald Welte59b04682009-06-10 05:40:52 +0800560 case GSM340_TP_VPF_RELATIVE:
Harald Welte68b7df22009-08-08 16:03:15 +0200561 sms_vp = smsp++;
Harald Welte59b04682009-06-10 05:40:52 +0800562 break;
563 case GSM340_TP_VPF_ABSOLUTE:
564 case GSM340_TP_VPF_ENHANCED:
Harald Welte68b7df22009-08-08 16:03:15 +0200565 sms_vp = smsp;
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100566 /* the additional functionality indicator... */
Steffen Neubauerdd488d12009-12-05 12:44:41 +0100567 if (sms_vpf == GSM340_TP_VPF_ENHANCED && *smsp & (1<<7))
568 smsp++;
Harald Welte59b04682009-06-10 05:40:52 +0800569 smsp += 7;
570 break;
Daniel Willmann426bb162009-08-13 03:40:49 +0200571 case GSM340_TP_VPF_NONE:
572 sms_vp = 0;
573 break;
Harald Welte59b04682009-06-10 05:40:52 +0800574 default:
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200575 LOGP(DSMS, LOGL_NOTICE,
Harald Welteced9a912009-12-24 15:08:18 +0100576 "SMS Validity period not implemented: 0x%02x\n", sms_vpf);
Harald Welte68b7df22009-08-08 16:03:15 +0200577 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte59b04682009-06-10 05:40:52 +0800578 }
Harald Welte68b7df22009-08-08 16:03:15 +0200579 gsms->user_data_len = *smsp++;
580 if (gsms->user_data_len) {
581 memcpy(gsms->user_data, smsp, gsms->user_data_len);
Harald Welte59b04682009-06-10 05:40:52 +0800582
Harald Welte68b7df22009-08-08 16:03:15 +0200583 switch (sms_alphabet) {
Harald Welte59b04682009-06-10 05:40:52 +0800584 case DCS_7BIT_DEFAULT:
Harald Welte68b7df22009-08-08 16:03:15 +0200585 gsm_7bit_decode(gsms->text, smsp, gsms->user_data_len);
Harald Welte59b04682009-06-10 05:40:52 +0800586 break;
587 case DCS_8BIT_DATA:
588 case DCS_UCS2:
589 case DCS_NONE:
Harald Welte59b04682009-06-10 05:40:52 +0800590 break;
591 }
592 }
593
Holger Hans Peter Freyther065b8112010-03-23 06:41:45 +0100594 gsms->sender = subscr_get(msg->lchan->conn.subscr);
Harald Welteced9a912009-12-24 15:08:18 +0100595
596 LOGP(DSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, "
597 "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, "
598 "UserDataLength: 0x%02x, UserData: \"%s\"\n",
599 subscr_name(gsms->sender), sms_mti, sms_vpf, gsms->msg_ref,
600 gsms->protocol_id, gsms->data_coding_scheme, gsms->dest_addr,
601 gsms->user_data_len,
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200602 sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
Harald Welte68b7df22009-08-08 16:03:15 +0200603 hexdump(gsms->user_data, gsms->user_data_len));
Harald Welte59b04682009-06-10 05:40:52 +0800604
Harald Welte68b7df22009-08-08 16:03:15 +0200605 gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
Harald Welte156c5e62009-07-05 14:02:46 +0200606
Harald Welte68b7df22009-08-08 16:03:15 +0200607 dispatch_signal(SS_SMS, 0, gsms);
Harald Welte156c5e62009-07-05 14:02:46 +0200608
Harald Welte59b04682009-06-10 05:40:52 +0800609 /* determine gsms->receiver based on dialled number */
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100610 gsms->receiver = subscr_get_by_extension(conn->bts->network, gsms->dest_addr);
Harald Welte59b04682009-06-10 05:40:52 +0800611 if (!gsms->receiver) {
612 rc = 1; /* cause 1: unknown subscriber */
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100613 counter_inc(conn->bts->network->stats.sms.no_receiver);
Harald Welte59b04682009-06-10 05:40:52 +0800614 goto out;
615 }
616
Harald Welte68b7df22009-08-08 16:03:15 +0200617 switch (sms_mti) {
Harald Welte59b04682009-06-10 05:40:52 +0800618 case GSM340_SMS_SUBMIT_MS2SC:
619 /* MS is submitting a SMS */
Harald Welte68b7df22009-08-08 16:03:15 +0200620 rc = gsm340_rx_sms_submit(msg, gsms);
Harald Welte59b04682009-06-10 05:40:52 +0800621 break;
622 case GSM340_SMS_COMMAND_MS2SC:
623 case GSM340_SMS_DELIVER_REP_MS2SC:
Harald Welteced9a912009-12-24 15:08:18 +0100624 LOGP(DSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti);
Harald Welte156c5e62009-07-05 14:02:46 +0200625 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte59b04682009-06-10 05:40:52 +0800626 break;
627 default:
Harald Welteced9a912009-12-24 15:08:18 +0100628 LOGP(DSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti);
Harald Welte156c5e62009-07-05 14:02:46 +0200629 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte59b04682009-06-10 05:40:52 +0800630 break;
631 }
632
Harald Welte156c5e62009-07-05 14:02:46 +0200633 if (!rc && !gsms->receiver)
634 rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
635
Harald Welte59b04682009-06-10 05:40:52 +0800636out:
Harald Welte68b7df22009-08-08 16:03:15 +0200637 sms_free(gsms);
Harald Welte59b04682009-06-10 05:40:52 +0800638
639 return rc;
640}
641
Harald Welteb78996d2009-07-27 20:11:35 +0200642static int gsm411_send_rp_ack(struct gsm_trans *trans, u_int8_t msg_ref)
Harald Welte59b04682009-06-10 05:40:52 +0800643{
644 struct msgb *msg = gsm411_msgb_alloc();
Harald Welte59b04682009-06-10 05:40:52 +0800645
Harald Welte59b04682009-06-10 05:40:52 +0800646 DEBUGP(DSMS, "TX: SMS RP ACK\n");
647
Harald Welteb78996d2009-07-27 20:11:35 +0200648 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ACK_MT, msg_ref);
Harald Welte59b04682009-06-10 05:40:52 +0800649}
650
Harald Welteb78996d2009-07-27 20:11:35 +0200651static int gsm411_send_rp_error(struct gsm_trans *trans,
652 u_int8_t msg_ref, u_int8_t cause)
Harald Welte59b04682009-06-10 05:40:52 +0800653{
654 struct msgb *msg = gsm411_msgb_alloc();
Harald Welte59b04682009-06-10 05:40:52 +0800655
Harald Welte59b04682009-06-10 05:40:52 +0800656 msgb_tv_put(msg, 1, cause);
657
Harald Welteced9a912009-12-24 15:08:18 +0100658 LOGP(DSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200659 get_value_string(rp_cause_strs, cause));
Harald Welte59b04682009-06-10 05:40:52 +0800660
Harald Welteb78996d2009-07-27 20:11:35 +0200661 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
Harald Welte59b04682009-06-10 05:40:52 +0800662}
663
664/* Receive a 04.11 TPDU inside RP-DATA / user data */
Harald Welteb78996d2009-07-27 20:11:35 +0200665static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
666 struct gsm411_rp_hdr *rph,
Harald Welte59b04682009-06-10 05:40:52 +0800667 u_int8_t src_len, u_int8_t *src,
668 u_int8_t dst_len, u_int8_t *dst,
669 u_int8_t tpdu_len, u_int8_t *tpdu)
670{
Harald Welte59b04682009-06-10 05:40:52 +0800671 int rc = 0;
672
673 if (src_len && src)
Harald Welteced9a912009-12-24 15:08:18 +0100674 LOGP(DSMS, LOGL_ERROR, "RP-DATA (MO) with SRC ?!?\n");
Harald Welte59b04682009-06-10 05:40:52 +0800675
676 if (!dst_len || !dst || !tpdu_len || !tpdu) {
Harald Welteced9a912009-12-24 15:08:18 +0100677 LOGP(DSMS, LOGL_ERROR,
678 "RP-DATA (MO) without DST or TPDU ?!?\n");
Harald Welteb78996d2009-07-27 20:11:35 +0200679 gsm411_send_rp_error(trans, rph->msg_ref,
Harald Welte156c5e62009-07-05 14:02:46 +0200680 GSM411_RP_CAUSE_INV_MAND_INF);
Harald Welte59b04682009-06-10 05:40:52 +0800681 return -EIO;
682 }
Harald Welte2c5706d2010-04-30 14:27:05 +0200683 msg->l4h = tpdu;
Harald Welte59b04682009-06-10 05:40:52 +0800684
685 DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
Harald Welte59b04682009-06-10 05:40:52 +0800686
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100687 rc = gsm340_rx_tpdu(trans->conn, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800688 if (rc == 0)
Harald Welteb78996d2009-07-27 20:11:35 +0200689 return gsm411_send_rp_ack(trans, rph->msg_ref);
Harald Welte59b04682009-06-10 05:40:52 +0800690 else if (rc > 0)
Harald Welteb78996d2009-07-27 20:11:35 +0200691 return gsm411_send_rp_error(trans, rph->msg_ref, rc);
Harald Welte59b04682009-06-10 05:40:52 +0800692 else
693 return rc;
694}
695
696/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
Harald Welteb78996d2009-07-27 20:11:35 +0200697static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
698 struct gsm411_rp_hdr *rph)
Harald Welte59b04682009-06-10 05:40:52 +0800699{
700 u_int8_t src_len, dst_len, rpud_len;
701 u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
702
703 /* in the MO case, this should always be zero length */
704 src_len = rph->data[0];
705 if (src_len)
706 src = &rph->data[1];
707
708 dst_len = rph->data[1+src_len];
709 if (dst_len)
710 dst = &rph->data[1+src_len+1];
711
712 rpud_len = rph->data[1+src_len+1+dst_len];
713 if (rpud_len)
714 rp_ud = &rph->data[1+src_len+1+dst_len+1];
715
Harald Welte156c5e62009-07-05 14:02:46 +0200716 DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
717 src_len, dst_len, rpud_len);
Harald Welteb78996d2009-07-27 20:11:35 +0200718 return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst,
Harald Welte59b04682009-06-10 05:40:52 +0800719 rpud_len, rp_ud);
720}
721
Harald Welte09421d32009-08-09 14:59:02 +0200722/* Receive a 04.11 RP-ACK message (response to RP-DATA from us) */
Harald Welteb78996d2009-07-27 20:11:35 +0200723static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
724 struct gsm411_rp_hdr *rph)
Harald Welte156c5e62009-07-05 14:02:46 +0200725{
Harald Welte68b7df22009-08-08 16:03:15 +0200726 struct gsm_sms *sms = trans->sms.sms;
727
Harald Welte156c5e62009-07-05 14:02:46 +0200728 /* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
729 * successfully received a SMS. We can now safely mark it as
730 * transmitted */
731
Harald Welte09421d32009-08-09 14:59:02 +0200732 if (!trans->sms.is_mt) {
Harald Welteced9a912009-12-24 15:08:18 +0100733 LOGP(DSMS, LOGL_ERROR, "RX RP-ACK on a MO transfer ?\n");
Harald Welte09421d32009-08-09 14:59:02 +0200734 return gsm411_send_rp_error(trans, rph->msg_ref,
735 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
736 }
Harald Weltedd62b162009-07-09 23:52:59 +0200737
Harald Welte68b7df22009-08-08 16:03:15 +0200738 if (!sms) {
Harald Welteced9a912009-12-24 15:08:18 +0100739 LOGP(DSMS, LOGL_ERROR, "RX RP-ACK but no sms in transaction?!?\n");
Harald Welte09421d32009-08-09 14:59:02 +0200740 return gsm411_send_rp_error(trans, rph->msg_ref,
741 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte68b7df22009-08-08 16:03:15 +0200742 }
743
744 /* mark this SMS as sent in database */
745 db_sms_mark_sent(sms);
746
747 dispatch_signal(SS_SMS, S_SMS_DELIVERED, sms);
748
749 sms_free(sms);
750 trans->sms.sms = NULL;
751
Harald Weltefc01b242009-08-09 19:07:41 +0200752 /* check for more messages for this subscriber */
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +0100753 assert(msg->lchan->conn.subscr == trans->subscr);
754
755 sms = db_sms_get_unsent_for_subscr(trans->subscr);
Harald Weltefc01b242009-08-09 19:07:41 +0200756 if (sms)
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +0100757 gsm411_send_sms_lchan(trans->conn, sms);
Sylvain Munautd17cdeb2009-12-24 13:33:51 +0100758
759 /* free the transaction here */
760 trans_free(trans);
Harald Welte68b7df22009-08-08 16:03:15 +0200761 return 0;
Harald Welte156c5e62009-07-05 14:02:46 +0200762}
763
Harald Welteb78996d2009-07-27 20:11:35 +0200764static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
765 struct gsm411_rp_hdr *rph)
Harald Welte156c5e62009-07-05 14:02:46 +0200766{
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100767 struct gsm_network *net = trans->conn->bts->network;
Harald Welte68b7df22009-08-08 16:03:15 +0200768 struct gsm_sms *sms = trans->sms.sms;
Harald Welteb78996d2009-07-27 20:11:35 +0200769 u_int8_t cause_len = rph->data[0];
770 u_int8_t cause = rph->data[1];
771
Harald Welte156c5e62009-07-05 14:02:46 +0200772 /* Error in response to MT RP_DATA, i.e. the MS did not
773 * successfully receive the SMS. We need to investigate
774 * the cause and take action depending on it */
775
Harald Welteced9a912009-12-24 15:08:18 +0100776 LOGP(DSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
Holger Hans Peter Freytherde896e52010-03-23 07:56:22 +0100777 subscr_name(trans->conn->subscr), cause_len, cause,
Harald Welteced9a912009-12-24 15:08:18 +0100778 get_value_string(rp_cause_strs, cause));
Harald Welteb78996d2009-07-27 20:11:35 +0200779
Harald Welte09421d32009-08-09 14:59:02 +0200780 if (!trans->sms.is_mt) {
Harald Welteced9a912009-12-24 15:08:18 +0100781 LOGP(DSMS, LOGL_ERROR, "RX RP-ERR on a MO transfer ?\n");
Harald Welte (local)ced09ed2009-08-17 09:39:55 +0200782#if 0
Harald Welte09421d32009-08-09 14:59:02 +0200783 return gsm411_send_rp_error(trans, rph->msg_ref,
784 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
Harald Welte (local)ced09ed2009-08-17 09:39:55 +0200785#endif
Harald Welte09421d32009-08-09 14:59:02 +0200786 }
Harald Weltedd62b162009-07-09 23:52:59 +0200787
Harald Welte68b7df22009-08-08 16:03:15 +0200788 if (!sms) {
Harald Welteced9a912009-12-24 15:08:18 +0100789 LOGP(DSMS, LOGL_ERROR,
790 "RX RP-ERR, but no sms in transaction?!?\n");
Harald Welte (local)ced09ed2009-08-17 09:39:55 +0200791 return -EINVAL;
792#if 0
Harald Welte09421d32009-08-09 14:59:02 +0200793 return gsm411_send_rp_error(trans, rph->msg_ref,
794 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte (local)ced09ed2009-08-17 09:39:55 +0200795#endif
Harald Welte09421d32009-08-09 14:59:02 +0200796 }
797
798 if (cause == GSM411_RP_CAUSE_MT_MEM_EXCEEDED) {
799 /* MS has not enough memory to store the message. We need
800 * to store this in our database and wati for a SMMA message */
801 /* FIXME */
802 dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr);
Harald Weltebdbb7442009-12-22 19:07:32 +0100803 counter_inc(net->stats.sms.rp_err_mem);
Harald Welte3edc5a92009-12-22 00:41:05 +0100804 } else
Harald Weltebdbb7442009-12-22 19:07:32 +0100805 counter_inc(net->stats.sms.rp_err_other);
Harald Welte68b7df22009-08-08 16:03:15 +0200806
807 sms_free(sms);
808 trans->sms.sms = NULL;
809
Harald Welte (local)9d0bd792009-08-14 14:52:17 +0200810 //trans_free(trans);
Harald Welte68b7df22009-08-08 16:03:15 +0200811
Harald Welteb78996d2009-07-27 20:11:35 +0200812 return 0;
Harald Welte156c5e62009-07-05 14:02:46 +0200813}
814
Harald Welteb78996d2009-07-27 20:11:35 +0200815static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans,
816 struct gsm411_rp_hdr *rph)
Harald Welte156c5e62009-07-05 14:02:46 +0200817{
Harald Weltefc01b242009-08-09 19:07:41 +0200818 struct gsm_sms *sms;
Harald Welteb78996d2009-07-27 20:11:35 +0200819 int rc;
820
Harald Weltefc01b242009-08-09 19:07:41 +0200821 rc = gsm411_send_rp_ack(trans, rph->msg_ref);
822 trans->sms.rp_state = GSM411_RPS_IDLE;
823
Harald Welte156c5e62009-07-05 14:02:46 +0200824 /* MS tells us that it has memory for more SMS, we need
825 * to check if we have any pending messages for it and then
826 * transfer those */
Harald Welte68b7df22009-08-08 16:03:15 +0200827 dispatch_signal(SS_SMS, S_SMS_SMMA, trans->subscr);
Harald Welteb78996d2009-07-27 20:11:35 +0200828
Harald Weltefc01b242009-08-09 19:07:41 +0200829 /* check for more messages for this subscriber */
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +0100830 assert(msg->lchan->conn.subscr == trans->subscr);
831 sms = db_sms_get_unsent_for_subscr(trans->subscr);
Harald Weltefc01b242009-08-09 19:07:41 +0200832 if (sms)
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +0100833 gsm411_send_sms_lchan(trans->conn, sms);
Harald Welteb78996d2009-07-27 20:11:35 +0200834
835 return rc;
Harald Welte156c5e62009-07-05 14:02:46 +0200836}
837
Harald Welteb78996d2009-07-27 20:11:35 +0200838static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
839 struct gsm_trans *trans)
Harald Welte59b04682009-06-10 05:40:52 +0800840{
841 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
842 u_int8_t msg_type = rp_data->msg_type & 0x07;
843 int rc = 0;
844
845 switch (msg_type) {
846 case GSM411_MT_RP_DATA_MO:
Harald Welteb78996d2009-07-27 20:11:35 +0200847 DEBUGP(DSMS, "RX SMS RP-DATA (MO)\n");
848 /* start TR2N and enter 'wait to send RP-ACK state' */
849 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
850 rc = gsm411_rx_rp_data(msg, trans, rp_data);
Harald Welte59b04682009-06-10 05:40:52 +0800851 break;
852 case GSM411_MT_RP_ACK_MO:
Harald Welteb78996d2009-07-27 20:11:35 +0200853 DEBUGP(DSMS,"RX SMS RP-ACK (MO)\n");
854 rc = gsm411_rx_rp_ack(msg, trans, rp_data);
Harald Welte156c5e62009-07-05 14:02:46 +0200855 break;
Harald Welte59b04682009-06-10 05:40:52 +0800856 case GSM411_MT_RP_SMMA_MO:
Harald Welteb78996d2009-07-27 20:11:35 +0200857 DEBUGP(DSMS, "RX SMS RP-SMMA\n");
858 /* start TR2N and enter 'wait to send RP-ACK state' */
859 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
860 rc = gsm411_rx_rp_smma(msg, trans, rp_data);
861 break;
862 case GSM411_MT_RP_ERROR_MO:
863 rc = gsm411_rx_rp_error(msg, trans, rp_data);
Harald Welte59b04682009-06-10 05:40:52 +0800864 break;
865 default:
Harald Welteced9a912009-12-24 15:08:18 +0100866 LOGP(DSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type);
Harald Welteb78996d2009-07-27 20:11:35 +0200867 rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
868 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
Harald Welte59b04682009-06-10 05:40:52 +0800869 break;
870 }
871
872 return rc;
873}
874
Harald Welteb78996d2009-07-27 20:11:35 +0200875/* send CP-ACK to given transaction */
876static int gsm411_tx_cp_ack(struct gsm_trans *trans)
877{
878 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltefc01b242009-08-09 19:07:41 +0200879 int rc;
Harald Welteb78996d2009-07-27 20:11:35 +0200880
Harald Weltefc01b242009-08-09 19:07:41 +0200881 rc = gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ACK);
882
883 if (trans->sms.is_mt) {
884 /* If this is a MT SMS DELIVER, we can clear transaction here */
885 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Welte (local)9d0bd792009-08-14 14:52:17 +0200886 //trans_free(trans);
Harald Weltefc01b242009-08-09 19:07:41 +0200887 }
Holger Hans Peter Freyther182c7452009-08-10 07:59:27 +0200888
889 return rc;
Harald Welteb78996d2009-07-27 20:11:35 +0200890}
891
892static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
893{
894 struct msgb *msg = gsm411_msgb_alloc();
895 u_int8_t *causep;
896
Harald Welteced9a912009-12-24 15:08:18 +0100897 LOGP(DSMS, LOGL_NOTICE, "TX CP-ERROR, cause %d (%s)\n", cause,
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200898 get_value_string(cp_cause_strs, cause));
899
Harald Welte68b7df22009-08-08 16:03:15 +0200900 causep = msgb_put(msg, 1);
Harald Welteb78996d2009-07-27 20:11:35 +0200901 *causep = cause;
902
903 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ERROR);
904}
905
906/* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200907int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id)
Harald Welte59b04682009-06-10 05:40:52 +0800908{
909 struct gsm48_hdr *gh = msgb_l3(msg);
910 u_int8_t msg_type = gh->msg_type;
Harald Welteb78996d2009-07-27 20:11:35 +0200911 u_int8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
912 struct gsm_lchan *lchan = msg->lchan;
913 struct gsm_trans *trans;
Harald Welte59b04682009-06-10 05:40:52 +0800914 int rc = 0;
915
Holger Hans Peter Freyther065b8112010-03-23 06:41:45 +0100916 if (!lchan->conn.subscr)
Harald Welteb78996d2009-07-27 20:11:35 +0200917 return -EIO;
918 /* FIXME: send some error message */
919
Sylvain Munaute02fb9a2009-12-18 18:28:08 +0100920 DEBUGP(DSMS, "trans_id=%x ", transaction_id);
Holger Hans Peter Freyther065b8112010-03-23 06:41:45 +0100921 trans = trans_find_by_id(lchan->conn.subscr, GSM48_PDISC_SMS,
Harald Welteb78996d2009-07-27 20:11:35 +0200922 transaction_id);
923 if (!trans) {
Sylvain Munaut40c23322009-12-18 18:28:09 +0100924 DEBUGPC(DSMS, "(new) ");
Holger Hans Peter Freyther065b8112010-03-23 06:41:45 +0100925 trans = trans_alloc(lchan->conn.subscr, GSM48_PDISC_SMS,
Harald Welteb78996d2009-07-27 20:11:35 +0200926 transaction_id, new_callref++);
927 if (!trans) {
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200928 DEBUGPC(DSMS, "No memory for trans\n");
Harald Welteb78996d2009-07-27 20:11:35 +0200929 /* FIXME: send some error message */
930 return -ENOMEM;
931 }
932 trans->sms.cp_state = GSM411_CPS_IDLE;
933 trans->sms.rp_state = GSM411_RPS_IDLE;
934 trans->sms.is_mt = 0;
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200935 trans->sms.link_id = link_id;
Harald Welteb78996d2009-07-27 20:11:35 +0200936
Holger Hans Peter Freyther4009da42010-03-23 07:00:22 +0100937 trans->conn = &lchan->conn;
938 use_subscr_con(trans->conn);
Harald Welteb78996d2009-07-27 20:11:35 +0200939 }
940
Harald Welte59b04682009-06-10 05:40:52 +0800941 switch(msg_type) {
942 case GSM411_MT_CP_DATA:
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200943 DEBUGPC(DSMS, "RX SMS CP-DATA\n");
Sylvain Munauta5914da2009-12-24 16:47:08 +0100944
945 /* 5.4: For MO, if a CP-DATA is received for a new
946 * transaction, equals reception of an implicit
947 * last CP-ACK for previous transaction */
948 if (trans->sms.cp_state == GSM411_CPS_IDLE) {
949 int i;
950 struct gsm_trans *ptrans;
951
952 /* Scan through all remote initiated transactions */
953 for (i=8; i<15; i++) {
954 if (i == transaction_id)
955 continue;
956
Holger Hans Peter Freyther065b8112010-03-23 06:41:45 +0100957 ptrans = trans_find_by_id(lchan->conn.subscr,
Sylvain Munauta5914da2009-12-24 16:47:08 +0100958 GSM48_PDISC_SMS, i);
959 if (!ptrans)
960 continue;
961
962 DEBUGP(DSMS, "Implicit CP-ACK for trans_id=%x\n", i);
963
964 /* Finish it for good */
965 bsc_del_timer(&ptrans->sms.cp_timer);
966 ptrans->sms.cp_state = GSM411_CPS_IDLE;
967 trans_free(ptrans);
968 }
969 }
970
Harald Welte09421d32009-08-09 14:59:02 +0200971 /* 5.2.3.1.3: MO state exists when SMC has received
972 * CP-DATA, including sending of the assoc. CP-ACK */
973 /* 5.2.3.2.4: MT state exists when SMC has received
974 * CP-DATA, including sending of the assoc. CP-ACK */
975 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Welteb78996d2009-07-27 20:11:35 +0200976
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200977 /* SMC instance acknowledges the CP-DATA frame */
978 gsm411_tx_cp_ack(trans);
979
Harald Welteb78996d2009-07-27 20:11:35 +0200980 rc = gsm411_rx_cp_data(msg, gh, trans);
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200981#if 0
Harald Welteb78996d2009-07-27 20:11:35 +0200982 /* Send CP-ACK or CP-ERORR in response */
983 if (rc < 0) {
984 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_NET_FAIL);
985 } else
986 rc = gsm411_tx_cp_ack(trans);
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200987#endif
Harald Welte59b04682009-06-10 05:40:52 +0800988 break;
989 case GSM411_MT_CP_ACK:
Harald Welteb78996d2009-07-27 20:11:35 +0200990 /* previous CP-DATA in this transaction was confirmed */
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200991 DEBUGPC(DSMS, "RX SMS CP-ACK\n");
Harald Welte09421d32009-08-09 14:59:02 +0200992 /* 5.2.3.1.3: MO state exists when SMC has received CP-ACK */
993 /* 5.2.3.2.4: MT state exists when SMC has received CP-ACK */
994 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Welte5fa17a22009-08-10 00:24:32 +0200995 /* Stop TC1* after CP-ACK has been received */
996 bsc_del_timer(&trans->sms.cp_timer);
Harald Welte09421d32009-08-09 14:59:02 +0200997
Harald Welteb78996d2009-07-27 20:11:35 +0200998 if (!trans->sms.is_mt) {
Holger Hans Peter Freyther6532f0e2010-06-10 18:08:12 +0800999 /* FIXME: we have sent one CP-DATA, which was now
Harald Welteb78996d2009-07-27 20:11:35 +02001000 * acknowledged. Check if we want to transfer more,
1001 * i.e. multi-part message */
1002 trans->sms.cp_state = GSM411_CPS_IDLE;
1003 trans_free(trans);
1004 }
Harald Welte59b04682009-06-10 05:40:52 +08001005 break;
1006 case GSM411_MT_CP_ERROR:
Harald Welte (local)cb4715c2009-08-14 10:42:43 +02001007 DEBUGPC(DSMS, "RX SMS CP-ERROR, cause %d (%s)\n", gh->data[0],
1008 get_value_string(cp_cause_strs, gh->data[0]));
Harald Welte5fa17a22009-08-10 00:24:32 +02001009 bsc_del_timer(&trans->sms.cp_timer);
Harald Welteb78996d2009-07-27 20:11:35 +02001010 trans->sms.cp_state = GSM411_CPS_IDLE;
1011 trans_free(trans);
Harald Welte59b04682009-06-10 05:40:52 +08001012 break;
1013 default:
Harald Welte (local)cb4715c2009-08-14 10:42:43 +02001014 DEBUGPC(DSMS, "RX Unimplemented CP msg_type: 0x%02x\n", msg_type);
Harald Welteb78996d2009-07-27 20:11:35 +02001015 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
Harald Welte09421d32009-08-09 14:59:02 +02001016 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Welteb78996d2009-07-27 20:11:35 +02001017 trans_free(trans);
Harald Welte59b04682009-06-10 05:40:52 +08001018 break;
1019 }
1020
Harald Welte59b04682009-06-10 05:40:52 +08001021 return rc;
1022}
1023
Harald Welte59b04682009-06-10 05:40:52 +08001024#if 0
Harald Welte59b04682009-06-10 05:40:52 +08001025/* Test TPDU - ALL YOUR */
1026static u_int8_t tpdu_test[] = {
1027 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
1028 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
1029 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
1030 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
1031};
1032#endif
1033
Harald Weltefc01b242009-08-09 19:07:41 +02001034/* Take a SMS in gsm_sms structure and send it through an already
1035 * existing lchan. We also assume that the caller ensured this lchan already
1036 * has a SAPI3 RLL connection! */
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001037int gsm411_send_sms_lchan(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
Harald Welte59b04682009-06-10 05:40:52 +08001038{
1039 struct msgb *msg = gsm411_msgb_alloc();
Harald Welteb78996d2009-07-27 20:11:35 +02001040 struct gsm_trans *trans;
Harald Welte68b7df22009-08-08 16:03:15 +02001041 u_int8_t *data, *rp_ud_len;
Harald Welte7e2f57d2009-07-04 17:39:00 +02001042 u_int8_t msg_ref = 42;
Sylvain Munaute65af1b2009-12-24 13:27:36 +01001043 int transaction_id;
Harald Welte68b7df22009-08-08 16:03:15 +02001044 int rc;
Harald Welte59b04682009-06-10 05:40:52 +08001045
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001046 transaction_id = trans_assign_trans_id(conn->subscr, GSM48_PDISC_SMS, 0);
Harald Welte6e55abf2009-12-22 13:45:58 +01001047 if (transaction_id == -1) {
Harald Welteced9a912009-12-24 15:08:18 +01001048 LOGP(DSMS, LOGL_ERROR, "No available transaction ids\n");
Harald Welte6e55abf2009-12-22 13:45:58 +01001049 return -EBUSY;
1050 }
Harald Weltefc01b242009-08-09 19:07:41 +02001051
Harald Welte68b7df22009-08-08 16:03:15 +02001052 DEBUGP(DSMS, "send_sms_lchan()\n");
Harald Welteb78996d2009-07-27 20:11:35 +02001053
Harald Welte68b7df22009-08-08 16:03:15 +02001054 /* FIXME: allocate transaction with message reference */
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001055 trans = trans_alloc(conn->subscr, GSM48_PDISC_SMS,
Harald Welte68b7df22009-08-08 16:03:15 +02001056 transaction_id, new_callref++);
1057 if (!trans) {
Harald Welteced9a912009-12-24 15:08:18 +01001058 LOGP(DSMS, LOGL_ERROR, "No memory for trans\n");
Harald Welte68b7df22009-08-08 16:03:15 +02001059 /* FIXME: send some error message */
1060 return -ENOMEM;
1061 }
1062 trans->sms.cp_state = GSM411_CPS_IDLE;
1063 trans->sms.rp_state = GSM411_RPS_IDLE;
1064 trans->sms.is_mt = 1;
1065 trans->sms.sms = sms;
Harald Welte (local)64994ce2009-08-14 11:41:12 +02001066 trans->sms.link_id = UM_SAPI_SMS; /* FIXME: main or SACCH ? */
Harald Welte68b7df22009-08-08 16:03:15 +02001067
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001068 trans->conn = conn;
Holger Hans Peter Freyther4009da42010-03-23 07:00:22 +01001069 use_subscr_con(trans->conn);
Harald Welte68b7df22009-08-08 16:03:15 +02001070
1071 /* Hardcode SMSC Originating Address for now */
Harald Welte59b04682009-06-10 05:40:52 +08001072 data = (u_int8_t *)msgb_put(msg, 8);
Harald Welte7e2f57d2009-07-04 17:39:00 +02001073 data[0] = 0x07; /* originator length == 7 */
Harald Welte156c5e62009-07-05 14:02:46 +02001074 data[1] = 0x91; /* type of number: international, ISDN */
1075 data[2] = 0x44; /* 447785016005 */
Harald Welte59b04682009-06-10 05:40:52 +08001076 data[3] = 0x77;
1077 data[4] = 0x58;
1078 data[5] = 0x10;
1079 data[6] = 0x06;
1080 data[7] = 0x50;
Harald Welte7e2f57d2009-07-04 17:39:00 +02001081
1082 /* Hardcoded Destination Address */
Harald Welte59b04682009-06-10 05:40:52 +08001083 data = (u_int8_t *)msgb_put(msg, 1);
Harald Welte7e2f57d2009-07-04 17:39:00 +02001084 data[0] = 0; /* destination length == 0 */
Harald Welte59b04682009-06-10 05:40:52 +08001085
Harald Welte68b7df22009-08-08 16:03:15 +02001086 /* obtain a pointer for the rp_ud_len, so we can fill it later */
1087 rp_ud_len = (u_int8_t *)msgb_put(msg, 1);
Harald Welte59b04682009-06-10 05:40:52 +08001088
Harald Welte68b7df22009-08-08 16:03:15 +02001089#if 1
1090 /* generate the 03.40 TPDU */
1091 rc = gsm340_gen_tpdu(msg, sms);
1092 if (rc < 0) {
1093 msgb_free(msg);
1094 return rc;
1095 }
Harald Welte59b04682009-06-10 05:40:52 +08001096
Harald Welte68b7df22009-08-08 16:03:15 +02001097 *rp_ud_len = rc;
1098#else
1099 data = msgb_put(msg, sizeof(tpdu_test));
Harald Welte59b04682009-06-10 05:40:52 +08001100 memcpy(data, tpdu_test, sizeof(tpdu_test));
Harald Welte68b7df22009-08-08 16:03:15 +02001101 *rp_ud_len = sizeof(tpdu_test);
1102#endif
Harald Welte59b04682009-06-10 05:40:52 +08001103
Harald Welte68b7df22009-08-08 16:03:15 +02001104 DEBUGP(DSMS, "TX: SMS DELIVER\n");
Harald Welte59b04682009-06-10 05:40:52 +08001105
Holger Hans Peter Freytherde896e52010-03-23 07:56:22 +01001106 counter_inc(conn->bts->network->stats.sms.delivered);
Harald Welte3edc5a92009-12-22 00:41:05 +01001107
Harald Welteb78996d2009-07-27 20:11:35 +02001108 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
1109 /* FIXME: enter 'wait for RP-ACK' state, start TR1N */
Harald Welte59b04682009-06-10 05:40:52 +08001110}
Harald Welteb78996d2009-07-27 20:11:35 +02001111
Harald Weltefc01b242009-08-09 19:07:41 +02001112/* RLL SAPI3 establish callback. Now we have a RLL connection and
1113 * can deliver the actual message */
Harald Welte09421d32009-08-09 14:59:02 +02001114static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
1115 void *_sms, enum bsc_rllr_ind type)
1116{
1117 struct gsm_sms *sms = _sms;
1118
1119 DEBUGP(DSMS, "rll_ind_cb(lchan=%p, link_id=%u, sms=%p, type=%u\n",
1120 lchan, link_id, sms, type);
1121
1122 switch (type) {
1123 case BSC_RLLR_IND_EST_CONF:
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001124#warning "BROKEN: The BSC will establish this transparently"
1125 gsm411_send_sms_lchan(&lchan->conn, sms);
Harald Welte09421d32009-08-09 14:59:02 +02001126 break;
1127 case BSC_RLLR_IND_REL_IND:
1128 case BSC_RLLR_IND_ERR_IND:
1129 case BSC_RLLR_IND_TIMEOUT:
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001130#warning "BROKEN: We will need to handle SAPI n Reject"
Harald Welte09421d32009-08-09 14:59:02 +02001131 sms_free(sms);
1132 break;
1133 }
1134}
1135
Harald Weltefc01b242009-08-09 19:07:41 +02001136/* paging callback. Here we get called if paging a subscriber has
1137 * succeeded or failed. */
Harald Welte68b7df22009-08-08 16:03:15 +02001138static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
1139 struct msgb *msg, void *_lchan, void *_sms)
Harald Welteb78996d2009-07-27 20:11:35 +02001140{
Harald Welte68b7df22009-08-08 16:03:15 +02001141 struct gsm_lchan *lchan = _lchan;
1142 struct gsm_sms *sms = _sms;
1143 int rc;
Harald Welteb78996d2009-07-27 20:11:35 +02001144
Harald Welte68b7df22009-08-08 16:03:15 +02001145 DEBUGP(DSMS, "paging_cb_send_sms(hooknum=%u, event=%u, msg=%p,"
1146 "lchan=%p, sms=%p)\n", hooknum, event, msg, lchan, sms);
1147
1148 if (hooknum != GSM_HOOK_RR_PAGING)
1149 return -EINVAL;
1150
1151 switch (event) {
1152 case GSM_PAGING_SUCCEEDED:
1153 /* Paging aborted without lchan ?!? */
1154 if (!lchan) {
1155 sms_free(sms);
1156 rc = -EIO;
1157 break;
1158 }
Harald Weltefc01b242009-08-09 19:07:41 +02001159 /* Establish a SAPI3 RLL connection for SMS */
Harald Welte09421d32009-08-09 14:59:02 +02001160 rc = rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
Harald Welte68b7df22009-08-08 16:03:15 +02001161 break;
1162 case GSM_PAGING_EXPIRED:
Holger Hans Peter Freyther54d5dd52010-06-10 18:20:54 +08001163 case GSM_PAGING_OOM:
Harald Welte68b7df22009-08-08 16:03:15 +02001164 sms_free(sms);
1165 rc = -ETIMEDOUT;
1166 break;
Harald Welte68b7df22009-08-08 16:03:15 +02001167 }
1168
1169 return rc;
1170}
1171
Harald Weltefc01b242009-08-09 19:07:41 +02001172/* high-level function to send a SMS to a given subscriber. The function
1173 * will take care of paging the subscriber, establishing the RLL SAPI3
1174 * connection, etc. */
Harald Welte68b7df22009-08-08 16:03:15 +02001175int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
1176 struct gsm_sms *sms)
1177{
Harald Weltefc01b242009-08-09 19:07:41 +02001178 struct gsm_lchan *lchan;
Harald Welted363c952009-08-15 03:16:17 +02001179 int rc;
Harald Weltefc01b242009-08-09 19:07:41 +02001180
Harald Welte68b7df22009-08-08 16:03:15 +02001181 /* check if we already have an open lchan to the subscriber.
1182 * if yes, send the SMS this way */
Harald Weltefc01b242009-08-09 19:07:41 +02001183 lchan = lchan_for_subscr(subscr);
1184 if (lchan)
1185 return rll_establish(lchan, UM_SAPI_SMS,
1186 rll_ind_cb, sms);
Harald Welte68b7df22009-08-08 16:03:15 +02001187
1188 /* if not, we have to start paging */
Holger Hans Peter Freyther99c10312010-06-10 18:21:25 +08001189 subscr_get_channel(subscr, RSL_CHANNEED_SDCCH, paging_cb_send_sms, sms);
Harald Welte68b7df22009-08-08 16:03:15 +02001190 return 0;
1191}
Harald Welte5b359d82009-07-28 00:44:49 +02001192
Harald Weltefc01b242009-08-09 19:07:41 +02001193static int subscr_sig_cb(unsigned int subsys, unsigned int signal,
1194 void *handler_data, void *signal_data)
1195{
1196 struct gsm_subscriber *subscr;
1197 struct gsm_lchan *lchan;
1198 struct gsm_sms *sms;
1199
1200 switch (signal) {
1201 case S_SUBSCR_ATTACHED:
1202 /* A subscriber has attached. Check if there are
1203 * any pending SMS for him to be delivered */
1204 subscr = signal_data;
1205 lchan = lchan_for_subscr(subscr);
1206 if (!lchan)
1207 break;
1208 sms = db_sms_get_unsent_for_subscr(subscr);
1209 if (!sms)
1210 break;
1211 /* Establish a SAPI3 RLL connection for SMS */
1212 rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
1213 break;
1214 default:
1215 break;
1216 }
1217 return 0;
1218}
1219
Harald Welte (local)9d0bd792009-08-14 14:52:17 +02001220void _gsm411_sms_trans_free(struct gsm_trans *trans)
1221{
1222 bsc_del_timer(&trans->sms.cp_timer);
1223}
1224
Harald Welte932e20d2009-07-28 00:41:45 +02001225static __attribute__((constructor)) void on_dso_load_sms(void)
1226{
Harald Weltefc01b242009-08-09 19:07:41 +02001227 register_signal_handler(SS_SUBSCR, subscr_sig_cb, NULL);
Harald Welte932e20d2009-07-28 00:41:45 +02001228}