blob: 3492f1f3bf76d18d3ba7b1e70004955ab0504d80 [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>
Harald Welte59b04682009-06-10 05:40:52 +080051
52#define GSM411_ALLOC_SIZE 1024
53#define GSM411_ALLOC_HEADROOM 128
54
Harald Welte09421d32009-08-09 14:59:02 +020055#define UM_SAPI_SMS 3 /* See GSM 04.05/04.06 */
56
Harald Welte (local)8751ee92009-08-15 02:30:58 +020057void *tall_gsms_ctx;
Harald Welteb78996d2009-07-27 20:11:35 +020058static u_int32_t new_callref = 0x40000001;
59
Harald Welte (local)cb4715c2009-08-14 10:42:43 +020060static const struct value_string cp_cause_strs[] = {
61 { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
62 { GSM411_CP_CAUSE_CONGESTION, "Congestion" },
63 { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
64 { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
65 { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
66 { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +020067 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
Harald Welte (local)cb4715c2009-08-14 10:42:43 +020068 "Message incompatible with protocol state" },
69 { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
70 { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
71 { 0, 0 }
72};
73
74static const struct value_string rp_cause_strs[] = {
75 { GSM411_RP_CAUSE_MO_NUM_UNASSIGNED, "(MO) Number not assigned" },
76 { GSM411_RP_CAUSE_MO_OP_DET_BARR, "(MO) Operator determined barring" },
77 { GSM411_RP_CAUSE_MO_CALL_BARRED, "(MO) Call barred" },
78 { GSM411_RP_CAUSE_MO_SMS_REJECTED, "(MO) SMS rejected" },
79 { GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER, "(MO) Destination out of order" },
80 { GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR, "(MO) Unidentified subscriber" },
81 { GSM411_RP_CAUSE_MO_FACILITY_REJ, "(MO) Facility reject" },
82 { GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR, "(MO) Unknown subscriber" },
83 { GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER, "(MO) Network out of order" },
84 { GSM411_RP_CAUSE_MO_TEMP_FAIL, "(MO) Temporary failure" },
85 { GSM411_RP_CAUSE_MO_CONGESTION, "(MO) Congestion" },
86 { GSM411_RP_CAUSE_MO_RES_UNAVAIL, "(MO) Resource unavailable" },
87 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR, "(MO) Requested facility not subscribed" },
88 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL, "(MO) Requested facility not implemented" },
89 { GSM411_RP_CAUSE_MO_INTERWORKING, "(MO) Interworking" },
90 /* valid only for MT */
91 { GSM411_RP_CAUSE_MT_MEM_EXCEEDED, "(MT) Memory Exceeded" },
92 /* valid for both directions */
93 { GSM411_RP_CAUSE_INV_TRANS_REF, "Invalid Transaction Reference" },
94 { GSM411_RP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
95 { GSM411_RP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
96 { GSM411_RP_CAUSE_MSGTYPE_NOTEXIST, "Message Type non-existant" },
97 { GSM411_RP_CAUSE_MSG_INCOMP_STATE, "Message incompatible with protocol state" },
98 { GSM411_RP_CAUSE_IE_NOTEXIST, "Information Element not existing" },
99 { GSM411_RP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
100 { 0, NULL }
101};
102
Harald Welte68b7df22009-08-08 16:03:15 +0200103struct gsm_sms *sms_alloc(void)
104{
105 return talloc_zero(tall_gsms_ctx, struct gsm_sms);
106}
107
108void sms_free(struct gsm_sms *sms)
109{
110 /* drop references to subscriber structure */
111 if (sms->sender)
112 subscr_put(sms->sender);
113 if (sms->receiver)
114 subscr_put(sms->receiver);
115
116 talloc_free(sms);
117}
118
Harald Welte59b04682009-06-10 05:40:52 +0800119struct msgb *gsm411_msgb_alloc(void)
120{
Harald Welte9cfc9352009-06-26 19:39:35 +0200121 return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
122 "GSM 04.11");
Harald Welte59b04682009-06-10 05:40:52 +0800123}
124
Holger Hans Peter Freyther7cdff242010-03-23 07:40:46 +0100125static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *msg, u_int8_t link_id)
Harald Welte59b04682009-06-10 05:40:52 +0800126{
Harald Welte68b7df22009-08-08 16:03:15 +0200127 DEBUGP(DSMS, "GSM4.11 TX %s\n", hexdump(msg->data, msg->len));
Holger Hans Peter Freyther7cdff242010-03-23 07:40:46 +0100128 msg->l3h = msg->data;
129 return gsm0808_submit_dtap(conn, msg, link_id);
Harald Welte59b04682009-06-10 05:40:52 +0800130}
131
Harald Welte5fa17a22009-08-10 00:24:32 +0200132/* SMC TC1* is expired */
133static void cp_timer_expired(void *data)
134{
135 struct gsm_trans *trans = data;
136
137 DEBUGP(DSMS, "SMC Timer TC1* is expired, calling trans_free()\n");
138 /* FIXME: we need to re-transmit the last CP-DATA 1..3 times */
139 trans_free(trans);
140}
141
Harald Welte7e2f57d2009-07-04 17:39:00 +0200142/* Prefix msg with a 04.08/04.11 CP header */
Harald Welteb78996d2009-07-27 20:11:35 +0200143static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
144 u_int8_t msg_type)
Harald Welte7e2f57d2009-07-04 17:39:00 +0200145{
146 struct gsm48_hdr *gh;
147
148 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
149 /* Outgoing needs the highest bit set */
Harald Welteb78996d2009-07-27 20:11:35 +0200150 gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
Harald Welte7e2f57d2009-07-04 17:39:00 +0200151 gh->msg_type = msg_type;
152
Harald Welteb78996d2009-07-27 20:11:35 +0200153 /* mobile originating */
154 switch (gh->msg_type) {
155 case GSM411_MT_CP_DATA:
156 /* 5.2.3.1.2: enter MO-wait for CP-ack */
Harald Welte09421d32009-08-09 14:59:02 +0200157 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
Harald Welteb78996d2009-07-27 20:11:35 +0200158 trans->sms.cp_state = GSM411_CPS_WAIT_CP_ACK;
Harald Welte5fa17a22009-08-10 00:24:32 +0200159 trans->sms.cp_timer.data = trans;
160 trans->sms.cp_timer.cb = cp_timer_expired;
161 /* 5.3.2.1: Set Timer TC1A */
162 bsc_schedule_timer(&trans->sms.cp_timer, GSM411_TMR_TC1A);
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200163 DEBUGP(DSMS, "TX: CP-DATA ");
164 break;
165 case GSM411_MT_CP_ACK:
166 DEBUGP(DSMS, "TX: CP-ACK ");
167 break;
168 case GSM411_MT_CP_ERROR:
Sylvain Munaut163a24a2009-12-18 18:28:07 +0100169 DEBUGP(DSMS, "TX: CP-ERROR ");
Harald Welteb78996d2009-07-27 20:11:35 +0200170 break;
171 }
172
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200173 DEBUGPC(DSMS, "trans=%x\n", trans->transaction_id);
174
Holger Hans Peter Freyther7cdff242010-03-23 07:40:46 +0100175 return gsm411_sendmsg(trans->conn, msg, trans->sms.link_id);
Harald Welte7e2f57d2009-07-04 17:39:00 +0200176}
177
178/* Prefix msg with a RP-DATA header and send as CP-DATA */
Harald Welteb78996d2009-07-27 20:11:35 +0200179static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
180 u_int8_t rp_msg_type, u_int8_t rp_msg_ref)
Harald Welte7e2f57d2009-07-04 17:39:00 +0200181{
182 struct gsm411_rp_hdr *rp;
Harald Weltef2e680b2009-08-10 00:22:19 +0200183 u_int8_t len = msg->len;
Harald Welte7e2f57d2009-07-04 17:39:00 +0200184
185 /* GSM 04.11 RP-DATA header */
186 rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
Harald Weltef2e680b2009-08-10 00:22:19 +0200187 rp->len = len + 2;
Harald Welte7e2f57d2009-07-04 17:39:00 +0200188 rp->msg_type = rp_msg_type;
189 rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */
190
Harald Welteb78996d2009-07-27 20:11:35 +0200191 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA);
Harald Welte7e2f57d2009-07-04 17:39:00 +0200192}
193
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100194/* Turn int into semi-octet representation: 98 => 0x89 */
195static u_int8_t bcdify(u_int8_t value)
196{
197 u_int8_t ret;
Steffen Neubauer94436952009-11-11 23:02:07 +0900198
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100199 ret = value / 10;
200 ret |= (value % 10) << 4;
201
202 return ret;
203}
204
205/* Turn semi-octet representation into int: 0x89 => 98 */
206static u_int8_t unbcdify(u_int8_t value)
207{
208 u_int8_t ret;
209
210 if ((value & 0x0F) > 9 || (value >> 4) > 9)
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200211 LOGP(DSMS, LOGL_ERROR,
Harald Welteced9a912009-12-24 15:08:18 +0100212 "unbcdify got too big nibble: 0x%02X\n", value);
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100213
214 ret = (value&0x0F)*10;
Steffen Neubauere5e0eb72009-11-26 23:38:41 +0100215 ret += value>>4;
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100216
217 return ret;
218}
219
220/* Generate 03.40 TP-SCTS */
221static void gsm340_gen_scts(u_int8_t *scts, time_t time)
222{
223 struct tm *tm = localtime(&time);
224
225 *scts++ = bcdify(tm->tm_year % 100);
226 *scts++ = bcdify(tm->tm_mon + 1);
227 *scts++ = bcdify(tm->tm_mday);
228 *scts++ = bcdify(tm->tm_hour);
229 *scts++ = bcdify(tm->tm_min);
230 *scts++ = bcdify(tm->tm_sec);
231 *scts++ = bcdify(tm->tm_gmtoff/(60*15));
232}
233
234/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */
235static time_t gsm340_scts(u_int8_t *scts)
236{
237 struct tm tm;
238
239 u_int8_t yr = unbcdify(*scts++);
240
241 if (yr <= 80)
242 tm.tm_year = 100 + yr;
243 else
244 tm.tm_year = yr;
245 tm.tm_mon = unbcdify(*scts++) - 1;
246 tm.tm_mday = unbcdify(*scts++);
247 tm.tm_hour = unbcdify(*scts++);
248 tm.tm_min = unbcdify(*scts++);
249 tm.tm_sec = unbcdify(*scts++);
250 /* according to gsm 03.40 time zone is
251 "expressed in quarters of an hour" */
252 tm.tm_gmtoff = unbcdify(*scts++) * 15*60;
253
254 return mktime(&tm);
255}
256
257/* Return the default validity period in minutes */
258static unsigned long gsm340_vp_default(void)
259{
260 unsigned long minutes;
261 /* Default validity: two days */
262 minutes = 24 * 60 * 2;
263 return minutes;
264}
265
266/* Decode validity period format 'relative' */
267static unsigned long gsm340_vp_relative(u_int8_t *sms_vp)
268{
269 /* Chapter 9.2.3.12.1 */
270 u_int8_t vp;
271 unsigned long minutes;
272
273 vp = *(sms_vp);
274 if (vp <= 143)
275 minutes = vp + 1 * 5;
276 else if (vp <= 167)
277 minutes = 12*60 + (vp-143) * 30;
278 else if (vp <= 196)
279 minutes = vp-166 * 60 * 24;
280 else
281 minutes = vp-192 * 60 * 24 * 7;
282 return minutes;
283}
284
285/* Decode validity period format 'absolute' */
286static unsigned long gsm340_vp_absolute(u_int8_t *sms_vp)
287{
288 /* Chapter 9.2.3.12.2 */
289 time_t expires, now;
290 unsigned long minutes;
291
292 expires = gsm340_scts(sms_vp);
293 now = mktime(gmtime(NULL));
294 if (expires <= now)
295 minutes = 0;
296 else
297 minutes = (expires-now)/60;
298 return minutes;
299}
300
301/* Decode validity period format 'relative in integer representation' */
302static unsigned long gsm340_vp_relative_integer(u_int8_t *sms_vp)
Harald Welte59b04682009-06-10 05:40:52 +0800303{
304 u_int8_t vp;
305 unsigned long minutes;
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100306 vp = *(sms_vp);
307 if (vp == 0) {
Harald Welteced9a912009-12-24 15:08:18 +0100308 LOGP(DSMS, LOGL_ERROR,
309 "reserved relative_integer validity period\n");
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100310 return gsm340_vp_default();
311 }
312 minutes = vp/60;
313 return minutes;
314}
315
316/* Decode validity period format 'relative in semi-octet representation' */
317static unsigned long gsm340_vp_relative_semioctet(u_int8_t *sms_vp)
318{
319 unsigned long minutes;
320 minutes = unbcdify(*sms_vp++)*60; /* hours */
321 minutes += unbcdify(*sms_vp++); /* minutes */
322 minutes += unbcdify(*sms_vp++)/60; /* seconds */
323 return minutes;
324}
325
326/* decode validity period. return minutes */
327static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp)
328{
329 u_int8_t fi; /* functionality indicator */
Harald Welte59b04682009-06-10 05:40:52 +0800330
Harald Welte68b7df22009-08-08 16:03:15 +0200331 switch (sms_vpf) {
Harald Welte59b04682009-06-10 05:40:52 +0800332 case GSM340_TP_VPF_RELATIVE:
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100333 return gsm340_vp_relative(sms_vp);
Harald Welte59b04682009-06-10 05:40:52 +0800334 case GSM340_TP_VPF_ABSOLUTE:
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100335 return gsm340_vp_absolute(sms_vp);
Harald Welte59b04682009-06-10 05:40:52 +0800336 case GSM340_TP_VPF_ENHANCED:
337 /* Chapter 9.2.3.12.3 */
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100338 fi = *sms_vp++;
339 /* ignore additional fi */
340 if (fi & (1<<7)) sms_vp++;
341 /* read validity period format */
342 switch (fi & 0b111) {
343 case 0b000:
344 return gsm340_vp_default(); /* no vpf specified */
345 case 0b001:
346 return gsm340_vp_relative(sms_vp);
347 case 0b010:
348 return gsm340_vp_relative_integer(sms_vp);
349 case 0b011:
350 return gsm340_vp_relative_semioctet(sms_vp);
351 default:
352 /* The GSM spec says that the SC should reject any
353 unsupported and/or undefined values. FIXME */
Harald Welteced9a912009-12-24 15:08:18 +0100354 LOGP(DSMS, LOGL_ERROR,
355 "Reserved enhanced validity period format\n");
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100356 return gsm340_vp_default();
357 }
Daniel Willmann426bb162009-08-13 03:40:49 +0200358 case GSM340_TP_VPF_NONE:
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100359 default:
360 return gsm340_vp_default();
Harald Welte59b04682009-06-10 05:40:52 +0800361 }
Harald Welte59b04682009-06-10 05:40:52 +0800362}
363
364/* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */
365enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
366{
367 u_int8_t cgbits = dcs >> 4;
368 enum sms_alphabet alpha = DCS_NONE;
369
370 if ((cgbits & 0xc) == 0) {
371 if (cgbits & 2)
Harald Welteced9a912009-12-24 15:08:18 +0100372 LOGP(DSMS, LOGL_NOTICE,
373 "Compressed SMS not supported yet\n");
Harald Welte59b04682009-06-10 05:40:52 +0800374
Daniel Willmannf2861022009-08-15 03:01:17 +0200375 switch ((dcs >> 2)&0x03) {
Harald Welte59b04682009-06-10 05:40:52 +0800376 case 0:
377 alpha = DCS_7BIT_DEFAULT;
378 break;
379 case 1:
380 alpha = DCS_8BIT_DATA;
381 break;
382 case 2:
383 alpha = DCS_UCS2;
384 break;
385 }
386 } else if (cgbits == 0xc || cgbits == 0xd)
387 alpha = DCS_7BIT_DEFAULT;
388 else if (cgbits == 0xe)
389 alpha = DCS_UCS2;
390 else if (cgbits == 0xf) {
391 if (dcs & 4)
392 alpha = DCS_8BIT_DATA;
393 else
394 alpha = DCS_7BIT_DEFAULT;
395 }
396
397 return alpha;
398}
399
Harald Welte68b7df22009-08-08 16:03:15 +0200400static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms)
Harald Welte59b04682009-06-10 05:40:52 +0800401{
402 if (db_sms_store(gsms) != 0) {
Harald Welteced9a912009-12-24 15:08:18 +0100403 LOGP(DSMS, LOGL_ERROR, "Failed to store SMS in Database\n");
Harald Welte156c5e62009-07-05 14:02:46 +0200404 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte59b04682009-06-10 05:40:52 +0800405 }
Harald Welte68b7df22009-08-08 16:03:15 +0200406 /* dispatch a signal to tell higher level about it */
407 dispatch_signal(SS_SMS, S_SMS_SUBMITTED, gsms);
Harald Welte (local)ced09ed2009-08-17 09:39:55 +0200408 /* try delivering the SMS right now */
409 //gsm411_send_sms_subscr(gsms->receiver, gsms);
410
Harald Welte59b04682009-06-10 05:40:52 +0800411 return 0;
412}
413
Harald Welte68b7df22009-08-08 16:03:15 +0200414/* generate a TPDU address field compliant with 03.40 sec. 9.1.2.5 */
415static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len,
416 struct gsm_subscriber *subscr)
Harald Welteb78996d2009-07-27 20:11:35 +0200417{
Harald Welte68b7df22009-08-08 16:03:15 +0200418 int len_in_bytes;
Harald Welteb78996d2009-07-27 20:11:35 +0200419
Harald Welte68b7df22009-08-08 16:03:15 +0200420 oa[1] = 0xb9; /* networks-specific number, private numbering plan */
421
Harald Weltefdc93d92010-03-07 23:40:35 +0100422 len_in_bytes = gsm48_encode_bcd_number(oa, oa_len, 1, subscr->extension);
Harald Welte68b7df22009-08-08 16:03:15 +0200423
424 /* GSM 03.40 tells us the length is in 'useful semi-octets' */
425 oa[0] = strlen(subscr->extension) & 0xff;
426
427 return len_in_bytes;
Harald Welteb78996d2009-07-27 20:11:35 +0200428}
429
Harald Welte68b7df22009-08-08 16:03:15 +0200430/* generate a msgb containing a TPDU derived from struct gsm_sms,
431 * returns total size of TPDU */
432static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
Harald Welteb78996d2009-07-27 20:11:35 +0200433{
Harald Welteb78996d2009-07-27 20:11:35 +0200434 u_int8_t *smsp;
435 u_int8_t oa[12]; /* max len per 03.40 */
436 u_int8_t oa_len = 0;
Daniel Willmanna31ed622009-08-13 03:39:07 +0200437 u_int8_t octet_len;
Harald Welte68b7df22009-08-08 16:03:15 +0200438 unsigned int old_msg_len = msg->len;
Harald Welteb78996d2009-07-27 20:11:35 +0200439
440 /* generate first octet with masked bits */
441 smsp = msgb_put(msg, 1);
Harald Welte68b7df22009-08-08 16:03:15 +0200442 /* TP-MTI (message type indicator) */
Harald Welteb78996d2009-07-27 20:11:35 +0200443 *smsp = GSM340_SMS_DELIVER_SC2MS;
Harald Welte68b7df22009-08-08 16:03:15 +0200444 /* TP-MMS (more messages to send) */
445 if (0 /* FIXME */)
Harald Welteb78996d2009-07-27 20:11:35 +0200446 *smsp |= 0x04;
Harald Welte68b7df22009-08-08 16:03:15 +0200447 /* TP-SRI(deliver)/SRR(submit) */
Harald Welteb78996d2009-07-27 20:11:35 +0200448 if (sms->status_rep_req)
449 *smsp |= 0x20;
Harald Welte68b7df22009-08-08 16:03:15 +0200450 /* TP-UDHI (indicating TP-UD contains a header) */
451 if (sms->ud_hdr_ind)
Harald Welteb78996d2009-07-27 20:11:35 +0200452 *smsp |= 0x40;
Harald Welte68b7df22009-08-08 16:03:15 +0200453#if 0
454 /* TP-RP (indicating that a reply path exists) */
Harald Welteb78996d2009-07-27 20:11:35 +0200455 if (sms->
456 *smsp |= 0x80;
457#endif
458
459 /* generate originator address */
Harald Welte68b7df22009-08-08 16:03:15 +0200460 oa_len = gsm340_gen_oa(oa, sizeof(oa), sms->sender);
Harald Welteb78996d2009-07-27 20:11:35 +0200461 smsp = msgb_put(msg, oa_len);
Harald Welteb78996d2009-07-27 20:11:35 +0200462 memcpy(smsp, oa, oa_len);
463
464 /* generate TP-PID */
465 smsp = msgb_put(msg, 1);
466 *smsp = sms->protocol_id;
467
468 /* generate TP-DCS */
469 smsp = msgb_put(msg, 1);
470 *smsp = sms->data_coding_scheme;
471
472 /* generate TP-SCTS */
473 smsp = msgb_put(msg, 7);
474 gsm340_gen_scts(smsp, time(NULL));
Harald Welte68b7df22009-08-08 16:03:15 +0200475
Harald Welteb78996d2009-07-27 20:11:35 +0200476 /* generate TP-UDL */
477 smsp = msgb_put(msg, 1);
Harald Welte68b7df22009-08-08 16:03:15 +0200478 *smsp = sms->user_data_len;
Harald Welteb78996d2009-07-27 20:11:35 +0200479
480 /* generate TP-UD */
Daniel Willmann8d786602009-08-15 03:01:46 +0200481 switch (gsm338_get_sms_alphabet(sms->data_coding_scheme)) {
482 case DCS_7BIT_DEFAULT:
Daniel Willmanna31ed622009-08-13 03:39:07 +0200483 octet_len = sms->user_data_len*7/8;
484 if (sms->user_data_len*7%8 != 0)
485 octet_len++;
Daniel Willmann8f31ed92009-08-12 21:17:06 +0200486 /* Warning, user_data_len indicates the amount of septets
487 * (characters), we need amount of octets occupied */
Daniel Willmanna31ed622009-08-13 03:39:07 +0200488 smsp = msgb_put(msg, octet_len);
489 memcpy(smsp, sms->user_data, octet_len);
Daniel Willmann8d786602009-08-15 03:01:46 +0200490 break;
491 case DCS_UCS2:
492 case DCS_8BIT_DATA:
493 smsp = msgb_put(msg, sms->user_data_len);
494 memcpy(smsp, sms->user_data, sms->user_data_len);
495 break;
496 default:
Harald Welteced9a912009-12-24 15:08:18 +0100497 LOGP(DSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: 0x%02X\n",
498 sms->data_coding_scheme);
Daniel Willmann8d786602009-08-15 03:01:46 +0200499 break;
Daniel Willmann8f31ed92009-08-12 21:17:06 +0200500 }
Harald Welteb78996d2009-07-27 20:11:35 +0200501
Harald Welte68b7df22009-08-08 16:03:15 +0200502 return msg->len - old_msg_len;
Harald Welteb78996d2009-07-27 20:11:35 +0200503}
504
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200505/* process an incoming TPDU (called from RP-DATA)
506 * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100507static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800508{
509 u_int8_t *smsp = msgb_sms(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800510 struct gsm_sms *gsms;
Harald Welte68b7df22009-08-08 16:03:15 +0200511 u_int8_t sms_mti, sms_mms, sms_vpf, sms_alphabet, sms_rp;
512 u_int8_t *sms_vp;
Harald Welte59b04682009-06-10 05:40:52 +0800513 u_int8_t da_len_bytes;
514 u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
515 int rc = 0;
516
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100517 counter_inc(conn->bts->network->stats.sms.submitted);
Harald Welte3edc5a92009-12-22 00:41:05 +0100518
Harald Welte68b7df22009-08-08 16:03:15 +0200519 gsms = sms_alloc();
520 if (!gsms)
Harald Welte156c5e62009-07-05 14:02:46 +0200521 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte59b04682009-06-10 05:40:52 +0800522
523 /* invert those fields where 0 means active/present */
Harald Welte68b7df22009-08-08 16:03:15 +0200524 sms_mti = *smsp & 0x03;
525 sms_mms = !!(*smsp & 0x04);
526 sms_vpf = (*smsp & 0x18) >> 3;
527 gsms->status_rep_req = (*smsp & 0x20);
528 gsms->ud_hdr_ind = (*smsp & 0x40);
529 sms_rp = (*smsp & 0x80);
Harald Welte59b04682009-06-10 05:40:52 +0800530
531 smsp++;
Harald Welte68b7df22009-08-08 16:03:15 +0200532 gsms->msg_ref = *smsp++;
Harald Welte59b04682009-06-10 05:40:52 +0800533
534 /* length in bytes of the destination address */
535 da_len_bytes = 2 + *smsp/2 + *smsp%2;
536 if (da_len_bytes > 12) {
Harald Welteced9a912009-12-24 15:08:18 +0100537 LOGP(DSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n");
Harald Welte156c5e62009-07-05 14:02:46 +0200538 rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
Harald Welte59b04682009-06-10 05:40:52 +0800539 goto out;
540 }
Harald Welte3794e152009-06-12 02:42:11 +0800541 memset(address_lv, 0, sizeof(address_lv));
Harald Welte59b04682009-06-10 05:40:52 +0800542 memcpy(address_lv, smsp, da_len_bytes);
543 /* mangle first byte to reflect length in bytes, not digits */
Harald Welte3794e152009-06-12 02:42:11 +0800544 address_lv[0] = da_len_bytes - 1;
Harald Welte59b04682009-06-10 05:40:52 +0800545 /* convert to real number */
Harald Weltefdc93d92010-03-07 23:40:35 +0100546 gsm48_decode_bcd_number(gsms->dest_addr, sizeof(gsms->dest_addr), address_lv, 1);
Harald Welte59b04682009-06-10 05:40:52 +0800547 smsp += da_len_bytes;
548
Harald Welte68b7df22009-08-08 16:03:15 +0200549 gsms->protocol_id = *smsp++;
550 gsms->data_coding_scheme = *smsp++;
Harald Welte59b04682009-06-10 05:40:52 +0800551
Harald Welte68b7df22009-08-08 16:03:15 +0200552 sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
Harald Welte59b04682009-06-10 05:40:52 +0800553
Harald Welte68b7df22009-08-08 16:03:15 +0200554 switch (sms_vpf) {
Harald Welte59b04682009-06-10 05:40:52 +0800555 case GSM340_TP_VPF_RELATIVE:
Harald Welte68b7df22009-08-08 16:03:15 +0200556 sms_vp = smsp++;
Harald Welte59b04682009-06-10 05:40:52 +0800557 break;
558 case GSM340_TP_VPF_ABSOLUTE:
559 case GSM340_TP_VPF_ENHANCED:
Harald Welte68b7df22009-08-08 16:03:15 +0200560 sms_vp = smsp;
Steffen Neubauer9cfb0402009-11-26 12:28:41 +0100561 /* the additional functionality indicator... */
Steffen Neubauerdd488d12009-12-05 12:44:41 +0100562 if (sms_vpf == GSM340_TP_VPF_ENHANCED && *smsp & (1<<7))
563 smsp++;
Harald Welte59b04682009-06-10 05:40:52 +0800564 smsp += 7;
565 break;
Daniel Willmann426bb162009-08-13 03:40:49 +0200566 case GSM340_TP_VPF_NONE:
567 sms_vp = 0;
568 break;
Harald Welte59b04682009-06-10 05:40:52 +0800569 default:
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200570 LOGP(DSMS, LOGL_NOTICE,
Harald Welteced9a912009-12-24 15:08:18 +0100571 "SMS Validity period not implemented: 0x%02x\n", sms_vpf);
Harald Welte68b7df22009-08-08 16:03:15 +0200572 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte59b04682009-06-10 05:40:52 +0800573 }
Harald Welte68b7df22009-08-08 16:03:15 +0200574 gsms->user_data_len = *smsp++;
575 if (gsms->user_data_len) {
576 memcpy(gsms->user_data, smsp, gsms->user_data_len);
Harald Welte59b04682009-06-10 05:40:52 +0800577
Harald Welte68b7df22009-08-08 16:03:15 +0200578 switch (sms_alphabet) {
Harald Welte59b04682009-06-10 05:40:52 +0800579 case DCS_7BIT_DEFAULT:
Harald Welte68b7df22009-08-08 16:03:15 +0200580 gsm_7bit_decode(gsms->text, smsp, gsms->user_data_len);
Harald Welte59b04682009-06-10 05:40:52 +0800581 break;
582 case DCS_8BIT_DATA:
583 case DCS_UCS2:
584 case DCS_NONE:
Harald Welte59b04682009-06-10 05:40:52 +0800585 break;
586 }
587 }
588
Holger Hans Peter Freyther065b8112010-03-23 06:41:45 +0100589 gsms->sender = subscr_get(msg->lchan->conn.subscr);
Harald Welteced9a912009-12-24 15:08:18 +0100590
591 LOGP(DSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, "
592 "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, "
593 "UserDataLength: 0x%02x, UserData: \"%s\"\n",
594 subscr_name(gsms->sender), sms_mti, sms_vpf, gsms->msg_ref,
595 gsms->protocol_id, gsms->data_coding_scheme, gsms->dest_addr,
596 gsms->user_data_len,
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200597 sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
Harald Welte68b7df22009-08-08 16:03:15 +0200598 hexdump(gsms->user_data, gsms->user_data_len));
Harald Welte59b04682009-06-10 05:40:52 +0800599
Harald Welte68b7df22009-08-08 16:03:15 +0200600 gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
Harald Welte156c5e62009-07-05 14:02:46 +0200601
Harald Welte68b7df22009-08-08 16:03:15 +0200602 dispatch_signal(SS_SMS, 0, gsms);
Harald Welte156c5e62009-07-05 14:02:46 +0200603
Harald Welte59b04682009-06-10 05:40:52 +0800604 /* determine gsms->receiver based on dialled number */
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100605 gsms->receiver = subscr_get_by_extension(conn->bts->network, gsms->dest_addr);
Harald Welte59b04682009-06-10 05:40:52 +0800606 if (!gsms->receiver) {
607 rc = 1; /* cause 1: unknown subscriber */
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100608 counter_inc(conn->bts->network->stats.sms.no_receiver);
Harald Welte59b04682009-06-10 05:40:52 +0800609 goto out;
610 }
611
Harald Welte68b7df22009-08-08 16:03:15 +0200612 switch (sms_mti) {
Harald Welte59b04682009-06-10 05:40:52 +0800613 case GSM340_SMS_SUBMIT_MS2SC:
614 /* MS is submitting a SMS */
Harald Welte68b7df22009-08-08 16:03:15 +0200615 rc = gsm340_rx_sms_submit(msg, gsms);
Harald Welte59b04682009-06-10 05:40:52 +0800616 break;
617 case GSM340_SMS_COMMAND_MS2SC:
618 case GSM340_SMS_DELIVER_REP_MS2SC:
Harald Welteced9a912009-12-24 15:08:18 +0100619 LOGP(DSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti);
Harald Welte156c5e62009-07-05 14:02:46 +0200620 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte59b04682009-06-10 05:40:52 +0800621 break;
622 default:
Harald Welteced9a912009-12-24 15:08:18 +0100623 LOGP(DSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti);
Harald Welte156c5e62009-07-05 14:02:46 +0200624 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte59b04682009-06-10 05:40:52 +0800625 break;
626 }
627
Harald Welte156c5e62009-07-05 14:02:46 +0200628 if (!rc && !gsms->receiver)
629 rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
630
Harald Welte59b04682009-06-10 05:40:52 +0800631out:
Harald Welte68b7df22009-08-08 16:03:15 +0200632 sms_free(gsms);
Harald Welte59b04682009-06-10 05:40:52 +0800633
634 return rc;
635}
636
Harald Welteb78996d2009-07-27 20:11:35 +0200637static int gsm411_send_rp_ack(struct gsm_trans *trans, u_int8_t msg_ref)
Harald Welte59b04682009-06-10 05:40:52 +0800638{
639 struct msgb *msg = gsm411_msgb_alloc();
Harald Welte59b04682009-06-10 05:40:52 +0800640
Harald Welte59b04682009-06-10 05:40:52 +0800641 DEBUGP(DSMS, "TX: SMS RP ACK\n");
642
Harald Welteb78996d2009-07-27 20:11:35 +0200643 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ACK_MT, msg_ref);
Harald Welte59b04682009-06-10 05:40:52 +0800644}
645
Harald Welteb78996d2009-07-27 20:11:35 +0200646static int gsm411_send_rp_error(struct gsm_trans *trans,
647 u_int8_t msg_ref, u_int8_t cause)
Harald Welte59b04682009-06-10 05:40:52 +0800648{
649 struct msgb *msg = gsm411_msgb_alloc();
Harald Welte59b04682009-06-10 05:40:52 +0800650
Harald Welte59b04682009-06-10 05:40:52 +0800651 msgb_tv_put(msg, 1, cause);
652
Harald Welteced9a912009-12-24 15:08:18 +0100653 LOGP(DSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200654 get_value_string(rp_cause_strs, cause));
Harald Welte59b04682009-06-10 05:40:52 +0800655
Harald Welteb78996d2009-07-27 20:11:35 +0200656 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
Harald Welte59b04682009-06-10 05:40:52 +0800657}
658
659/* Receive a 04.11 TPDU inside RP-DATA / user data */
Harald Welteb78996d2009-07-27 20:11:35 +0200660static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
661 struct gsm411_rp_hdr *rph,
Harald Welte59b04682009-06-10 05:40:52 +0800662 u_int8_t src_len, u_int8_t *src,
663 u_int8_t dst_len, u_int8_t *dst,
664 u_int8_t tpdu_len, u_int8_t *tpdu)
665{
Harald Welte59b04682009-06-10 05:40:52 +0800666 int rc = 0;
667
668 if (src_len && src)
Harald Welteced9a912009-12-24 15:08:18 +0100669 LOGP(DSMS, LOGL_ERROR, "RP-DATA (MO) with SRC ?!?\n");
Harald Welte59b04682009-06-10 05:40:52 +0800670
671 if (!dst_len || !dst || !tpdu_len || !tpdu) {
Harald Welteced9a912009-12-24 15:08:18 +0100672 LOGP(DSMS, LOGL_ERROR,
673 "RP-DATA (MO) without DST or TPDU ?!?\n");
Harald Welteb78996d2009-07-27 20:11:35 +0200674 gsm411_send_rp_error(trans, rph->msg_ref,
Harald Welte156c5e62009-07-05 14:02:46 +0200675 GSM411_RP_CAUSE_INV_MAND_INF);
Harald Welte59b04682009-06-10 05:40:52 +0800676 return -EIO;
677 }
Harald Welte2c5706d2010-04-30 14:27:05 +0200678 msg->l4h = tpdu;
Harald Welte59b04682009-06-10 05:40:52 +0800679
680 DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
Harald Welte59b04682009-06-10 05:40:52 +0800681
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100682 rc = gsm340_rx_tpdu(trans->conn, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800683 if (rc == 0)
Harald Welteb78996d2009-07-27 20:11:35 +0200684 return gsm411_send_rp_ack(trans, rph->msg_ref);
Harald Welte59b04682009-06-10 05:40:52 +0800685 else if (rc > 0)
Harald Welteb78996d2009-07-27 20:11:35 +0200686 return gsm411_send_rp_error(trans, rph->msg_ref, rc);
Harald Welte59b04682009-06-10 05:40:52 +0800687 else
688 return rc;
689}
690
691/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
Harald Welteb78996d2009-07-27 20:11:35 +0200692static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
693 struct gsm411_rp_hdr *rph)
Harald Welte59b04682009-06-10 05:40:52 +0800694{
695 u_int8_t src_len, dst_len, rpud_len;
696 u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
697
698 /* in the MO case, this should always be zero length */
699 src_len = rph->data[0];
700 if (src_len)
701 src = &rph->data[1];
702
703 dst_len = rph->data[1+src_len];
704 if (dst_len)
705 dst = &rph->data[1+src_len+1];
706
707 rpud_len = rph->data[1+src_len+1+dst_len];
708 if (rpud_len)
709 rp_ud = &rph->data[1+src_len+1+dst_len+1];
710
Harald Welte156c5e62009-07-05 14:02:46 +0200711 DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
712 src_len, dst_len, rpud_len);
Harald Welteb78996d2009-07-27 20:11:35 +0200713 return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst,
Harald Welte59b04682009-06-10 05:40:52 +0800714 rpud_len, rp_ud);
715}
716
Harald Welte09421d32009-08-09 14:59:02 +0200717/* Receive a 04.11 RP-ACK message (response to RP-DATA from us) */
Harald Welteb78996d2009-07-27 20:11:35 +0200718static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
719 struct gsm411_rp_hdr *rph)
Harald Welte156c5e62009-07-05 14:02:46 +0200720{
Harald Welte68b7df22009-08-08 16:03:15 +0200721 struct gsm_sms *sms = trans->sms.sms;
722
Harald Welte156c5e62009-07-05 14:02:46 +0200723 /* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
724 * successfully received a SMS. We can now safely mark it as
725 * transmitted */
726
Harald Welte09421d32009-08-09 14:59:02 +0200727 if (!trans->sms.is_mt) {
Harald Welteced9a912009-12-24 15:08:18 +0100728 LOGP(DSMS, LOGL_ERROR, "RX RP-ACK on a MO transfer ?\n");
Harald Welte09421d32009-08-09 14:59:02 +0200729 return gsm411_send_rp_error(trans, rph->msg_ref,
730 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
731 }
Harald Weltedd62b162009-07-09 23:52:59 +0200732
Harald Welte68b7df22009-08-08 16:03:15 +0200733 if (!sms) {
Harald Welteced9a912009-12-24 15:08:18 +0100734 LOGP(DSMS, LOGL_ERROR, "RX RP-ACK but no sms in transaction?!?\n");
Harald Welte09421d32009-08-09 14:59:02 +0200735 return gsm411_send_rp_error(trans, rph->msg_ref,
736 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte68b7df22009-08-08 16:03:15 +0200737 }
738
739 /* mark this SMS as sent in database */
740 db_sms_mark_sent(sms);
741
742 dispatch_signal(SS_SMS, S_SMS_DELIVERED, sms);
743
744 sms_free(sms);
745 trans->sms.sms = NULL;
746
Harald Weltefc01b242009-08-09 19:07:41 +0200747 /* check for more messages for this subscriber */
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +0100748 assert(msg->lchan->conn.subscr == trans->subscr);
749
750 sms = db_sms_get_unsent_for_subscr(trans->subscr);
Harald Weltefc01b242009-08-09 19:07:41 +0200751 if (sms)
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +0100752 gsm411_send_sms_lchan(trans->conn, sms);
Sylvain Munautd17cdeb2009-12-24 13:33:51 +0100753
754 /* free the transaction here */
755 trans_free(trans);
756
757 /* release channel if done */
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +0100758#warning "BROKEN. The SAPI will be released automatically by the BSC"
Sylvain Munautd17cdeb2009-12-24 13:33:51 +0100759 if (!sms)
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200760 rsl_release_request(msg->lchan, trans->sms.link_id);
Harald Welte68b7df22009-08-08 16:03:15 +0200761
762 return 0;
Harald Welte156c5e62009-07-05 14:02:46 +0200763}
764
Harald Welteb78996d2009-07-27 20:11:35 +0200765static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
766 struct gsm411_rp_hdr *rph)
Harald Welte156c5e62009-07-05 14:02:46 +0200767{
Holger Hans Peter Freythere9781842010-03-23 07:52:17 +0100768 struct gsm_network *net = trans->conn->bts->network;
Harald Welte68b7df22009-08-08 16:03:15 +0200769 struct gsm_sms *sms = trans->sms.sms;
Harald Welteb78996d2009-07-27 20:11:35 +0200770 u_int8_t cause_len = rph->data[0];
771 u_int8_t cause = rph->data[1];
772
Harald Welte156c5e62009-07-05 14:02:46 +0200773 /* Error in response to MT RP_DATA, i.e. the MS did not
774 * successfully receive the SMS. We need to investigate
775 * the cause and take action depending on it */
776
Harald Welteced9a912009-12-24 15:08:18 +0100777 LOGP(DSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
Holger Hans Peter Freytherde896e52010-03-23 07:56:22 +0100778 subscr_name(trans->conn->subscr), cause_len, cause,
Harald Welteced9a912009-12-24 15:08:18 +0100779 get_value_string(rp_cause_strs, cause));
Harald Welteb78996d2009-07-27 20:11:35 +0200780
Harald Welte09421d32009-08-09 14:59:02 +0200781 if (!trans->sms.is_mt) {
Harald Welteced9a912009-12-24 15:08:18 +0100782 LOGP(DSMS, LOGL_ERROR, "RX RP-ERR on a MO transfer ?\n");
Harald Welte (local)ced09ed2009-08-17 09:39:55 +0200783#if 0
Harald Welte09421d32009-08-09 14:59:02 +0200784 return gsm411_send_rp_error(trans, rph->msg_ref,
785 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
Harald Welte (local)ced09ed2009-08-17 09:39:55 +0200786#endif
Harald Welte09421d32009-08-09 14:59:02 +0200787 }
Harald Weltedd62b162009-07-09 23:52:59 +0200788
Harald Welte68b7df22009-08-08 16:03:15 +0200789 if (!sms) {
Harald Welteced9a912009-12-24 15:08:18 +0100790 LOGP(DSMS, LOGL_ERROR,
791 "RX RP-ERR, but no sms in transaction?!?\n");
Harald Welte (local)ced09ed2009-08-17 09:39:55 +0200792 return -EINVAL;
793#if 0
Harald Welte09421d32009-08-09 14:59:02 +0200794 return gsm411_send_rp_error(trans, rph->msg_ref,
795 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte (local)ced09ed2009-08-17 09:39:55 +0200796#endif
Harald Welte09421d32009-08-09 14:59:02 +0200797 }
798
799 if (cause == GSM411_RP_CAUSE_MT_MEM_EXCEEDED) {
800 /* MS has not enough memory to store the message. We need
801 * to store this in our database and wati for a SMMA message */
802 /* FIXME */
803 dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr);
Harald Weltebdbb7442009-12-22 19:07:32 +0100804 counter_inc(net->stats.sms.rp_err_mem);
Harald Welte3edc5a92009-12-22 00:41:05 +0100805 } else
Harald Weltebdbb7442009-12-22 19:07:32 +0100806 counter_inc(net->stats.sms.rp_err_other);
Harald Welte68b7df22009-08-08 16:03:15 +0200807
808 sms_free(sms);
809 trans->sms.sms = NULL;
810
Harald Welte (local)9d0bd792009-08-14 14:52:17 +0200811 //trans_free(trans);
Harald Welte68b7df22009-08-08 16:03:15 +0200812
Harald Welteb78996d2009-07-27 20:11:35 +0200813 return 0;
Harald Welte156c5e62009-07-05 14:02:46 +0200814}
815
Harald Welteb78996d2009-07-27 20:11:35 +0200816static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans,
817 struct gsm411_rp_hdr *rph)
Harald Welte156c5e62009-07-05 14:02:46 +0200818{
Harald Weltefc01b242009-08-09 19:07:41 +0200819 struct gsm_sms *sms;
Harald Welteb78996d2009-07-27 20:11:35 +0200820 int rc;
821
Harald Weltefc01b242009-08-09 19:07:41 +0200822 rc = gsm411_send_rp_ack(trans, rph->msg_ref);
823 trans->sms.rp_state = GSM411_RPS_IDLE;
824
Harald Welte156c5e62009-07-05 14:02:46 +0200825 /* MS tells us that it has memory for more SMS, we need
826 * to check if we have any pending messages for it and then
827 * transfer those */
Harald Welte68b7df22009-08-08 16:03:15 +0200828 dispatch_signal(SS_SMS, S_SMS_SMMA, trans->subscr);
Harald Welteb78996d2009-07-27 20:11:35 +0200829
Harald Weltefc01b242009-08-09 19:07:41 +0200830 /* check for more messages for this subscriber */
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +0100831 assert(msg->lchan->conn.subscr == trans->subscr);
832 sms = db_sms_get_unsent_for_subscr(trans->subscr);
Harald Weltefc01b242009-08-09 19:07:41 +0200833 if (sms)
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +0100834 gsm411_send_sms_lchan(trans->conn, sms);
Harald Weltefc01b242009-08-09 19:07:41 +0200835 else
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200836 rsl_release_request(msg->lchan, trans->sms.link_id);
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +0100837#warning "BROKEN: The SAPI=3 will be released automatically by the BSC"
Harald Welteb78996d2009-07-27 20:11:35 +0200838
839 return rc;
Harald Welte156c5e62009-07-05 14:02:46 +0200840}
841
Harald Welteb78996d2009-07-27 20:11:35 +0200842static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
843 struct gsm_trans *trans)
Harald Welte59b04682009-06-10 05:40:52 +0800844{
845 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
846 u_int8_t msg_type = rp_data->msg_type & 0x07;
847 int rc = 0;
848
849 switch (msg_type) {
850 case GSM411_MT_RP_DATA_MO:
Harald Welteb78996d2009-07-27 20:11:35 +0200851 DEBUGP(DSMS, "RX SMS RP-DATA (MO)\n");
852 /* start TR2N and enter 'wait to send RP-ACK state' */
853 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
854 rc = gsm411_rx_rp_data(msg, trans, rp_data);
Harald Welte59b04682009-06-10 05:40:52 +0800855 break;
856 case GSM411_MT_RP_ACK_MO:
Harald Welteb78996d2009-07-27 20:11:35 +0200857 DEBUGP(DSMS,"RX SMS RP-ACK (MO)\n");
858 rc = gsm411_rx_rp_ack(msg, trans, rp_data);
Harald Welte156c5e62009-07-05 14:02:46 +0200859 break;
Harald Welte59b04682009-06-10 05:40:52 +0800860 case GSM411_MT_RP_SMMA_MO:
Harald Welteb78996d2009-07-27 20:11:35 +0200861 DEBUGP(DSMS, "RX SMS RP-SMMA\n");
862 /* start TR2N and enter 'wait to send RP-ACK state' */
863 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
864 rc = gsm411_rx_rp_smma(msg, trans, rp_data);
865 break;
866 case GSM411_MT_RP_ERROR_MO:
867 rc = gsm411_rx_rp_error(msg, trans, rp_data);
Harald Welte59b04682009-06-10 05:40:52 +0800868 break;
869 default:
Harald Welteced9a912009-12-24 15:08:18 +0100870 LOGP(DSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type);
Harald Welteb78996d2009-07-27 20:11:35 +0200871 rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
872 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
Harald Welte59b04682009-06-10 05:40:52 +0800873 break;
874 }
875
876 return rc;
877}
878
Harald Welteb78996d2009-07-27 20:11:35 +0200879/* send CP-ACK to given transaction */
880static int gsm411_tx_cp_ack(struct gsm_trans *trans)
881{
882 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltefc01b242009-08-09 19:07:41 +0200883 int rc;
Harald Welteb78996d2009-07-27 20:11:35 +0200884
Harald Weltefc01b242009-08-09 19:07:41 +0200885 rc = gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ACK);
886
887 if (trans->sms.is_mt) {
888 /* If this is a MT SMS DELIVER, we can clear transaction here */
889 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Welte (local)9d0bd792009-08-14 14:52:17 +0200890 //trans_free(trans);
Harald Weltefc01b242009-08-09 19:07:41 +0200891 }
Holger Hans Peter Freyther182c7452009-08-10 07:59:27 +0200892
893 return rc;
Harald Welteb78996d2009-07-27 20:11:35 +0200894}
895
896static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
897{
898 struct msgb *msg = gsm411_msgb_alloc();
899 u_int8_t *causep;
900
Harald Welteced9a912009-12-24 15:08:18 +0100901 LOGP(DSMS, LOGL_NOTICE, "TX CP-ERROR, cause %d (%s)\n", cause,
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200902 get_value_string(cp_cause_strs, cause));
903
Harald Welte68b7df22009-08-08 16:03:15 +0200904 causep = msgb_put(msg, 1);
Harald Welteb78996d2009-07-27 20:11:35 +0200905 *causep = cause;
906
907 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ERROR);
908}
909
910/* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200911int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id)
Harald Welte59b04682009-06-10 05:40:52 +0800912{
913 struct gsm48_hdr *gh = msgb_l3(msg);
914 u_int8_t msg_type = gh->msg_type;
Harald Welteb78996d2009-07-27 20:11:35 +0200915 u_int8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
916 struct gsm_lchan *lchan = msg->lchan;
917 struct gsm_trans *trans;
Harald Welte59b04682009-06-10 05:40:52 +0800918 int rc = 0;
919
Holger Hans Peter Freyther065b8112010-03-23 06:41:45 +0100920 if (!lchan->conn.subscr)
Harald Welteb78996d2009-07-27 20:11:35 +0200921 return -EIO;
922 /* FIXME: send some error message */
923
Sylvain Munaute02fb9a2009-12-18 18:28:08 +0100924 DEBUGP(DSMS, "trans_id=%x ", transaction_id);
Holger Hans Peter Freyther065b8112010-03-23 06:41:45 +0100925 trans = trans_find_by_id(lchan->conn.subscr, GSM48_PDISC_SMS,
Harald Welteb78996d2009-07-27 20:11:35 +0200926 transaction_id);
927 if (!trans) {
Sylvain Munaut40c23322009-12-18 18:28:09 +0100928 DEBUGPC(DSMS, "(new) ");
Holger Hans Peter Freyther065b8112010-03-23 06:41:45 +0100929 trans = trans_alloc(lchan->conn.subscr, GSM48_PDISC_SMS,
Harald Welteb78996d2009-07-27 20:11:35 +0200930 transaction_id, new_callref++);
931 if (!trans) {
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200932 DEBUGPC(DSMS, "No memory for trans\n");
Harald Welteb78996d2009-07-27 20:11:35 +0200933 /* FIXME: send some error message */
934 return -ENOMEM;
935 }
936 trans->sms.cp_state = GSM411_CPS_IDLE;
937 trans->sms.rp_state = GSM411_RPS_IDLE;
938 trans->sms.is_mt = 0;
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200939 trans->sms.link_id = link_id;
Harald Welteb78996d2009-07-27 20:11:35 +0200940
Holger Hans Peter Freyther4009da42010-03-23 07:00:22 +0100941 trans->conn = &lchan->conn;
942 use_subscr_con(trans->conn);
Harald Welteb78996d2009-07-27 20:11:35 +0200943 }
944
Harald Welte59b04682009-06-10 05:40:52 +0800945 switch(msg_type) {
946 case GSM411_MT_CP_DATA:
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200947 DEBUGPC(DSMS, "RX SMS CP-DATA\n");
Sylvain Munauta5914da2009-12-24 16:47:08 +0100948
949 /* 5.4: For MO, if a CP-DATA is received for a new
950 * transaction, equals reception of an implicit
951 * last CP-ACK for previous transaction */
952 if (trans->sms.cp_state == GSM411_CPS_IDLE) {
953 int i;
954 struct gsm_trans *ptrans;
955
956 /* Scan through all remote initiated transactions */
957 for (i=8; i<15; i++) {
958 if (i == transaction_id)
959 continue;
960
Holger Hans Peter Freyther065b8112010-03-23 06:41:45 +0100961 ptrans = trans_find_by_id(lchan->conn.subscr,
Sylvain Munauta5914da2009-12-24 16:47:08 +0100962 GSM48_PDISC_SMS, i);
963 if (!ptrans)
964 continue;
965
966 DEBUGP(DSMS, "Implicit CP-ACK for trans_id=%x\n", i);
967
968 /* Finish it for good */
969 bsc_del_timer(&ptrans->sms.cp_timer);
970 ptrans->sms.cp_state = GSM411_CPS_IDLE;
971 trans_free(ptrans);
972 }
973 }
974
Harald Welte09421d32009-08-09 14:59:02 +0200975 /* 5.2.3.1.3: MO state exists when SMC has received
976 * CP-DATA, including sending of the assoc. CP-ACK */
977 /* 5.2.3.2.4: MT state exists when SMC has received
978 * CP-DATA, including sending of the assoc. CP-ACK */
979 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Welteb78996d2009-07-27 20:11:35 +0200980
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200981 /* SMC instance acknowledges the CP-DATA frame */
982 gsm411_tx_cp_ack(trans);
983
Harald Welteb78996d2009-07-27 20:11:35 +0200984 rc = gsm411_rx_cp_data(msg, gh, trans);
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200985#if 0
Harald Welteb78996d2009-07-27 20:11:35 +0200986 /* Send CP-ACK or CP-ERORR in response */
987 if (rc < 0) {
988 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_NET_FAIL);
989 } else
990 rc = gsm411_tx_cp_ack(trans);
Harald Welte (local)64994ce2009-08-14 11:41:12 +0200991#endif
Harald Welte59b04682009-06-10 05:40:52 +0800992 break;
993 case GSM411_MT_CP_ACK:
Harald Welteb78996d2009-07-27 20:11:35 +0200994 /* previous CP-DATA in this transaction was confirmed */
Harald Welte (local)cb4715c2009-08-14 10:42:43 +0200995 DEBUGPC(DSMS, "RX SMS CP-ACK\n");
Harald Welte09421d32009-08-09 14:59:02 +0200996 /* 5.2.3.1.3: MO state exists when SMC has received CP-ACK */
997 /* 5.2.3.2.4: MT state exists when SMC has received CP-ACK */
998 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Welte5fa17a22009-08-10 00:24:32 +0200999 /* Stop TC1* after CP-ACK has been received */
1000 bsc_del_timer(&trans->sms.cp_timer);
Harald Welte09421d32009-08-09 14:59:02 +02001001
Harald Welteb78996d2009-07-27 20:11:35 +02001002 if (!trans->sms.is_mt) {
Harald Welteb78996d2009-07-27 20:11:35 +02001003 /* FIXME: we have sont one CP-DATA, which was now
1004 * acknowledged. Check if we want to transfer more,
1005 * i.e. multi-part message */
1006 trans->sms.cp_state = GSM411_CPS_IDLE;
1007 trans_free(trans);
1008 }
Harald Welte59b04682009-06-10 05:40:52 +08001009 break;
1010 case GSM411_MT_CP_ERROR:
Harald Welte (local)cb4715c2009-08-14 10:42:43 +02001011 DEBUGPC(DSMS, "RX SMS CP-ERROR, cause %d (%s)\n", gh->data[0],
1012 get_value_string(cp_cause_strs, gh->data[0]));
Harald Welte5fa17a22009-08-10 00:24:32 +02001013 bsc_del_timer(&trans->sms.cp_timer);
Harald Welteb78996d2009-07-27 20:11:35 +02001014 trans->sms.cp_state = GSM411_CPS_IDLE;
1015 trans_free(trans);
Harald Welte59b04682009-06-10 05:40:52 +08001016 break;
1017 default:
Harald Welte (local)cb4715c2009-08-14 10:42:43 +02001018 DEBUGPC(DSMS, "RX Unimplemented CP msg_type: 0x%02x\n", msg_type);
Harald Welteb78996d2009-07-27 20:11:35 +02001019 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
Harald Welte09421d32009-08-09 14:59:02 +02001020 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Welteb78996d2009-07-27 20:11:35 +02001021 trans_free(trans);
Harald Welte59b04682009-06-10 05:40:52 +08001022 break;
1023 }
1024
Harald Welte59b04682009-06-10 05:40:52 +08001025 return rc;
1026}
1027
Harald Welte59b04682009-06-10 05:40:52 +08001028#if 0
Harald Welte59b04682009-06-10 05:40:52 +08001029/* Test TPDU - ALL YOUR */
1030static u_int8_t tpdu_test[] = {
1031 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
1032 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
1033 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
1034 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
1035};
1036#endif
1037
Harald Weltefc01b242009-08-09 19:07:41 +02001038/* Take a SMS in gsm_sms structure and send it through an already
1039 * existing lchan. We also assume that the caller ensured this lchan already
1040 * has a SAPI3 RLL connection! */
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001041int gsm411_send_sms_lchan(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
Harald Welte59b04682009-06-10 05:40:52 +08001042{
1043 struct msgb *msg = gsm411_msgb_alloc();
Harald Welteb78996d2009-07-27 20:11:35 +02001044 struct gsm_trans *trans;
Harald Welte68b7df22009-08-08 16:03:15 +02001045 u_int8_t *data, *rp_ud_len;
Harald Welte7e2f57d2009-07-04 17:39:00 +02001046 u_int8_t msg_ref = 42;
Sylvain Munaute65af1b2009-12-24 13:27:36 +01001047 int transaction_id;
Harald Welte68b7df22009-08-08 16:03:15 +02001048 int rc;
Harald Welte59b04682009-06-10 05:40:52 +08001049
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001050 transaction_id = trans_assign_trans_id(conn->subscr, GSM48_PDISC_SMS, 0);
Harald Welte6e55abf2009-12-22 13:45:58 +01001051 if (transaction_id == -1) {
Harald Welteced9a912009-12-24 15:08:18 +01001052 LOGP(DSMS, LOGL_ERROR, "No available transaction ids\n");
Harald Welte6e55abf2009-12-22 13:45:58 +01001053 return -EBUSY;
1054 }
Harald Weltefc01b242009-08-09 19:07:41 +02001055
Harald Welte68b7df22009-08-08 16:03:15 +02001056 DEBUGP(DSMS, "send_sms_lchan()\n");
Harald Welteb78996d2009-07-27 20:11:35 +02001057
Harald Welte68b7df22009-08-08 16:03:15 +02001058 /* FIXME: allocate transaction with message reference */
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001059 trans = trans_alloc(conn->subscr, GSM48_PDISC_SMS,
Harald Welte68b7df22009-08-08 16:03:15 +02001060 transaction_id, new_callref++);
1061 if (!trans) {
Harald Welteced9a912009-12-24 15:08:18 +01001062 LOGP(DSMS, LOGL_ERROR, "No memory for trans\n");
Harald Welte68b7df22009-08-08 16:03:15 +02001063 /* FIXME: send some error message */
1064 return -ENOMEM;
1065 }
1066 trans->sms.cp_state = GSM411_CPS_IDLE;
1067 trans->sms.rp_state = GSM411_RPS_IDLE;
1068 trans->sms.is_mt = 1;
1069 trans->sms.sms = sms;
Harald Welte (local)64994ce2009-08-14 11:41:12 +02001070 trans->sms.link_id = UM_SAPI_SMS; /* FIXME: main or SACCH ? */
Harald Welte68b7df22009-08-08 16:03:15 +02001071
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001072 trans->conn = conn;
Holger Hans Peter Freyther4009da42010-03-23 07:00:22 +01001073 use_subscr_con(trans->conn);
Harald Welte68b7df22009-08-08 16:03:15 +02001074
1075 /* Hardcode SMSC Originating Address for now */
Harald Welte59b04682009-06-10 05:40:52 +08001076 data = (u_int8_t *)msgb_put(msg, 8);
Harald Welte7e2f57d2009-07-04 17:39:00 +02001077 data[0] = 0x07; /* originator length == 7 */
Harald Welte156c5e62009-07-05 14:02:46 +02001078 data[1] = 0x91; /* type of number: international, ISDN */
1079 data[2] = 0x44; /* 447785016005 */
Harald Welte59b04682009-06-10 05:40:52 +08001080 data[3] = 0x77;
1081 data[4] = 0x58;
1082 data[5] = 0x10;
1083 data[6] = 0x06;
1084 data[7] = 0x50;
Harald Welte7e2f57d2009-07-04 17:39:00 +02001085
1086 /* Hardcoded Destination Address */
Harald Welte59b04682009-06-10 05:40:52 +08001087 data = (u_int8_t *)msgb_put(msg, 1);
Harald Welte7e2f57d2009-07-04 17:39:00 +02001088 data[0] = 0; /* destination length == 0 */
Harald Welte59b04682009-06-10 05:40:52 +08001089
Harald Welte68b7df22009-08-08 16:03:15 +02001090 /* obtain a pointer for the rp_ud_len, so we can fill it later */
1091 rp_ud_len = (u_int8_t *)msgb_put(msg, 1);
Harald Welte59b04682009-06-10 05:40:52 +08001092
Harald Welte68b7df22009-08-08 16:03:15 +02001093#if 1
1094 /* generate the 03.40 TPDU */
1095 rc = gsm340_gen_tpdu(msg, sms);
1096 if (rc < 0) {
1097 msgb_free(msg);
1098 return rc;
1099 }
Harald Welte59b04682009-06-10 05:40:52 +08001100
Harald Welte68b7df22009-08-08 16:03:15 +02001101 *rp_ud_len = rc;
1102#else
1103 data = msgb_put(msg, sizeof(tpdu_test));
Harald Welte59b04682009-06-10 05:40:52 +08001104 memcpy(data, tpdu_test, sizeof(tpdu_test));
Harald Welte68b7df22009-08-08 16:03:15 +02001105 *rp_ud_len = sizeof(tpdu_test);
1106#endif
Harald Welte59b04682009-06-10 05:40:52 +08001107
Harald Welte68b7df22009-08-08 16:03:15 +02001108 DEBUGP(DSMS, "TX: SMS DELIVER\n");
Harald Welte59b04682009-06-10 05:40:52 +08001109
Holger Hans Peter Freytherde896e52010-03-23 07:56:22 +01001110 counter_inc(conn->bts->network->stats.sms.delivered);
Harald Welte3edc5a92009-12-22 00:41:05 +01001111
Harald Welteb78996d2009-07-27 20:11:35 +02001112 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
1113 /* FIXME: enter 'wait for RP-ACK' state, start TR1N */
Harald Welte59b04682009-06-10 05:40:52 +08001114}
Harald Welteb78996d2009-07-27 20:11:35 +02001115
Harald Weltefc01b242009-08-09 19:07:41 +02001116/* RLL SAPI3 establish callback. Now we have a RLL connection and
1117 * can deliver the actual message */
Harald Welte09421d32009-08-09 14:59:02 +02001118static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
1119 void *_sms, enum bsc_rllr_ind type)
1120{
1121 struct gsm_sms *sms = _sms;
1122
1123 DEBUGP(DSMS, "rll_ind_cb(lchan=%p, link_id=%u, sms=%p, type=%u\n",
1124 lchan, link_id, sms, type);
1125
1126 switch (type) {
1127 case BSC_RLLR_IND_EST_CONF:
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001128#warning "BROKEN: The BSC will establish this transparently"
1129 gsm411_send_sms_lchan(&lchan->conn, sms);
Harald Welte09421d32009-08-09 14:59:02 +02001130 break;
1131 case BSC_RLLR_IND_REL_IND:
1132 case BSC_RLLR_IND_ERR_IND:
1133 case BSC_RLLR_IND_TIMEOUT:
Holger Hans Peter Freyther40772ef2010-03-23 07:32:23 +01001134#warning "BROKEN: We will need to handle SAPI n Reject"
Harald Welte09421d32009-08-09 14:59:02 +02001135 sms_free(sms);
1136 break;
1137 }
1138}
1139
Harald Weltefc01b242009-08-09 19:07:41 +02001140/* paging callback. Here we get called if paging a subscriber has
1141 * succeeded or failed. */
Harald Welte68b7df22009-08-08 16:03:15 +02001142static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
1143 struct msgb *msg, void *_lchan, void *_sms)
Harald Welteb78996d2009-07-27 20:11:35 +02001144{
Harald Welte68b7df22009-08-08 16:03:15 +02001145 struct gsm_lchan *lchan = _lchan;
1146 struct gsm_sms *sms = _sms;
1147 int rc;
Harald Welteb78996d2009-07-27 20:11:35 +02001148
Harald Welte68b7df22009-08-08 16:03:15 +02001149 DEBUGP(DSMS, "paging_cb_send_sms(hooknum=%u, event=%u, msg=%p,"
1150 "lchan=%p, sms=%p)\n", hooknum, event, msg, lchan, sms);
1151
1152 if (hooknum != GSM_HOOK_RR_PAGING)
1153 return -EINVAL;
1154
1155 switch (event) {
1156 case GSM_PAGING_SUCCEEDED:
1157 /* Paging aborted without lchan ?!? */
1158 if (!lchan) {
1159 sms_free(sms);
1160 rc = -EIO;
1161 break;
1162 }
Harald Weltefc01b242009-08-09 19:07:41 +02001163 /* Establish a SAPI3 RLL connection for SMS */
Harald Welte09421d32009-08-09 14:59:02 +02001164 rc = rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
Harald Welte68b7df22009-08-08 16:03:15 +02001165 break;
1166 case GSM_PAGING_EXPIRED:
1167 sms_free(sms);
1168 rc = -ETIMEDOUT;
1169 break;
1170 default:
1171 rc = -EINVAL;
1172 break;
1173 }
1174
1175 return rc;
1176}
1177
Harald Weltefc01b242009-08-09 19:07:41 +02001178/* high-level function to send a SMS to a given subscriber. The function
1179 * will take care of paging the subscriber, establishing the RLL SAPI3
1180 * connection, etc. */
Harald Welte68b7df22009-08-08 16:03:15 +02001181int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
1182 struct gsm_sms *sms)
1183{
Harald Weltefc01b242009-08-09 19:07:41 +02001184 struct gsm_lchan *lchan;
Harald Welted363c952009-08-15 03:16:17 +02001185 int rc;
Harald Weltefc01b242009-08-09 19:07:41 +02001186
Harald Welte68b7df22009-08-08 16:03:15 +02001187 /* check if we already have an open lchan to the subscriber.
1188 * if yes, send the SMS this way */
Harald Weltefc01b242009-08-09 19:07:41 +02001189 lchan = lchan_for_subscr(subscr);
1190 if (lchan)
1191 return rll_establish(lchan, UM_SAPI_SMS,
1192 rll_ind_cb, sms);
Harald Welte68b7df22009-08-08 16:03:15 +02001193
1194 /* if not, we have to start paging */
Harald Welted363c952009-08-15 03:16:17 +02001195 rc = paging_request(subscr->net, subscr, RSL_CHANNEED_SDCCH,
1196 paging_cb_send_sms, sms);
Harald Welte (local)dec08ee2009-08-15 11:25:45 +02001197 if (rc <= 0)
Harald Welted363c952009-08-15 03:16:17 +02001198 sms_free(sms);
Harald Welte68b7df22009-08-08 16:03:15 +02001199
1200 return 0;
1201}
Harald Welte5b359d82009-07-28 00:44:49 +02001202
Harald Weltefc01b242009-08-09 19:07:41 +02001203static int subscr_sig_cb(unsigned int subsys, unsigned int signal,
1204 void *handler_data, void *signal_data)
1205{
1206 struct gsm_subscriber *subscr;
1207 struct gsm_lchan *lchan;
1208 struct gsm_sms *sms;
1209
1210 switch (signal) {
1211 case S_SUBSCR_ATTACHED:
1212 /* A subscriber has attached. Check if there are
1213 * any pending SMS for him to be delivered */
1214 subscr = signal_data;
1215 lchan = lchan_for_subscr(subscr);
1216 if (!lchan)
1217 break;
1218 sms = db_sms_get_unsent_for_subscr(subscr);
1219 if (!sms)
1220 break;
1221 /* Establish a SAPI3 RLL connection for SMS */
1222 rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
1223 break;
1224 default:
1225 break;
1226 }
1227 return 0;
1228}
1229
Harald Welte (local)9d0bd792009-08-14 14:52:17 +02001230void _gsm411_sms_trans_free(struct gsm_trans *trans)
1231{
1232 bsc_del_timer(&trans->sms.cp_timer);
1233}
1234
Harald Welte932e20d2009-07-28 00:41:45 +02001235static __attribute__((constructor)) void on_dso_load_sms(void)
1236{
Harald Weltefc01b242009-08-09 19:07:41 +02001237 register_signal_handler(SS_SUBSCR, subscr_sig_cb, NULL);
Harald Welte932e20d2009-07-28 00:41:45 +02001238}