blob: 40b257d507c396ede47db97935f75bba0ef21fef [file] [log] [blame]
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001/* Point-to-Point (PP) Short Message Service (SMS)
2 * Support on Mobile Radio Interface
3 * 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0 */
4
5/* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
Harald Welte7e310b12009-03-30 20:56:32 +00006 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
Daniel Willmann8b3390e2008-12-28 00:31:09 +00007 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 *
24 */
25
26
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +010027#include <assert.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <errno.h>
Harald Weltef3efc592009-07-27 20:11:35 +020032#include <time.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000033#include <netinet/in.h>
34
Harald Weltedfe6c7d2010-02-20 16:24:02 +010035#include <osmocore/msgb.h>
36#include <osmocore/tlv.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000037#include <openbsc/debug.h>
Daniel Willmann471712b2008-12-29 01:54:02 +000038#include <openbsc/gsm_data.h>
39#include <openbsc/gsm_subscriber.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000040#include <openbsc/gsm_04_11.h>
41#include <openbsc/gsm_04_08.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010042#include <osmocore/gsm_utils.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000043#include <openbsc/abis_rsl.h>
Holger Freyther9b177762009-02-16 19:07:18 +000044#include <openbsc/signal.h>
Harald Welte7e310b12009-03-30 20:56:32 +000045#include <openbsc/db.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010046#include <osmocore/talloc.h>
Harald Weltef3efc592009-07-27 20:11:35 +020047#include <openbsc/transaction.h>
Harald Welte76042182009-08-08 16:03:15 +020048#include <openbsc/paging.h>
Harald Weltecb8f4432009-08-09 14:59:02 +020049#include <openbsc/bsc_rll.h>
Holger Hans Peter Freyther34e97492009-08-10 07:54:02 +020050#include <openbsc/chan_alloc.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000051
Daniel Willmann471712b2008-12-29 01:54:02 +000052#define GSM411_ALLOC_SIZE 1024
53#define GSM411_ALLOC_HEADROOM 128
54
Harald Weltecb8f4432009-08-09 14:59:02 +020055#define UM_SAPI_SMS 3 /* See GSM 04.05/04.06 */
56
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020057void *tall_gsms_ctx;
Harald Weltef3efc592009-07-27 20:11:35 +020058static u_int32_t new_callref = 0x40000001;
59
Harald Welte (local)c89a5112009-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" },
67 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
68 "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 Welte76042182009-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
Holger Freythera553d092009-01-04 20:16:25 +0000119struct msgb *gsm411_msgb_alloc(void)
Daniel Willmann471712b2008-12-29 01:54:02 +0000120{
Harald Welte966636f2009-06-26 19:39:35 +0200121 return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
122 "GSM 04.11");
Daniel Willmann471712b2008-12-29 01:54:02 +0000123}
124
Harald Welte (local)daef6062009-08-14 11:41:12 +0200125static int gsm411_sendmsg(struct msgb *msg, u_int8_t link_id)
Daniel Willmann471712b2008-12-29 01:54:02 +0000126{
127 if (msg->lchan)
128 msg->trx = msg->lchan->ts->trx;
129
130 msg->l3h = msg->data;
131
Harald Welte76042182009-08-08 16:03:15 +0200132 DEBUGP(DSMS, "GSM4.11 TX %s\n", hexdump(msg->data, msg->len));
133
Harald Welte (local)daef6062009-08-14 11:41:12 +0200134 return rsl_data_request(msg, link_id);
Daniel Willmann471712b2008-12-29 01:54:02 +0000135}
136
Harald Welte41985612009-08-10 00:24:32 +0200137/* SMC TC1* is expired */
138static void cp_timer_expired(void *data)
139{
140 struct gsm_trans *trans = data;
141
142 DEBUGP(DSMS, "SMC Timer TC1* is expired, calling trans_free()\n");
143 /* FIXME: we need to re-transmit the last CP-DATA 1..3 times */
144 trans_free(trans);
145}
146
Harald Welte87f5d632009-07-04 17:39:00 +0200147/* Prefix msg with a 04.08/04.11 CP header */
Harald Weltef3efc592009-07-27 20:11:35 +0200148static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
149 u_int8_t msg_type)
Harald Welte87f5d632009-07-04 17:39:00 +0200150{
151 struct gsm48_hdr *gh;
152
153 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
154 /* Outgoing needs the highest bit set */
Harald Weltef3efc592009-07-27 20:11:35 +0200155 gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
Harald Welte87f5d632009-07-04 17:39:00 +0200156 gh->msg_type = msg_type;
157
Harald Weltef3efc592009-07-27 20:11:35 +0200158 /* assign the outgoing lchan */
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +0100159 msg->lchan = trans->conn->lchan;
Harald Weltef3efc592009-07-27 20:11:35 +0200160
161 /* mobile originating */
162 switch (gh->msg_type) {
163 case GSM411_MT_CP_DATA:
164 /* 5.2.3.1.2: enter MO-wait for CP-ack */
Harald Weltecb8f4432009-08-09 14:59:02 +0200165 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
Harald Weltef3efc592009-07-27 20:11:35 +0200166 trans->sms.cp_state = GSM411_CPS_WAIT_CP_ACK;
Harald Welte41985612009-08-10 00:24:32 +0200167 trans->sms.cp_timer.data = trans;
168 trans->sms.cp_timer.cb = cp_timer_expired;
169 /* 5.3.2.1: Set Timer TC1A */
170 bsc_schedule_timer(&trans->sms.cp_timer, GSM411_TMR_TC1A);
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200171 DEBUGP(DSMS, "TX: CP-DATA ");
172 break;
173 case GSM411_MT_CP_ACK:
174 DEBUGP(DSMS, "TX: CP-ACK ");
175 break;
176 case GSM411_MT_CP_ERROR:
Sylvain Munaut1d9efd62009-12-18 18:28:07 +0100177 DEBUGP(DSMS, "TX: CP-ERROR ");
Harald Weltef3efc592009-07-27 20:11:35 +0200178 break;
179 }
180
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200181 DEBUGPC(DSMS, "trans=%x\n", trans->transaction_id);
182
Harald Welte (local)daef6062009-08-14 11:41:12 +0200183 return gsm411_sendmsg(msg, trans->sms.link_id);
Harald Welte87f5d632009-07-04 17:39:00 +0200184}
185
186/* Prefix msg with a RP-DATA header and send as CP-DATA */
Harald Weltef3efc592009-07-27 20:11:35 +0200187static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
188 u_int8_t rp_msg_type, u_int8_t rp_msg_ref)
Harald Welte87f5d632009-07-04 17:39:00 +0200189{
190 struct gsm411_rp_hdr *rp;
Harald Welte0d544e72009-08-10 00:22:19 +0200191 u_int8_t len = msg->len;
Harald Welte87f5d632009-07-04 17:39:00 +0200192
193 /* GSM 04.11 RP-DATA header */
194 rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
Harald Welte0d544e72009-08-10 00:22:19 +0200195 rp->len = len + 2;
Harald Welte87f5d632009-07-04 17:39:00 +0200196 rp->msg_type = rp_msg_type;
197 rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */
198
Harald Weltef3efc592009-07-27 20:11:35 +0200199 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA);
Harald Welte87f5d632009-07-04 17:39:00 +0200200}
201
Steffen Neubauerf3262672009-11-26 12:28:41 +0100202/* Turn int into semi-octet representation: 98 => 0x89 */
203static u_int8_t bcdify(u_int8_t value)
204{
205 u_int8_t ret;
Steffen Neubauer5727cf42009-11-11 23:02:07 +0900206
Steffen Neubauerf3262672009-11-26 12:28:41 +0100207 ret = value / 10;
208 ret |= (value % 10) << 4;
209
210 return ret;
211}
212
213/* Turn semi-octet representation into int: 0x89 => 98 */
214static u_int8_t unbcdify(u_int8_t value)
215{
216 u_int8_t ret;
217
218 if ((value & 0x0F) > 9 || (value >> 4) > 9)
Harald Welted0cf7ba2009-12-24 15:08:18 +0100219 LOGP(DSMS, LOGL_ERROR,
220 "unbcdify got too big nibble: 0x%02X\n", value);
Steffen Neubauerf3262672009-11-26 12:28:41 +0100221
222 ret = (value&0x0F)*10;
Steffen Neubauerad69d7f2009-11-26 23:38:41 +0100223 ret += value>>4;
Steffen Neubauerf3262672009-11-26 12:28:41 +0100224
225 return ret;
226}
227
228/* Generate 03.40 TP-SCTS */
229static void gsm340_gen_scts(u_int8_t *scts, time_t time)
230{
231 struct tm *tm = localtime(&time);
232
233 *scts++ = bcdify(tm->tm_year % 100);
234 *scts++ = bcdify(tm->tm_mon + 1);
235 *scts++ = bcdify(tm->tm_mday);
236 *scts++ = bcdify(tm->tm_hour);
237 *scts++ = bcdify(tm->tm_min);
238 *scts++ = bcdify(tm->tm_sec);
239 *scts++ = bcdify(tm->tm_gmtoff/(60*15));
240}
241
242/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */
243static time_t gsm340_scts(u_int8_t *scts)
244{
245 struct tm tm;
246
247 u_int8_t yr = unbcdify(*scts++);
248
249 if (yr <= 80)
250 tm.tm_year = 100 + yr;
251 else
252 tm.tm_year = yr;
253 tm.tm_mon = unbcdify(*scts++) - 1;
254 tm.tm_mday = unbcdify(*scts++);
255 tm.tm_hour = unbcdify(*scts++);
256 tm.tm_min = unbcdify(*scts++);
257 tm.tm_sec = unbcdify(*scts++);
258 /* according to gsm 03.40 time zone is
259 "expressed in quarters of an hour" */
260 tm.tm_gmtoff = unbcdify(*scts++) * 15*60;
261
262 return mktime(&tm);
263}
264
265/* Return the default validity period in minutes */
266static unsigned long gsm340_vp_default(void)
267{
268 unsigned long minutes;
269 /* Default validity: two days */
270 minutes = 24 * 60 * 2;
271 return minutes;
272}
273
274/* Decode validity period format 'relative' */
275static unsigned long gsm340_vp_relative(u_int8_t *sms_vp)
276{
277 /* Chapter 9.2.3.12.1 */
278 u_int8_t vp;
279 unsigned long minutes;
280
281 vp = *(sms_vp);
282 if (vp <= 143)
283 minutes = vp + 1 * 5;
284 else if (vp <= 167)
285 minutes = 12*60 + (vp-143) * 30;
286 else if (vp <= 196)
287 minutes = vp-166 * 60 * 24;
288 else
289 minutes = vp-192 * 60 * 24 * 7;
290 return minutes;
291}
292
293/* Decode validity period format 'absolute' */
294static unsigned long gsm340_vp_absolute(u_int8_t *sms_vp)
295{
296 /* Chapter 9.2.3.12.2 */
297 time_t expires, now;
298 unsigned long minutes;
299
300 expires = gsm340_scts(sms_vp);
301 now = mktime(gmtime(NULL));
302 if (expires <= now)
303 minutes = 0;
304 else
305 minutes = (expires-now)/60;
306 return minutes;
307}
308
309/* Decode validity period format 'relative in integer representation' */
310static unsigned long gsm340_vp_relative_integer(u_int8_t *sms_vp)
Harald Welte7e310b12009-03-30 20:56:32 +0000311{
312 u_int8_t vp;
313 unsigned long minutes;
Steffen Neubauerf3262672009-11-26 12:28:41 +0100314 vp = *(sms_vp);
315 if (vp == 0) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100316 LOGP(DSMS, LOGL_ERROR,
317 "reserved relative_integer validity period\n");
Steffen Neubauerf3262672009-11-26 12:28:41 +0100318 return gsm340_vp_default();
319 }
320 minutes = vp/60;
321 return minutes;
322}
323
324/* Decode validity period format 'relative in semi-octet representation' */
325static unsigned long gsm340_vp_relative_semioctet(u_int8_t *sms_vp)
326{
327 unsigned long minutes;
328 minutes = unbcdify(*sms_vp++)*60; /* hours */
329 minutes += unbcdify(*sms_vp++); /* minutes */
330 minutes += unbcdify(*sms_vp++)/60; /* seconds */
331 return minutes;
332}
333
334/* decode validity period. return minutes */
335static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp)
336{
337 u_int8_t fi; /* functionality indicator */
Harald Welte7e310b12009-03-30 20:56:32 +0000338
Harald Welte76042182009-08-08 16:03:15 +0200339 switch (sms_vpf) {
Harald Welte7e310b12009-03-30 20:56:32 +0000340 case GSM340_TP_VPF_RELATIVE:
Steffen Neubauerf3262672009-11-26 12:28:41 +0100341 return gsm340_vp_relative(sms_vp);
Harald Welte7e310b12009-03-30 20:56:32 +0000342 case GSM340_TP_VPF_ABSOLUTE:
Steffen Neubauerf3262672009-11-26 12:28:41 +0100343 return gsm340_vp_absolute(sms_vp);
Harald Welte7e310b12009-03-30 20:56:32 +0000344 case GSM340_TP_VPF_ENHANCED:
345 /* Chapter 9.2.3.12.3 */
Steffen Neubauerf3262672009-11-26 12:28:41 +0100346 fi = *sms_vp++;
347 /* ignore additional fi */
348 if (fi & (1<<7)) sms_vp++;
349 /* read validity period format */
350 switch (fi & 0b111) {
351 case 0b000:
352 return gsm340_vp_default(); /* no vpf specified */
353 case 0b001:
354 return gsm340_vp_relative(sms_vp);
355 case 0b010:
356 return gsm340_vp_relative_integer(sms_vp);
357 case 0b011:
358 return gsm340_vp_relative_semioctet(sms_vp);
359 default:
360 /* The GSM spec says that the SC should reject any
361 unsupported and/or undefined values. FIXME */
Harald Welted0cf7ba2009-12-24 15:08:18 +0100362 LOGP(DSMS, LOGL_ERROR,
363 "Reserved enhanced validity period format\n");
Steffen Neubauerf3262672009-11-26 12:28:41 +0100364 return gsm340_vp_default();
365 }
Daniel Willmann58c83d82009-08-13 03:40:49 +0200366 case GSM340_TP_VPF_NONE:
Steffen Neubauerf3262672009-11-26 12:28:41 +0100367 default:
368 return gsm340_vp_default();
Harald Welte7e310b12009-03-30 20:56:32 +0000369 }
Harald Welte7e310b12009-03-30 20:56:32 +0000370}
371
372/* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */
373enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
374{
375 u_int8_t cgbits = dcs >> 4;
376 enum sms_alphabet alpha = DCS_NONE;
377
378 if ((cgbits & 0xc) == 0) {
379 if (cgbits & 2)
Harald Welted0cf7ba2009-12-24 15:08:18 +0100380 LOGP(DSMS, LOGL_NOTICE,
381 "Compressed SMS not supported yet\n");
Harald Welte7e310b12009-03-30 20:56:32 +0000382
Daniel Willmannd5d5e1d2009-08-15 03:01:17 +0200383 switch ((dcs >> 2)&0x03) {
Harald Welte7e310b12009-03-30 20:56:32 +0000384 case 0:
385 alpha = DCS_7BIT_DEFAULT;
386 break;
387 case 1:
388 alpha = DCS_8BIT_DATA;
389 break;
390 case 2:
391 alpha = DCS_UCS2;
392 break;
393 }
394 } else if (cgbits == 0xc || cgbits == 0xd)
395 alpha = DCS_7BIT_DEFAULT;
396 else if (cgbits == 0xe)
397 alpha = DCS_UCS2;
398 else if (cgbits == 0xf) {
399 if (dcs & 4)
400 alpha = DCS_8BIT_DATA;
401 else
402 alpha = DCS_7BIT_DEFAULT;
403 }
404
405 return alpha;
406}
407
Harald Welte76042182009-08-08 16:03:15 +0200408static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms)
Harald Welte7e310b12009-03-30 20:56:32 +0000409{
410 if (db_sms_store(gsms) != 0) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100411 LOGP(DSMS, LOGL_ERROR, "Failed to store SMS in Database\n");
Harald Welteb9c758b2009-07-05 14:02:46 +0200412 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000413 }
Harald Welte76042182009-08-08 16:03:15 +0200414 /* dispatch a signal to tell higher level about it */
415 dispatch_signal(SS_SMS, S_SMS_SUBMITTED, gsms);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200416 /* try delivering the SMS right now */
417 //gsm411_send_sms_subscr(gsms->receiver, gsms);
418
Harald Welte7e310b12009-03-30 20:56:32 +0000419 return 0;
420}
421
Harald Welte76042182009-08-08 16:03:15 +0200422/* generate a TPDU address field compliant with 03.40 sec. 9.1.2.5 */
423static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len,
424 struct gsm_subscriber *subscr)
Harald Weltef3efc592009-07-27 20:11:35 +0200425{
Harald Welte76042182009-08-08 16:03:15 +0200426 int len_in_bytes;
Harald Weltef3efc592009-07-27 20:11:35 +0200427
Harald Welte76042182009-08-08 16:03:15 +0200428 oa[1] = 0xb9; /* networks-specific number, private numbering plan */
429
Harald Welte55c8f352010-03-07 23:40:35 +0100430 len_in_bytes = gsm48_encode_bcd_number(oa, oa_len, 1, subscr->extension);
Harald Welte76042182009-08-08 16:03:15 +0200431
432 /* GSM 03.40 tells us the length is in 'useful semi-octets' */
433 oa[0] = strlen(subscr->extension) & 0xff;
434
435 return len_in_bytes;
Harald Weltef3efc592009-07-27 20:11:35 +0200436}
437
Harald Welte76042182009-08-08 16:03:15 +0200438/* generate a msgb containing a TPDU derived from struct gsm_sms,
439 * returns total size of TPDU */
440static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
Harald Weltef3efc592009-07-27 20:11:35 +0200441{
Harald Weltef3efc592009-07-27 20:11:35 +0200442 u_int8_t *smsp;
443 u_int8_t oa[12]; /* max len per 03.40 */
444 u_int8_t oa_len = 0;
Daniel Willmann9aef1452009-08-13 03:39:07 +0200445 u_int8_t octet_len;
Harald Welte76042182009-08-08 16:03:15 +0200446 unsigned int old_msg_len = msg->len;
Harald Weltef3efc592009-07-27 20:11:35 +0200447
448 /* generate first octet with masked bits */
449 smsp = msgb_put(msg, 1);
Harald Welte76042182009-08-08 16:03:15 +0200450 /* TP-MTI (message type indicator) */
Harald Weltef3efc592009-07-27 20:11:35 +0200451 *smsp = GSM340_SMS_DELIVER_SC2MS;
Harald Welte76042182009-08-08 16:03:15 +0200452 /* TP-MMS (more messages to send) */
453 if (0 /* FIXME */)
Harald Weltef3efc592009-07-27 20:11:35 +0200454 *smsp |= 0x04;
Harald Welte76042182009-08-08 16:03:15 +0200455 /* TP-SRI(deliver)/SRR(submit) */
Harald Weltef3efc592009-07-27 20:11:35 +0200456 if (sms->status_rep_req)
457 *smsp |= 0x20;
Harald Welte76042182009-08-08 16:03:15 +0200458 /* TP-UDHI (indicating TP-UD contains a header) */
459 if (sms->ud_hdr_ind)
Harald Weltef3efc592009-07-27 20:11:35 +0200460 *smsp |= 0x40;
Harald Welte76042182009-08-08 16:03:15 +0200461#if 0
462 /* TP-RP (indicating that a reply path exists) */
Harald Weltef3efc592009-07-27 20:11:35 +0200463 if (sms->
464 *smsp |= 0x80;
465#endif
466
467 /* generate originator address */
Harald Welte76042182009-08-08 16:03:15 +0200468 oa_len = gsm340_gen_oa(oa, sizeof(oa), sms->sender);
Harald Weltef3efc592009-07-27 20:11:35 +0200469 smsp = msgb_put(msg, oa_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200470 memcpy(smsp, oa, oa_len);
471
472 /* generate TP-PID */
473 smsp = msgb_put(msg, 1);
474 *smsp = sms->protocol_id;
475
476 /* generate TP-DCS */
477 smsp = msgb_put(msg, 1);
478 *smsp = sms->data_coding_scheme;
479
480 /* generate TP-SCTS */
481 smsp = msgb_put(msg, 7);
482 gsm340_gen_scts(smsp, time(NULL));
Harald Welte76042182009-08-08 16:03:15 +0200483
Harald Weltef3efc592009-07-27 20:11:35 +0200484 /* generate TP-UDL */
485 smsp = msgb_put(msg, 1);
Harald Welte76042182009-08-08 16:03:15 +0200486 *smsp = sms->user_data_len;
Harald Weltef3efc592009-07-27 20:11:35 +0200487
488 /* generate TP-UD */
Daniel Willmann6b024cb2009-08-15 03:01:46 +0200489 switch (gsm338_get_sms_alphabet(sms->data_coding_scheme)) {
490 case DCS_7BIT_DEFAULT:
Daniel Willmann9aef1452009-08-13 03:39:07 +0200491 octet_len = sms->user_data_len*7/8;
492 if (sms->user_data_len*7%8 != 0)
493 octet_len++;
Daniel Willmann6b1e8222009-08-12 21:17:06 +0200494 /* Warning, user_data_len indicates the amount of septets
495 * (characters), we need amount of octets occupied */
Daniel Willmann9aef1452009-08-13 03:39:07 +0200496 smsp = msgb_put(msg, octet_len);
497 memcpy(smsp, sms->user_data, octet_len);
Daniel Willmann6b024cb2009-08-15 03:01:46 +0200498 break;
499 case DCS_UCS2:
500 case DCS_8BIT_DATA:
501 smsp = msgb_put(msg, sms->user_data_len);
502 memcpy(smsp, sms->user_data, sms->user_data_len);
503 break;
504 default:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100505 LOGP(DSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: 0x%02X\n",
506 sms->data_coding_scheme);
Daniel Willmann6b024cb2009-08-15 03:01:46 +0200507 break;
Daniel Willmann6b1e8222009-08-12 21:17:06 +0200508 }
Harald Weltef3efc592009-07-27 20:11:35 +0200509
Harald Welte76042182009-08-08 16:03:15 +0200510 return msg->len - old_msg_len;
Harald Weltef3efc592009-07-27 20:11:35 +0200511}
512
Harald Welteb9c758b2009-07-05 14:02:46 +0200513/* process an incoming TPDU (called from RP-DATA)
514 * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
Harald Welte7e310b12009-03-30 20:56:32 +0000515static int gsm340_rx_tpdu(struct msgb *msg)
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000516{
Harald Welte9176bd42009-07-23 18:46:00 +0200517 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000518 u_int8_t *smsp = msgb_sms(msg);
Harald Welte7e310b12009-03-30 20:56:32 +0000519 struct gsm_sms *gsms;
Harald Welte76042182009-08-08 16:03:15 +0200520 u_int8_t sms_mti, sms_mms, sms_vpf, sms_alphabet, sms_rp;
521 u_int8_t *sms_vp;
Harald Welte7e310b12009-03-30 20:56:32 +0000522 u_int8_t da_len_bytes;
523 u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
524 int rc = 0;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000525
Harald Welteffa55a42009-12-22 19:07:32 +0100526 counter_inc(bts->network->stats.sms.submitted);
Harald Welte24ff6ee2009-12-22 00:41:05 +0100527
Harald Welte76042182009-08-08 16:03:15 +0200528 gsms = sms_alloc();
529 if (!gsms)
Harald Welteb9c758b2009-07-05 14:02:46 +0200530 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000531
532 /* invert those fields where 0 means active/present */
Harald Welte76042182009-08-08 16:03:15 +0200533 sms_mti = *smsp & 0x03;
534 sms_mms = !!(*smsp & 0x04);
535 sms_vpf = (*smsp & 0x18) >> 3;
536 gsms->status_rep_req = (*smsp & 0x20);
537 gsms->ud_hdr_ind = (*smsp & 0x40);
538 sms_rp = (*smsp & 0x80);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000539
540 smsp++;
Harald Welte76042182009-08-08 16:03:15 +0200541 gsms->msg_ref = *smsp++;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000542
Harald Welte7e310b12009-03-30 20:56:32 +0000543 /* length in bytes of the destination address */
544 da_len_bytes = 2 + *smsp/2 + *smsp%2;
545 if (da_len_bytes > 12) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100546 LOGP(DSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n");
Harald Welteb9c758b2009-07-05 14:02:46 +0200547 rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
Harald Welte7e310b12009-03-30 20:56:32 +0000548 goto out;
549 }
Harald Welte3cfdb222009-06-12 02:42:11 +0800550 memset(address_lv, 0, sizeof(address_lv));
Harald Welte7e310b12009-03-30 20:56:32 +0000551 memcpy(address_lv, smsp, da_len_bytes);
552 /* mangle first byte to reflect length in bytes, not digits */
Harald Welte3cfdb222009-06-12 02:42:11 +0800553 address_lv[0] = da_len_bytes - 1;
Harald Welte7e310b12009-03-30 20:56:32 +0000554 /* convert to real number */
Harald Welte55c8f352010-03-07 23:40:35 +0100555 gsm48_decode_bcd_number(gsms->dest_addr, sizeof(gsms->dest_addr), address_lv, 1);
Harald Welte7e310b12009-03-30 20:56:32 +0000556 smsp += da_len_bytes;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000557
Harald Welte76042182009-08-08 16:03:15 +0200558 gsms->protocol_id = *smsp++;
559 gsms->data_coding_scheme = *smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000560
Harald Welte76042182009-08-08 16:03:15 +0200561 sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
Harald Welte7e310b12009-03-30 20:56:32 +0000562
Harald Welte76042182009-08-08 16:03:15 +0200563 switch (sms_vpf) {
Harald Welte7e310b12009-03-30 20:56:32 +0000564 case GSM340_TP_VPF_RELATIVE:
Harald Welte76042182009-08-08 16:03:15 +0200565 sms_vp = smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000566 break;
567 case GSM340_TP_VPF_ABSOLUTE:
568 case GSM340_TP_VPF_ENHANCED:
Harald Welte76042182009-08-08 16:03:15 +0200569 sms_vp = smsp;
Steffen Neubauerf3262672009-11-26 12:28:41 +0100570 /* the additional functionality indicator... */
Steffen Neubauerac0c13c2009-12-05 12:44:41 +0100571 if (sms_vpf == GSM340_TP_VPF_ENHANCED && *smsp & (1<<7))
572 smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000573 smsp += 7;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000574 break;
Daniel Willmann58c83d82009-08-13 03:40:49 +0200575 case GSM340_TP_VPF_NONE:
576 sms_vp = 0;
577 break;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000578 default:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100579 LOGP(DSMS, LOGL_NOTICE,
580 "SMS Validity period not implemented: 0x%02x\n", sms_vpf);
Harald Welte76042182009-08-08 16:03:15 +0200581 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000582 }
Harald Welte76042182009-08-08 16:03:15 +0200583 gsms->user_data_len = *smsp++;
584 if (gsms->user_data_len) {
585 memcpy(gsms->user_data, smsp, gsms->user_data_len);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000586
Harald Welte76042182009-08-08 16:03:15 +0200587 switch (sms_alphabet) {
Harald Welte7e310b12009-03-30 20:56:32 +0000588 case DCS_7BIT_DEFAULT:
Harald Welte76042182009-08-08 16:03:15 +0200589 gsm_7bit_decode(gsms->text, smsp, gsms->user_data_len);
Harald Welte7e310b12009-03-30 20:56:32 +0000590 break;
591 case DCS_8BIT_DATA:
592 case DCS_UCS2:
593 case DCS_NONE:
Harald Welte7e310b12009-03-30 20:56:32 +0000594 break;
595 }
596 }
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000597
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100598 gsms->sender = subscr_get(msg->lchan->conn.subscr);
Harald Welted0cf7ba2009-12-24 15:08:18 +0100599
600 LOGP(DSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, "
601 "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, "
602 "UserDataLength: 0x%02x, UserData: \"%s\"\n",
603 subscr_name(gsms->sender), sms_mti, sms_vpf, gsms->msg_ref,
604 gsms->protocol_id, gsms->data_coding_scheme, gsms->dest_addr,
605 gsms->user_data_len,
Harald Welte76042182009-08-08 16:03:15 +0200606 sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
607 hexdump(gsms->user_data, gsms->user_data_len));
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000608
Harald Welte76042182009-08-08 16:03:15 +0200609 gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
Harald Welteb9c758b2009-07-05 14:02:46 +0200610
Harald Welte76042182009-08-08 16:03:15 +0200611 dispatch_signal(SS_SMS, 0, gsms);
Harald Welteb9c758b2009-07-05 14:02:46 +0200612
Harald Welte7e310b12009-03-30 20:56:32 +0000613 /* determine gsms->receiver based on dialled number */
Harald Welte76042182009-08-08 16:03:15 +0200614 gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr);
Harald Welte7e310b12009-03-30 20:56:32 +0000615 if (!gsms->receiver) {
616 rc = 1; /* cause 1: unknown subscriber */
Harald Welteffa55a42009-12-22 19:07:32 +0100617 counter_inc(bts->network->stats.sms.no_receiver);
Harald Welte7e310b12009-03-30 20:56:32 +0000618 goto out;
619 }
620
Harald Welte76042182009-08-08 16:03:15 +0200621 switch (sms_mti) {
Harald Welte7e310b12009-03-30 20:56:32 +0000622 case GSM340_SMS_SUBMIT_MS2SC:
623 /* MS is submitting a SMS */
Harald Welte76042182009-08-08 16:03:15 +0200624 rc = gsm340_rx_sms_submit(msg, gsms);
Harald Welte7e310b12009-03-30 20:56:32 +0000625 break;
626 case GSM340_SMS_COMMAND_MS2SC:
627 case GSM340_SMS_DELIVER_REP_MS2SC:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100628 LOGP(DSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200629 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000630 break;
631 default:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100632 LOGP(DSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200633 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000634 break;
635 }
636
Harald Welteb9c758b2009-07-05 14:02:46 +0200637 if (!rc && !gsms->receiver)
638 rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
639
Harald Welte7e310b12009-03-30 20:56:32 +0000640out:
Harald Welte76042182009-08-08 16:03:15 +0200641 sms_free(gsms);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000642
Harald Welte7e310b12009-03-30 20:56:32 +0000643 return rc;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000644}
645
Harald Weltef3efc592009-07-27 20:11:35 +0200646static int gsm411_send_rp_ack(struct gsm_trans *trans, u_int8_t msg_ref)
Daniel Willmann471712b2008-12-29 01:54:02 +0000647{
648 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000649
Daniel Willmann471712b2008-12-29 01:54:02 +0000650 DEBUGP(DSMS, "TX: SMS RP ACK\n");
651
Harald Weltef3efc592009-07-27 20:11:35 +0200652 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ACK_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000653}
654
Harald Weltef3efc592009-07-27 20:11:35 +0200655static int gsm411_send_rp_error(struct gsm_trans *trans,
656 u_int8_t msg_ref, u_int8_t cause)
Daniel Willmann471712b2008-12-29 01:54:02 +0000657{
658 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000659
Harald Welte7e310b12009-03-30 20:56:32 +0000660 msgb_tv_put(msg, 1, cause);
Daniel Willmann471712b2008-12-29 01:54:02 +0000661
Harald Welted0cf7ba2009-12-24 15:08:18 +0100662 LOGP(DSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200663 get_value_string(rp_cause_strs, cause));
Daniel Willmann471712b2008-12-29 01:54:02 +0000664
Harald Weltef3efc592009-07-27 20:11:35 +0200665 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000666}
667
Harald Welte7e310b12009-03-30 20:56:32 +0000668/* Receive a 04.11 TPDU inside RP-DATA / user data */
Harald Weltef3efc592009-07-27 20:11:35 +0200669static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
670 struct gsm411_rp_hdr *rph,
Harald Welte7e310b12009-03-30 20:56:32 +0000671 u_int8_t src_len, u_int8_t *src,
672 u_int8_t dst_len, u_int8_t *dst,
673 u_int8_t tpdu_len, u_int8_t *tpdu)
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000674{
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000675 int rc = 0;
676
Harald Welte7e310b12009-03-30 20:56:32 +0000677 if (src_len && src)
Harald Welted0cf7ba2009-12-24 15:08:18 +0100678 LOGP(DSMS, LOGL_ERROR, "RP-DATA (MO) with SRC ?!?\n");
Harald Welte7e310b12009-03-30 20:56:32 +0000679
680 if (!dst_len || !dst || !tpdu_len || !tpdu) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100681 LOGP(DSMS, LOGL_ERROR,
682 "RP-DATA (MO) without DST or TPDU ?!?\n");
Harald Weltef3efc592009-07-27 20:11:35 +0200683 gsm411_send_rp_error(trans, rph->msg_ref,
Harald Welteb9c758b2009-07-05 14:02:46 +0200684 GSM411_RP_CAUSE_INV_MAND_INF);
Harald Welte7e310b12009-03-30 20:56:32 +0000685 return -EIO;
686 }
687 msg->smsh = tpdu;
688
689 DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
Harald Welte7e310b12009-03-30 20:56:32 +0000690
691 rc = gsm340_rx_tpdu(msg);
692 if (rc == 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200693 return gsm411_send_rp_ack(trans, rph->msg_ref);
Harald Welte7e310b12009-03-30 20:56:32 +0000694 else if (rc > 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200695 return gsm411_send_rp_error(trans, rph->msg_ref, rc);
Harald Welte7e310b12009-03-30 20:56:32 +0000696 else
697 return rc;
698}
699
700/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
Harald Weltef3efc592009-07-27 20:11:35 +0200701static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
702 struct gsm411_rp_hdr *rph)
Harald Welte7e310b12009-03-30 20:56:32 +0000703{
704 u_int8_t src_len, dst_len, rpud_len;
705 u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
706
707 /* in the MO case, this should always be zero length */
708 src_len = rph->data[0];
709 if (src_len)
710 src = &rph->data[1];
711
712 dst_len = rph->data[1+src_len];
713 if (dst_len)
714 dst = &rph->data[1+src_len+1];
715
716 rpud_len = rph->data[1+src_len+1+dst_len];
717 if (rpud_len)
718 rp_ud = &rph->data[1+src_len+1+dst_len+1];
719
Harald Welteb9c758b2009-07-05 14:02:46 +0200720 DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
721 src_len, dst_len, rpud_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200722 return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst,
Harald Welte7e310b12009-03-30 20:56:32 +0000723 rpud_len, rp_ud);
724}
725
Harald Weltecb8f4432009-08-09 14:59:02 +0200726/* Receive a 04.11 RP-ACK message (response to RP-DATA from us) */
Harald Weltef3efc592009-07-27 20:11:35 +0200727static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
728 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200729{
Harald Welte76042182009-08-08 16:03:15 +0200730 struct gsm_sms *sms = trans->sms.sms;
731
Harald Welteb9c758b2009-07-05 14:02:46 +0200732 /* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
733 * successfully received a SMS. We can now safely mark it as
734 * transmitted */
735
Harald Weltecb8f4432009-08-09 14:59:02 +0200736 if (!trans->sms.is_mt) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100737 LOGP(DSMS, LOGL_ERROR, "RX RP-ACK on a MO transfer ?\n");
Harald Weltecb8f4432009-08-09 14:59:02 +0200738 return gsm411_send_rp_error(trans, rph->msg_ref,
739 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
740 }
Harald Welte3e0f6172009-07-09 23:52:59 +0200741
Harald Welte76042182009-08-08 16:03:15 +0200742 if (!sms) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100743 LOGP(DSMS, LOGL_ERROR, "RX RP-ACK but no sms in transaction?!?\n");
Harald Weltecb8f4432009-08-09 14:59:02 +0200744 return gsm411_send_rp_error(trans, rph->msg_ref,
745 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte76042182009-08-08 16:03:15 +0200746 }
747
748 /* mark this SMS as sent in database */
749 db_sms_mark_sent(sms);
750
751 dispatch_signal(SS_SMS, S_SMS_DELIVERED, sms);
752
753 sms_free(sms);
754 trans->sms.sms = NULL;
755
Harald Weltecf6a3812009-08-09 19:07:41 +0200756 /* check for more messages for this subscriber */
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +0100757 assert(msg->lchan->conn.subscr == trans->subscr);
758
759 sms = db_sms_get_unsent_for_subscr(trans->subscr);
Harald Weltecf6a3812009-08-09 19:07:41 +0200760 if (sms)
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +0100761 gsm411_send_sms_lchan(trans->conn, sms);
Sylvain Munautd6c35f62009-12-24 13:33:51 +0100762
763 /* free the transaction here */
764 trans_free(trans);
765
766 /* release channel if done */
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +0100767#warning "BROKEN. The SAPI will be released automatically by the BSC"
Sylvain Munautd6c35f62009-12-24 13:33:51 +0100768 if (!sms)
Harald Welte (local)daef6062009-08-14 11:41:12 +0200769 rsl_release_request(msg->lchan, trans->sms.link_id);
Harald Welte76042182009-08-08 16:03:15 +0200770
771 return 0;
Harald Welteb9c758b2009-07-05 14:02:46 +0200772}
773
Harald Weltef3efc592009-07-27 20:11:35 +0200774static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
775 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200776{
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +0100777 struct gsm_network *net = trans->conn->lchan->ts->trx->bts->network;
Harald Welte76042182009-08-08 16:03:15 +0200778 struct gsm_sms *sms = trans->sms.sms;
Harald Weltef3efc592009-07-27 20:11:35 +0200779 u_int8_t cause_len = rph->data[0];
780 u_int8_t cause = rph->data[1];
781
Harald Welteb9c758b2009-07-05 14:02:46 +0200782 /* Error in response to MT RP_DATA, i.e. the MS did not
783 * successfully receive the SMS. We need to investigate
784 * the cause and take action depending on it */
785
Harald Welted0cf7ba2009-12-24 15:08:18 +0100786 LOGP(DSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100787 subscr_name(msg->lchan->conn.subscr), cause_len, cause,
Harald Welted0cf7ba2009-12-24 15:08:18 +0100788 get_value_string(rp_cause_strs, cause));
Harald Weltef3efc592009-07-27 20:11:35 +0200789
Harald Weltecb8f4432009-08-09 14:59:02 +0200790 if (!trans->sms.is_mt) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100791 LOGP(DSMS, LOGL_ERROR, "RX RP-ERR on a MO transfer ?\n");
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200792#if 0
Harald Weltecb8f4432009-08-09 14:59:02 +0200793 return gsm411_send_rp_error(trans, rph->msg_ref,
794 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200795#endif
Harald Weltecb8f4432009-08-09 14:59:02 +0200796 }
Harald Welte3e0f6172009-07-09 23:52:59 +0200797
Harald Welte76042182009-08-08 16:03:15 +0200798 if (!sms) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100799 LOGP(DSMS, LOGL_ERROR,
800 "RX RP-ERR, but no sms in transaction?!?\n");
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200801 return -EINVAL;
802#if 0
Harald Weltecb8f4432009-08-09 14:59:02 +0200803 return gsm411_send_rp_error(trans, rph->msg_ref,
804 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200805#endif
Harald Weltecb8f4432009-08-09 14:59:02 +0200806 }
807
808 if (cause == GSM411_RP_CAUSE_MT_MEM_EXCEEDED) {
809 /* MS has not enough memory to store the message. We need
810 * to store this in our database and wati for a SMMA message */
811 /* FIXME */
812 dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr);
Harald Welteffa55a42009-12-22 19:07:32 +0100813 counter_inc(net->stats.sms.rp_err_mem);
Harald Welte24ff6ee2009-12-22 00:41:05 +0100814 } else
Harald Welteffa55a42009-12-22 19:07:32 +0100815 counter_inc(net->stats.sms.rp_err_other);
Harald Welte76042182009-08-08 16:03:15 +0200816
817 sms_free(sms);
818 trans->sms.sms = NULL;
819
Harald Welte (local)86b17172009-08-14 14:52:17 +0200820 //trans_free(trans);
Harald Welte76042182009-08-08 16:03:15 +0200821
Harald Weltef3efc592009-07-27 20:11:35 +0200822 return 0;
Harald Welteb9c758b2009-07-05 14:02:46 +0200823}
824
Harald Weltef3efc592009-07-27 20:11:35 +0200825static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans,
826 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200827{
Harald Weltecf6a3812009-08-09 19:07:41 +0200828 struct gsm_sms *sms;
Harald Weltef3efc592009-07-27 20:11:35 +0200829 int rc;
830
Harald Weltecf6a3812009-08-09 19:07:41 +0200831 rc = gsm411_send_rp_ack(trans, rph->msg_ref);
832 trans->sms.rp_state = GSM411_RPS_IDLE;
833
Harald Welteb9c758b2009-07-05 14:02:46 +0200834 /* MS tells us that it has memory for more SMS, we need
835 * to check if we have any pending messages for it and then
836 * transfer those */
Harald Welte76042182009-08-08 16:03:15 +0200837 dispatch_signal(SS_SMS, S_SMS_SMMA, trans->subscr);
Harald Weltef3efc592009-07-27 20:11:35 +0200838
Harald Weltecf6a3812009-08-09 19:07:41 +0200839 /* check for more messages for this subscriber */
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +0100840 assert(msg->lchan->conn.subscr == trans->subscr);
841 sms = db_sms_get_unsent_for_subscr(trans->subscr);
Harald Weltecf6a3812009-08-09 19:07:41 +0200842 if (sms)
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +0100843 gsm411_send_sms_lchan(trans->conn, sms);
Harald Weltecf6a3812009-08-09 19:07:41 +0200844 else
Harald Welte (local)daef6062009-08-14 11:41:12 +0200845 rsl_release_request(msg->lchan, trans->sms.link_id);
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +0100846#warning "BROKEN: The SAPI=3 will be released automatically by the BSC"
Harald Weltef3efc592009-07-27 20:11:35 +0200847
848 return rc;
Harald Welteb9c758b2009-07-05 14:02:46 +0200849}
850
Harald Weltef3efc592009-07-27 20:11:35 +0200851static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
852 struct gsm_trans *trans)
Harald Welte7e310b12009-03-30 20:56:32 +0000853{
Daniel Willmann471712b2008-12-29 01:54:02 +0000854 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000855 u_int8_t msg_type = rp_data->msg_type & 0x07;
Harald Welte7e310b12009-03-30 20:56:32 +0000856 int rc = 0;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000857
858 switch (msg_type) {
859 case GSM411_MT_RP_DATA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200860 DEBUGP(DSMS, "RX SMS RP-DATA (MO)\n");
861 /* start TR2N and enter 'wait to send RP-ACK state' */
862 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
863 rc = gsm411_rx_rp_data(msg, trans, rp_data);
Harald Welte7e310b12009-03-30 20:56:32 +0000864 break;
865 case GSM411_MT_RP_ACK_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200866 DEBUGP(DSMS,"RX SMS RP-ACK (MO)\n");
867 rc = gsm411_rx_rp_ack(msg, trans, rp_data);
Harald Welteb9c758b2009-07-05 14:02:46 +0200868 break;
Harald Welte7e310b12009-03-30 20:56:32 +0000869 case GSM411_MT_RP_SMMA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200870 DEBUGP(DSMS, "RX SMS RP-SMMA\n");
871 /* start TR2N and enter 'wait to send RP-ACK state' */
872 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
873 rc = gsm411_rx_rp_smma(msg, trans, rp_data);
874 break;
875 case GSM411_MT_RP_ERROR_MO:
876 rc = gsm411_rx_rp_error(msg, trans, rp_data);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000877 break;
878 default:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100879 LOGP(DSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type);
Harald Weltef3efc592009-07-27 20:11:35 +0200880 rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
881 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000882 break;
883 }
884
885 return rc;
886}
887
Harald Weltef3efc592009-07-27 20:11:35 +0200888/* send CP-ACK to given transaction */
889static int gsm411_tx_cp_ack(struct gsm_trans *trans)
890{
891 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltecf6a3812009-08-09 19:07:41 +0200892 int rc;
Harald Weltef3efc592009-07-27 20:11:35 +0200893
Harald Weltecf6a3812009-08-09 19:07:41 +0200894 rc = gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ACK);
895
896 if (trans->sms.is_mt) {
897 /* If this is a MT SMS DELIVER, we can clear transaction here */
898 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Welte (local)86b17172009-08-14 14:52:17 +0200899 //trans_free(trans);
Harald Weltecf6a3812009-08-09 19:07:41 +0200900 }
Holger Hans Peter Freyther09e364b2009-08-10 07:59:27 +0200901
902 return rc;
Harald Weltef3efc592009-07-27 20:11:35 +0200903}
904
905static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
906{
907 struct msgb *msg = gsm411_msgb_alloc();
908 u_int8_t *causep;
909
Harald Welted0cf7ba2009-12-24 15:08:18 +0100910 LOGP(DSMS, LOGL_NOTICE, "TX CP-ERROR, cause %d (%s)\n", cause,
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200911 get_value_string(cp_cause_strs, cause));
912
Harald Welte76042182009-08-08 16:03:15 +0200913 causep = msgb_put(msg, 1);
Harald Weltef3efc592009-07-27 20:11:35 +0200914 *causep = cause;
915
916 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ERROR);
917}
918
919/* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */
Harald Welte (local)daef6062009-08-14 11:41:12 +0200920int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id)
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000921{
922 struct gsm48_hdr *gh = msgb_l3(msg);
923 u_int8_t msg_type = gh->msg_type;
Harald Weltef3efc592009-07-27 20:11:35 +0200924 u_int8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
925 struct gsm_lchan *lchan = msg->lchan;
926 struct gsm_trans *trans;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000927 int rc = 0;
928
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100929 if (!lchan->conn.subscr)
Harald Weltef3efc592009-07-27 20:11:35 +0200930 return -EIO;
931 /* FIXME: send some error message */
932
Sylvain Munautc56a1412009-12-18 18:28:08 +0100933 DEBUGP(DSMS, "trans_id=%x ", transaction_id);
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100934 trans = trans_find_by_id(lchan->conn.subscr, GSM48_PDISC_SMS,
Harald Weltef3efc592009-07-27 20:11:35 +0200935 transaction_id);
936 if (!trans) {
Sylvain Munautfeaca922009-12-18 18:28:09 +0100937 DEBUGPC(DSMS, "(new) ");
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100938 trans = trans_alloc(lchan->conn.subscr, GSM48_PDISC_SMS,
Harald Weltef3efc592009-07-27 20:11:35 +0200939 transaction_id, new_callref++);
940 if (!trans) {
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200941 DEBUGPC(DSMS, "No memory for trans\n");
Harald Weltef3efc592009-07-27 20:11:35 +0200942 /* FIXME: send some error message */
943 return -ENOMEM;
944 }
945 trans->sms.cp_state = GSM411_CPS_IDLE;
946 trans->sms.rp_state = GSM411_RPS_IDLE;
947 trans->sms.is_mt = 0;
Harald Welte (local)daef6062009-08-14 11:41:12 +0200948 trans->sms.link_id = link_id;
Harald Weltef3efc592009-07-27 20:11:35 +0200949
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +0100950 trans->conn = &lchan->conn;
951 use_subscr_con(trans->conn);
Harald Weltef3efc592009-07-27 20:11:35 +0200952 }
953
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000954 switch(msg_type) {
955 case GSM411_MT_CP_DATA:
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200956 DEBUGPC(DSMS, "RX SMS CP-DATA\n");
Sylvain Munaut258e2f92009-12-24 16:47:08 +0100957
958 /* 5.4: For MO, if a CP-DATA is received for a new
959 * transaction, equals reception of an implicit
960 * last CP-ACK for previous transaction */
961 if (trans->sms.cp_state == GSM411_CPS_IDLE) {
962 int i;
963 struct gsm_trans *ptrans;
964
965 /* Scan through all remote initiated transactions */
966 for (i=8; i<15; i++) {
967 if (i == transaction_id)
968 continue;
969
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100970 ptrans = trans_find_by_id(lchan->conn.subscr,
Sylvain Munaut258e2f92009-12-24 16:47:08 +0100971 GSM48_PDISC_SMS, i);
972 if (!ptrans)
973 continue;
974
975 DEBUGP(DSMS, "Implicit CP-ACK for trans_id=%x\n", i);
976
977 /* Finish it for good */
978 bsc_del_timer(&ptrans->sms.cp_timer);
979 ptrans->sms.cp_state = GSM411_CPS_IDLE;
980 trans_free(ptrans);
981 }
982 }
983
Harald Weltecb8f4432009-08-09 14:59:02 +0200984 /* 5.2.3.1.3: MO state exists when SMC has received
985 * CP-DATA, including sending of the assoc. CP-ACK */
986 /* 5.2.3.2.4: MT state exists when SMC has received
987 * CP-DATA, including sending of the assoc. CP-ACK */
988 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Weltef3efc592009-07-27 20:11:35 +0200989
Harald Welte (local)daef6062009-08-14 11:41:12 +0200990 /* SMC instance acknowledges the CP-DATA frame */
991 gsm411_tx_cp_ack(trans);
992
Harald Weltef3efc592009-07-27 20:11:35 +0200993 rc = gsm411_rx_cp_data(msg, gh, trans);
Harald Welte (local)daef6062009-08-14 11:41:12 +0200994#if 0
Harald Weltef3efc592009-07-27 20:11:35 +0200995 /* Send CP-ACK or CP-ERORR in response */
996 if (rc < 0) {
997 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_NET_FAIL);
998 } else
999 rc = gsm411_tx_cp_ack(trans);
Harald Welte (local)daef6062009-08-14 11:41:12 +02001000#endif
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001001 break;
1002 case GSM411_MT_CP_ACK:
Harald Weltef3efc592009-07-27 20:11:35 +02001003 /* previous CP-DATA in this transaction was confirmed */
Harald Welte (local)c89a5112009-08-14 10:42:43 +02001004 DEBUGPC(DSMS, "RX SMS CP-ACK\n");
Harald Weltecb8f4432009-08-09 14:59:02 +02001005 /* 5.2.3.1.3: MO state exists when SMC has received CP-ACK */
1006 /* 5.2.3.2.4: MT state exists when SMC has received CP-ACK */
1007 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Welte41985612009-08-10 00:24:32 +02001008 /* Stop TC1* after CP-ACK has been received */
1009 bsc_del_timer(&trans->sms.cp_timer);
Harald Weltecb8f4432009-08-09 14:59:02 +02001010
Harald Weltef3efc592009-07-27 20:11:35 +02001011 if (!trans->sms.is_mt) {
Harald Weltef3efc592009-07-27 20:11:35 +02001012 /* FIXME: we have sont one CP-DATA, which was now
1013 * acknowledged. Check if we want to transfer more,
1014 * i.e. multi-part message */
1015 trans->sms.cp_state = GSM411_CPS_IDLE;
1016 trans_free(trans);
1017 }
Daniel Willmannbb16e8e2008-12-29 03:53:50 +00001018 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001019 case GSM411_MT_CP_ERROR:
Harald Welte (local)c89a5112009-08-14 10:42:43 +02001020 DEBUGPC(DSMS, "RX SMS CP-ERROR, cause %d (%s)\n", gh->data[0],
1021 get_value_string(cp_cause_strs, gh->data[0]));
Harald Welte41985612009-08-10 00:24:32 +02001022 bsc_del_timer(&trans->sms.cp_timer);
Harald Weltef3efc592009-07-27 20:11:35 +02001023 trans->sms.cp_state = GSM411_CPS_IDLE;
1024 trans_free(trans);
Daniel Willmannbb16e8e2008-12-29 03:53:50 +00001025 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001026 default:
Harald Welte (local)c89a5112009-08-14 10:42:43 +02001027 DEBUGPC(DSMS, "RX Unimplemented CP msg_type: 0x%02x\n", msg_type);
Harald Weltef3efc592009-07-27 20:11:35 +02001028 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
Harald Weltecb8f4432009-08-09 14:59:02 +02001029 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Weltef3efc592009-07-27 20:11:35 +02001030 trans_free(trans);
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001031 break;
1032 }
1033
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001034 return rc;
1035}
1036
Harald Welte8c2e36e2008-12-30 15:00:14 +00001037#if 0
Daniel Willmann3b3f0012008-12-30 13:56:46 +00001038/* Test TPDU - ALL YOUR */
1039static u_int8_t tpdu_test[] = {
1040 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
1041 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
1042 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
1043 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
Daniel Willmanne2a728d2008-12-30 14:03:09 +00001044};
Harald Welte8c2e36e2008-12-30 15:00:14 +00001045#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001046
Harald Weltecf6a3812009-08-09 19:07:41 +02001047/* Take a SMS in gsm_sms structure and send it through an already
1048 * existing lchan. We also assume that the caller ensured this lchan already
1049 * has a SAPI3 RLL connection! */
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001050int gsm411_send_sms_lchan(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001051{
1052 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltef3efc592009-07-27 20:11:35 +02001053 struct gsm_trans *trans;
Harald Welte76042182009-08-08 16:03:15 +02001054 u_int8_t *data, *rp_ud_len;
Harald Welte87f5d632009-07-04 17:39:00 +02001055 u_int8_t msg_ref = 42;
Sylvain Munautc4052cf2009-12-24 13:27:36 +01001056 int transaction_id;
Harald Welte76042182009-08-08 16:03:15 +02001057 int rc;
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001058
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001059 transaction_id = trans_assign_trans_id(conn->subscr, GSM48_PDISC_SMS, 0);
Harald Welte49839212009-12-22 13:45:58 +01001060 if (transaction_id == -1) {
Harald Welted0cf7ba2009-12-24 15:08:18 +01001061 LOGP(DSMS, LOGL_ERROR, "No available transaction ids\n");
Harald Welte49839212009-12-22 13:45:58 +01001062 return -EBUSY;
1063 }
Harald Weltecf6a3812009-08-09 19:07:41 +02001064
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001065 msg->lchan = conn->lchan;
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001066
Harald Welte76042182009-08-08 16:03:15 +02001067 DEBUGP(DSMS, "send_sms_lchan()\n");
Harald Weltef3efc592009-07-27 20:11:35 +02001068
Harald Welte76042182009-08-08 16:03:15 +02001069 /* FIXME: allocate transaction with message reference */
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001070 trans = trans_alloc(conn->subscr, GSM48_PDISC_SMS,
Harald Welte76042182009-08-08 16:03:15 +02001071 transaction_id, new_callref++);
1072 if (!trans) {
Harald Welted0cf7ba2009-12-24 15:08:18 +01001073 LOGP(DSMS, LOGL_ERROR, "No memory for trans\n");
Harald Welte76042182009-08-08 16:03:15 +02001074 /* FIXME: send some error message */
1075 return -ENOMEM;
1076 }
1077 trans->sms.cp_state = GSM411_CPS_IDLE;
1078 trans->sms.rp_state = GSM411_RPS_IDLE;
1079 trans->sms.is_mt = 1;
1080 trans->sms.sms = sms;
Harald Welte (local)daef6062009-08-14 11:41:12 +02001081 trans->sms.link_id = UM_SAPI_SMS; /* FIXME: main or SACCH ? */
Harald Welte76042182009-08-08 16:03:15 +02001082
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001083 trans->conn = conn;
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +01001084 use_subscr_con(trans->conn);
Harald Welte76042182009-08-08 16:03:15 +02001085
1086 /* Hardcode SMSC Originating Address for now */
Daniel Willmanna3e29842008-12-29 16:03:54 +00001087 data = (u_int8_t *)msgb_put(msg, 8);
Harald Welte87f5d632009-07-04 17:39:00 +02001088 data[0] = 0x07; /* originator length == 7 */
Harald Welteb9c758b2009-07-05 14:02:46 +02001089 data[1] = 0x91; /* type of number: international, ISDN */
1090 data[2] = 0x44; /* 447785016005 */
Daniel Willmanna3e29842008-12-29 16:03:54 +00001091 data[3] = 0x77;
1092 data[4] = 0x58;
1093 data[5] = 0x10;
1094 data[6] = 0x06;
1095 data[7] = 0x50;
Harald Welte87f5d632009-07-04 17:39:00 +02001096
1097 /* Hardcoded Destination Address */
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001098 data = (u_int8_t *)msgb_put(msg, 1);
Harald Welte87f5d632009-07-04 17:39:00 +02001099 data[0] = 0; /* destination length == 0 */
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001100
Harald Welte76042182009-08-08 16:03:15 +02001101 /* obtain a pointer for the rp_ud_len, so we can fill it later */
1102 rp_ud_len = (u_int8_t *)msgb_put(msg, 1);
Daniel Willmann4a1e8792008-12-29 06:23:56 +00001103
Harald Welte76042182009-08-08 16:03:15 +02001104#if 1
1105 /* generate the 03.40 TPDU */
1106 rc = gsm340_gen_tpdu(msg, sms);
1107 if (rc < 0) {
1108 msgb_free(msg);
1109 return rc;
1110 }
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001111
Harald Welte76042182009-08-08 16:03:15 +02001112 *rp_ud_len = rc;
1113#else
1114 data = msgb_put(msg, sizeof(tpdu_test));
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001115 memcpy(data, tpdu_test, sizeof(tpdu_test));
Harald Welte76042182009-08-08 16:03:15 +02001116 *rp_ud_len = sizeof(tpdu_test);
1117#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001118
Harald Welte76042182009-08-08 16:03:15 +02001119 DEBUGP(DSMS, "TX: SMS DELIVER\n");
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001120
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001121 counter_inc(conn->lchan->ts->trx->bts->network->stats.sms.delivered);
Harald Welte24ff6ee2009-12-22 00:41:05 +01001122
Harald Weltef3efc592009-07-27 20:11:35 +02001123 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
1124 /* FIXME: enter 'wait for RP-ACK' state, start TR1N */
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001125}
Harald Weltef3efc592009-07-27 20:11:35 +02001126
Harald Weltecf6a3812009-08-09 19:07:41 +02001127/* RLL SAPI3 establish callback. Now we have a RLL connection and
1128 * can deliver the actual message */
Harald Weltecb8f4432009-08-09 14:59:02 +02001129static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
1130 void *_sms, enum bsc_rllr_ind type)
1131{
1132 struct gsm_sms *sms = _sms;
1133
1134 DEBUGP(DSMS, "rll_ind_cb(lchan=%p, link_id=%u, sms=%p, type=%u\n",
1135 lchan, link_id, sms, type);
1136
1137 switch (type) {
1138 case BSC_RLLR_IND_EST_CONF:
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001139#warning "BROKEN: The BSC will establish this transparently"
1140 gsm411_send_sms_lchan(&lchan->conn, sms);
Harald Weltecb8f4432009-08-09 14:59:02 +02001141 break;
1142 case BSC_RLLR_IND_REL_IND:
1143 case BSC_RLLR_IND_ERR_IND:
1144 case BSC_RLLR_IND_TIMEOUT:
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001145#warning "BROKEN: We will need to handle SAPI n Reject"
Harald Weltecb8f4432009-08-09 14:59:02 +02001146 sms_free(sms);
1147 break;
1148 }
1149}
1150
Harald Weltecf6a3812009-08-09 19:07:41 +02001151/* paging callback. Here we get called if paging a subscriber has
1152 * succeeded or failed. */
Harald Welte76042182009-08-08 16:03:15 +02001153static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
1154 struct msgb *msg, void *_lchan, void *_sms)
Harald Weltef3efc592009-07-27 20:11:35 +02001155{
Harald Welte76042182009-08-08 16:03:15 +02001156 struct gsm_lchan *lchan = _lchan;
1157 struct gsm_sms *sms = _sms;
1158 int rc;
Harald Weltef3efc592009-07-27 20:11:35 +02001159
Harald Welte76042182009-08-08 16:03:15 +02001160 DEBUGP(DSMS, "paging_cb_send_sms(hooknum=%u, event=%u, msg=%p,"
1161 "lchan=%p, sms=%p)\n", hooknum, event, msg, lchan, sms);
1162
1163 if (hooknum != GSM_HOOK_RR_PAGING)
1164 return -EINVAL;
1165
1166 switch (event) {
1167 case GSM_PAGING_SUCCEEDED:
1168 /* Paging aborted without lchan ?!? */
1169 if (!lchan) {
1170 sms_free(sms);
1171 rc = -EIO;
1172 break;
1173 }
Harald Weltecf6a3812009-08-09 19:07:41 +02001174 /* Establish a SAPI3 RLL connection for SMS */
Harald Weltecb8f4432009-08-09 14:59:02 +02001175 rc = rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
Harald Welte76042182009-08-08 16:03:15 +02001176 break;
1177 case GSM_PAGING_EXPIRED:
1178 sms_free(sms);
1179 rc = -ETIMEDOUT;
1180 break;
1181 default:
1182 rc = -EINVAL;
1183 break;
1184 }
1185
1186 return rc;
1187}
1188
Harald Weltecf6a3812009-08-09 19:07:41 +02001189/* high-level function to send a SMS to a given subscriber. The function
1190 * will take care of paging the subscriber, establishing the RLL SAPI3
1191 * connection, etc. */
Harald Welte76042182009-08-08 16:03:15 +02001192int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
1193 struct gsm_sms *sms)
1194{
Harald Weltecf6a3812009-08-09 19:07:41 +02001195 struct gsm_lchan *lchan;
Harald Weltee903edf2009-08-15 03:16:17 +02001196 int rc;
Harald Weltecf6a3812009-08-09 19:07:41 +02001197
Harald Welte76042182009-08-08 16:03:15 +02001198 /* check if we already have an open lchan to the subscriber.
1199 * if yes, send the SMS this way */
Harald Weltecf6a3812009-08-09 19:07:41 +02001200 lchan = lchan_for_subscr(subscr);
1201 if (lchan)
1202 return rll_establish(lchan, UM_SAPI_SMS,
1203 rll_ind_cb, sms);
Harald Welte76042182009-08-08 16:03:15 +02001204
1205 /* if not, we have to start paging */
Harald Weltee903edf2009-08-15 03:16:17 +02001206 rc = paging_request(subscr->net, subscr, RSL_CHANNEED_SDCCH,
1207 paging_cb_send_sms, sms);
Harald Welte (local)0abaf332009-08-15 11:25:45 +02001208 if (rc <= 0)
Harald Weltee903edf2009-08-15 03:16:17 +02001209 sms_free(sms);
Harald Welte76042182009-08-08 16:03:15 +02001210
1211 return 0;
1212}
Harald Welte3366a942009-07-28 00:44:49 +02001213
Harald Weltecf6a3812009-08-09 19:07:41 +02001214static int subscr_sig_cb(unsigned int subsys, unsigned int signal,
1215 void *handler_data, void *signal_data)
1216{
1217 struct gsm_subscriber *subscr;
1218 struct gsm_lchan *lchan;
1219 struct gsm_sms *sms;
1220
1221 switch (signal) {
1222 case S_SUBSCR_ATTACHED:
1223 /* A subscriber has attached. Check if there are
1224 * any pending SMS for him to be delivered */
1225 subscr = signal_data;
1226 lchan = lchan_for_subscr(subscr);
1227 if (!lchan)
1228 break;
1229 sms = db_sms_get_unsent_for_subscr(subscr);
1230 if (!sms)
1231 break;
1232 /* Establish a SAPI3 RLL connection for SMS */
1233 rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
1234 break;
1235 default:
1236 break;
1237 }
1238 return 0;
1239}
1240
Harald Welte (local)86b17172009-08-14 14:52:17 +02001241void _gsm411_sms_trans_free(struct gsm_trans *trans)
1242{
1243 bsc_del_timer(&trans->sms.cp_timer);
1244}
1245
Harald Welte7bfc2672009-07-28 00:41:45 +02001246static __attribute__((constructor)) void on_dso_load_sms(void)
1247{
Harald Weltecf6a3812009-08-09 19:07:41 +02001248 register_signal_handler(SS_SUBSCR, subscr_sig_cb, NULL);
Harald Welte7bfc2672009-07-28 00:41:45 +02001249}