blob: f84463c6fd9a60d75dadebd97d0ad1db8ce3c295 [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>
Holger Hans Peter Freythercbac76e2010-05-23 21:05:18 +080051#include <openbsc/bsc_api.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000052
Daniel Willmann471712b2008-12-29 01:54:02 +000053#define GSM411_ALLOC_SIZE 1024
54#define GSM411_ALLOC_HEADROOM 128
55
Harald Weltecb8f4432009-08-09 14:59:02 +020056#define UM_SAPI_SMS 3 /* See GSM 04.05/04.06 */
57
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020058void *tall_gsms_ctx;
Harald Weltef3efc592009-07-27 20:11:35 +020059static u_int32_t new_callref = 0x40000001;
60
Harald Welte (local)c89a5112009-08-14 10:42:43 +020061static const struct value_string cp_cause_strs[] = {
62 { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
63 { GSM411_CP_CAUSE_CONGESTION, "Congestion" },
64 { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
65 { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
66 { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
67 { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +020068 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
Harald Welte (local)c89a5112009-08-14 10:42:43 +020069 "Message incompatible with protocol state" },
70 { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
71 { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
72 { 0, 0 }
73};
74
75static const struct value_string rp_cause_strs[] = {
76 { GSM411_RP_CAUSE_MO_NUM_UNASSIGNED, "(MO) Number not assigned" },
77 { GSM411_RP_CAUSE_MO_OP_DET_BARR, "(MO) Operator determined barring" },
78 { GSM411_RP_CAUSE_MO_CALL_BARRED, "(MO) Call barred" },
79 { GSM411_RP_CAUSE_MO_SMS_REJECTED, "(MO) SMS rejected" },
80 { GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER, "(MO) Destination out of order" },
81 { GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR, "(MO) Unidentified subscriber" },
82 { GSM411_RP_CAUSE_MO_FACILITY_REJ, "(MO) Facility reject" },
83 { GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR, "(MO) Unknown subscriber" },
84 { GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER, "(MO) Network out of order" },
85 { GSM411_RP_CAUSE_MO_TEMP_FAIL, "(MO) Temporary failure" },
86 { GSM411_RP_CAUSE_MO_CONGESTION, "(MO) Congestion" },
87 { GSM411_RP_CAUSE_MO_RES_UNAVAIL, "(MO) Resource unavailable" },
88 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR, "(MO) Requested facility not subscribed" },
89 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL, "(MO) Requested facility not implemented" },
90 { GSM411_RP_CAUSE_MO_INTERWORKING, "(MO) Interworking" },
91 /* valid only for MT */
92 { GSM411_RP_CAUSE_MT_MEM_EXCEEDED, "(MT) Memory Exceeded" },
93 /* valid for both directions */
94 { GSM411_RP_CAUSE_INV_TRANS_REF, "Invalid Transaction Reference" },
95 { GSM411_RP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
96 { GSM411_RP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
97 { GSM411_RP_CAUSE_MSGTYPE_NOTEXIST, "Message Type non-existant" },
98 { GSM411_RP_CAUSE_MSG_INCOMP_STATE, "Message incompatible with protocol state" },
99 { GSM411_RP_CAUSE_IE_NOTEXIST, "Information Element not existing" },
100 { GSM411_RP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
101 { 0, NULL }
102};
103
Harald Welte76042182009-08-08 16:03:15 +0200104struct gsm_sms *sms_alloc(void)
105{
106 return talloc_zero(tall_gsms_ctx, struct gsm_sms);
107}
108
109void sms_free(struct gsm_sms *sms)
110{
111 /* drop references to subscriber structure */
112 if (sms->sender)
113 subscr_put(sms->sender);
114 if (sms->receiver)
115 subscr_put(sms->receiver);
116
117 talloc_free(sms);
118}
119
Holger Freythera553d092009-01-04 20:16:25 +0000120struct msgb *gsm411_msgb_alloc(void)
Daniel Willmann471712b2008-12-29 01:54:02 +0000121{
Harald Welte966636f2009-06-26 19:39:35 +0200122 return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
123 "GSM 04.11");
Daniel Willmann471712b2008-12-29 01:54:02 +0000124}
125
Holger Hans Peter Freytherec32b582010-03-23 07:40:46 +0100126static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *msg, u_int8_t link_id)
Daniel Willmann471712b2008-12-29 01:54:02 +0000127{
Harald Welte76042182009-08-08 16:03:15 +0200128 DEBUGP(DSMS, "GSM4.11 TX %s\n", hexdump(msg->data, msg->len));
Holger Hans Peter Freytherec32b582010-03-23 07:40:46 +0100129 msg->l3h = msg->data;
130 return gsm0808_submit_dtap(conn, msg, link_id);
Daniel Willmann471712b2008-12-29 01:54:02 +0000131}
132
Harald Welte41985612009-08-10 00:24:32 +0200133/* SMC TC1* is expired */
134static void cp_timer_expired(void *data)
135{
136 struct gsm_trans *trans = data;
137
138 DEBUGP(DSMS, "SMC Timer TC1* is expired, calling trans_free()\n");
139 /* FIXME: we need to re-transmit the last CP-DATA 1..3 times */
140 trans_free(trans);
141}
142
Harald Welte87f5d632009-07-04 17:39:00 +0200143/* Prefix msg with a 04.08/04.11 CP header */
Harald Weltef3efc592009-07-27 20:11:35 +0200144static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
145 u_int8_t msg_type)
Harald Welte87f5d632009-07-04 17:39:00 +0200146{
147 struct gsm48_hdr *gh;
148
149 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
150 /* Outgoing needs the highest bit set */
Harald Weltef3efc592009-07-27 20:11:35 +0200151 gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
Harald Welte87f5d632009-07-04 17:39:00 +0200152 gh->msg_type = msg_type;
153
Harald Weltef3efc592009-07-27 20:11:35 +0200154 /* mobile originating */
155 switch (gh->msg_type) {
156 case GSM411_MT_CP_DATA:
157 /* 5.2.3.1.2: enter MO-wait for CP-ack */
Harald Weltecb8f4432009-08-09 14:59:02 +0200158 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
Harald Weltef3efc592009-07-27 20:11:35 +0200159 trans->sms.cp_state = GSM411_CPS_WAIT_CP_ACK;
Harald Welte41985612009-08-10 00:24:32 +0200160 trans->sms.cp_timer.data = trans;
161 trans->sms.cp_timer.cb = cp_timer_expired;
162 /* 5.3.2.1: Set Timer TC1A */
163 bsc_schedule_timer(&trans->sms.cp_timer, GSM411_TMR_TC1A);
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200164 DEBUGP(DSMS, "TX: CP-DATA ");
165 break;
166 case GSM411_MT_CP_ACK:
167 DEBUGP(DSMS, "TX: CP-ACK ");
168 break;
169 case GSM411_MT_CP_ERROR:
Sylvain Munaut1d9efd62009-12-18 18:28:07 +0100170 DEBUGP(DSMS, "TX: CP-ERROR ");
Harald Weltef3efc592009-07-27 20:11:35 +0200171 break;
172 }
173
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200174 DEBUGPC(DSMS, "trans=%x\n", trans->transaction_id);
175
Holger Hans Peter Freytherec32b582010-03-23 07:40:46 +0100176 return gsm411_sendmsg(trans->conn, msg, trans->sms.link_id);
Harald Welte87f5d632009-07-04 17:39:00 +0200177}
178
179/* Prefix msg with a RP-DATA header and send as CP-DATA */
Harald Weltef3efc592009-07-27 20:11:35 +0200180static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
181 u_int8_t rp_msg_type, u_int8_t rp_msg_ref)
Harald Welte87f5d632009-07-04 17:39:00 +0200182{
183 struct gsm411_rp_hdr *rp;
Harald Welte0d544e72009-08-10 00:22:19 +0200184 u_int8_t len = msg->len;
Harald Welte87f5d632009-07-04 17:39:00 +0200185
186 /* GSM 04.11 RP-DATA header */
187 rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
Harald Welte0d544e72009-08-10 00:22:19 +0200188 rp->len = len + 2;
Harald Welte87f5d632009-07-04 17:39:00 +0200189 rp->msg_type = rp_msg_type;
190 rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */
191
Harald Weltef3efc592009-07-27 20:11:35 +0200192 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA);
Harald Welte87f5d632009-07-04 17:39:00 +0200193}
194
Steffen Neubauerf3262672009-11-26 12:28:41 +0100195/* Turn int into semi-octet representation: 98 => 0x89 */
196static u_int8_t bcdify(u_int8_t value)
197{
198 u_int8_t ret;
Steffen Neubauer5727cf42009-11-11 23:02:07 +0900199
Steffen Neubauerf3262672009-11-26 12:28:41 +0100200 ret = value / 10;
201 ret |= (value % 10) << 4;
202
203 return ret;
204}
205
206/* Turn semi-octet representation into int: 0x89 => 98 */
207static u_int8_t unbcdify(u_int8_t value)
208{
209 u_int8_t ret;
210
211 if ((value & 0x0F) > 9 || (value >> 4) > 9)
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200212 LOGP(DSMS, LOGL_ERROR,
Harald Welted0cf7ba2009-12-24 15:08:18 +0100213 "unbcdify got too big nibble: 0x%02X\n", value);
Steffen Neubauerf3262672009-11-26 12:28:41 +0100214
215 ret = (value&0x0F)*10;
Steffen Neubauerad69d7f2009-11-26 23:38:41 +0100216 ret += value>>4;
Steffen Neubauerf3262672009-11-26 12:28:41 +0100217
218 return ret;
219}
220
221/* Generate 03.40 TP-SCTS */
222static void gsm340_gen_scts(u_int8_t *scts, time_t time)
223{
224 struct tm *tm = localtime(&time);
225
226 *scts++ = bcdify(tm->tm_year % 100);
227 *scts++ = bcdify(tm->tm_mon + 1);
228 *scts++ = bcdify(tm->tm_mday);
229 *scts++ = bcdify(tm->tm_hour);
230 *scts++ = bcdify(tm->tm_min);
231 *scts++ = bcdify(tm->tm_sec);
232 *scts++ = bcdify(tm->tm_gmtoff/(60*15));
233}
234
235/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */
236static time_t gsm340_scts(u_int8_t *scts)
237{
238 struct tm tm;
239
240 u_int8_t yr = unbcdify(*scts++);
241
242 if (yr <= 80)
243 tm.tm_year = 100 + yr;
244 else
245 tm.tm_year = yr;
246 tm.tm_mon = unbcdify(*scts++) - 1;
247 tm.tm_mday = unbcdify(*scts++);
248 tm.tm_hour = unbcdify(*scts++);
249 tm.tm_min = unbcdify(*scts++);
250 tm.tm_sec = unbcdify(*scts++);
251 /* according to gsm 03.40 time zone is
252 "expressed in quarters of an hour" */
253 tm.tm_gmtoff = unbcdify(*scts++) * 15*60;
254
255 return mktime(&tm);
256}
257
258/* Return the default validity period in minutes */
259static unsigned long gsm340_vp_default(void)
260{
261 unsigned long minutes;
262 /* Default validity: two days */
263 minutes = 24 * 60 * 2;
264 return minutes;
265}
266
267/* Decode validity period format 'relative' */
268static unsigned long gsm340_vp_relative(u_int8_t *sms_vp)
269{
270 /* Chapter 9.2.3.12.1 */
271 u_int8_t vp;
272 unsigned long minutes;
273
274 vp = *(sms_vp);
275 if (vp <= 143)
276 minutes = vp + 1 * 5;
277 else if (vp <= 167)
278 minutes = 12*60 + (vp-143) * 30;
279 else if (vp <= 196)
280 minutes = vp-166 * 60 * 24;
281 else
282 minutes = vp-192 * 60 * 24 * 7;
283 return minutes;
284}
285
286/* Decode validity period format 'absolute' */
287static unsigned long gsm340_vp_absolute(u_int8_t *sms_vp)
288{
289 /* Chapter 9.2.3.12.2 */
290 time_t expires, now;
291 unsigned long minutes;
292
293 expires = gsm340_scts(sms_vp);
294 now = mktime(gmtime(NULL));
295 if (expires <= now)
296 minutes = 0;
297 else
298 minutes = (expires-now)/60;
299 return minutes;
300}
301
302/* Decode validity period format 'relative in integer representation' */
303static unsigned long gsm340_vp_relative_integer(u_int8_t *sms_vp)
Harald Welte7e310b12009-03-30 20:56:32 +0000304{
305 u_int8_t vp;
306 unsigned long minutes;
Steffen Neubauerf3262672009-11-26 12:28:41 +0100307 vp = *(sms_vp);
308 if (vp == 0) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100309 LOGP(DSMS, LOGL_ERROR,
310 "reserved relative_integer validity period\n");
Steffen Neubauerf3262672009-11-26 12:28:41 +0100311 return gsm340_vp_default();
312 }
313 minutes = vp/60;
314 return minutes;
315}
316
317/* Decode validity period format 'relative in semi-octet representation' */
318static unsigned long gsm340_vp_relative_semioctet(u_int8_t *sms_vp)
319{
320 unsigned long minutes;
321 minutes = unbcdify(*sms_vp++)*60; /* hours */
322 minutes += unbcdify(*sms_vp++); /* minutes */
323 minutes += unbcdify(*sms_vp++)/60; /* seconds */
324 return minutes;
325}
326
327/* decode validity period. return minutes */
328static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp)
329{
330 u_int8_t fi; /* functionality indicator */
Harald Welte7e310b12009-03-30 20:56:32 +0000331
Harald Welte76042182009-08-08 16:03:15 +0200332 switch (sms_vpf) {
Harald Welte7e310b12009-03-30 20:56:32 +0000333 case GSM340_TP_VPF_RELATIVE:
Steffen Neubauerf3262672009-11-26 12:28:41 +0100334 return gsm340_vp_relative(sms_vp);
Harald Welte7e310b12009-03-30 20:56:32 +0000335 case GSM340_TP_VPF_ABSOLUTE:
Steffen Neubauerf3262672009-11-26 12:28:41 +0100336 return gsm340_vp_absolute(sms_vp);
Harald Welte7e310b12009-03-30 20:56:32 +0000337 case GSM340_TP_VPF_ENHANCED:
338 /* Chapter 9.2.3.12.3 */
Steffen Neubauerf3262672009-11-26 12:28:41 +0100339 fi = *sms_vp++;
340 /* ignore additional fi */
341 if (fi & (1<<7)) sms_vp++;
342 /* read validity period format */
343 switch (fi & 0b111) {
344 case 0b000:
345 return gsm340_vp_default(); /* no vpf specified */
346 case 0b001:
347 return gsm340_vp_relative(sms_vp);
348 case 0b010:
349 return gsm340_vp_relative_integer(sms_vp);
350 case 0b011:
351 return gsm340_vp_relative_semioctet(sms_vp);
352 default:
353 /* The GSM spec says that the SC should reject any
354 unsupported and/or undefined values. FIXME */
Harald Welted0cf7ba2009-12-24 15:08:18 +0100355 LOGP(DSMS, LOGL_ERROR,
356 "Reserved enhanced validity period format\n");
Steffen Neubauerf3262672009-11-26 12:28:41 +0100357 return gsm340_vp_default();
358 }
Daniel Willmann58c83d82009-08-13 03:40:49 +0200359 case GSM340_TP_VPF_NONE:
Steffen Neubauerf3262672009-11-26 12:28:41 +0100360 default:
361 return gsm340_vp_default();
Harald Welte7e310b12009-03-30 20:56:32 +0000362 }
Harald Welte7e310b12009-03-30 20:56:32 +0000363}
364
365/* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */
366enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
367{
368 u_int8_t cgbits = dcs >> 4;
369 enum sms_alphabet alpha = DCS_NONE;
370
371 if ((cgbits & 0xc) == 0) {
372 if (cgbits & 2)
Harald Welted0cf7ba2009-12-24 15:08:18 +0100373 LOGP(DSMS, LOGL_NOTICE,
374 "Compressed SMS not supported yet\n");
Harald Welte7e310b12009-03-30 20:56:32 +0000375
Daniel Willmannd5d5e1d2009-08-15 03:01:17 +0200376 switch ((dcs >> 2)&0x03) {
Harald Welte7e310b12009-03-30 20:56:32 +0000377 case 0:
378 alpha = DCS_7BIT_DEFAULT;
379 break;
380 case 1:
381 alpha = DCS_8BIT_DATA;
382 break;
383 case 2:
384 alpha = DCS_UCS2;
385 break;
386 }
387 } else if (cgbits == 0xc || cgbits == 0xd)
388 alpha = DCS_7BIT_DEFAULT;
389 else if (cgbits == 0xe)
390 alpha = DCS_UCS2;
391 else if (cgbits == 0xf) {
392 if (dcs & 4)
393 alpha = DCS_8BIT_DATA;
394 else
395 alpha = DCS_7BIT_DEFAULT;
396 }
397
398 return alpha;
399}
400
Harald Welte76042182009-08-08 16:03:15 +0200401static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms)
Harald Welte7e310b12009-03-30 20:56:32 +0000402{
403 if (db_sms_store(gsms) != 0) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100404 LOGP(DSMS, LOGL_ERROR, "Failed to store SMS in Database\n");
Harald Welteb9c758b2009-07-05 14:02:46 +0200405 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000406 }
Harald Welte76042182009-08-08 16:03:15 +0200407 /* dispatch a signal to tell higher level about it */
408 dispatch_signal(SS_SMS, S_SMS_SUBMITTED, gsms);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200409 /* try delivering the SMS right now */
410 //gsm411_send_sms_subscr(gsms->receiver, gsms);
411
Harald Welte7e310b12009-03-30 20:56:32 +0000412 return 0;
413}
414
Harald Welte76042182009-08-08 16:03:15 +0200415/* generate a TPDU address field compliant with 03.40 sec. 9.1.2.5 */
416static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len,
417 struct gsm_subscriber *subscr)
Harald Weltef3efc592009-07-27 20:11:35 +0200418{
Harald Welte76042182009-08-08 16:03:15 +0200419 int len_in_bytes;
Harald Weltef3efc592009-07-27 20:11:35 +0200420
Harald Welte76042182009-08-08 16:03:15 +0200421 oa[1] = 0xb9; /* networks-specific number, private numbering plan */
422
Harald Welte55c8f352010-03-07 23:40:35 +0100423 len_in_bytes = gsm48_encode_bcd_number(oa, oa_len, 1, subscr->extension);
Harald Welte76042182009-08-08 16:03:15 +0200424
425 /* GSM 03.40 tells us the length is in 'useful semi-octets' */
426 oa[0] = strlen(subscr->extension) & 0xff;
427
428 return len_in_bytes;
Harald Weltef3efc592009-07-27 20:11:35 +0200429}
430
Harald Welte76042182009-08-08 16:03:15 +0200431/* generate a msgb containing a TPDU derived from struct gsm_sms,
432 * returns total size of TPDU */
433static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
Harald Weltef3efc592009-07-27 20:11:35 +0200434{
Harald Weltef3efc592009-07-27 20:11:35 +0200435 u_int8_t *smsp;
436 u_int8_t oa[12]; /* max len per 03.40 */
437 u_int8_t oa_len = 0;
Daniel Willmann9aef1452009-08-13 03:39:07 +0200438 u_int8_t octet_len;
Harald Welte76042182009-08-08 16:03:15 +0200439 unsigned int old_msg_len = msg->len;
Harald Weltef3efc592009-07-27 20:11:35 +0200440
441 /* generate first octet with masked bits */
442 smsp = msgb_put(msg, 1);
Harald Welte76042182009-08-08 16:03:15 +0200443 /* TP-MTI (message type indicator) */
Harald Weltef3efc592009-07-27 20:11:35 +0200444 *smsp = GSM340_SMS_DELIVER_SC2MS;
Harald Welte76042182009-08-08 16:03:15 +0200445 /* TP-MMS (more messages to send) */
446 if (0 /* FIXME */)
Harald Weltef3efc592009-07-27 20:11:35 +0200447 *smsp |= 0x04;
Harald Welte76042182009-08-08 16:03:15 +0200448 /* TP-SRI(deliver)/SRR(submit) */
Harald Weltef3efc592009-07-27 20:11:35 +0200449 if (sms->status_rep_req)
450 *smsp |= 0x20;
Harald Welte76042182009-08-08 16:03:15 +0200451 /* TP-UDHI (indicating TP-UD contains a header) */
452 if (sms->ud_hdr_ind)
Harald Weltef3efc592009-07-27 20:11:35 +0200453 *smsp |= 0x40;
Harald Welte76042182009-08-08 16:03:15 +0200454#if 0
455 /* TP-RP (indicating that a reply path exists) */
Harald Weltef3efc592009-07-27 20:11:35 +0200456 if (sms->
457 *smsp |= 0x80;
458#endif
459
460 /* generate originator address */
Harald Welte76042182009-08-08 16:03:15 +0200461 oa_len = gsm340_gen_oa(oa, sizeof(oa), sms->sender);
Harald Weltef3efc592009-07-27 20:11:35 +0200462 smsp = msgb_put(msg, oa_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200463 memcpy(smsp, oa, oa_len);
464
465 /* generate TP-PID */
466 smsp = msgb_put(msg, 1);
467 *smsp = sms->protocol_id;
468
469 /* generate TP-DCS */
470 smsp = msgb_put(msg, 1);
471 *smsp = sms->data_coding_scheme;
472
473 /* generate TP-SCTS */
474 smsp = msgb_put(msg, 7);
475 gsm340_gen_scts(smsp, time(NULL));
Harald Welte76042182009-08-08 16:03:15 +0200476
Harald Weltef3efc592009-07-27 20:11:35 +0200477 /* generate TP-UDL */
478 smsp = msgb_put(msg, 1);
Harald Welte76042182009-08-08 16:03:15 +0200479 *smsp = sms->user_data_len;
Harald Weltef3efc592009-07-27 20:11:35 +0200480
481 /* generate TP-UD */
Daniel Willmann6b024cb2009-08-15 03:01:46 +0200482 switch (gsm338_get_sms_alphabet(sms->data_coding_scheme)) {
483 case DCS_7BIT_DEFAULT:
Daniel Willmann9aef1452009-08-13 03:39:07 +0200484 octet_len = sms->user_data_len*7/8;
485 if (sms->user_data_len*7%8 != 0)
486 octet_len++;
Daniel Willmann6b1e8222009-08-12 21:17:06 +0200487 /* Warning, user_data_len indicates the amount of septets
488 * (characters), we need amount of octets occupied */
Daniel Willmann9aef1452009-08-13 03:39:07 +0200489 smsp = msgb_put(msg, octet_len);
490 memcpy(smsp, sms->user_data, octet_len);
Daniel Willmann6b024cb2009-08-15 03:01:46 +0200491 break;
492 case DCS_UCS2:
493 case DCS_8BIT_DATA:
494 smsp = msgb_put(msg, sms->user_data_len);
495 memcpy(smsp, sms->user_data, sms->user_data_len);
496 break;
497 default:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100498 LOGP(DSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: 0x%02X\n",
499 sms->data_coding_scheme);
Daniel Willmann6b024cb2009-08-15 03:01:46 +0200500 break;
Daniel Willmann6b1e8222009-08-12 21:17:06 +0200501 }
Harald Weltef3efc592009-07-27 20:11:35 +0200502
Harald Welte76042182009-08-08 16:03:15 +0200503 return msg->len - old_msg_len;
Harald Weltef3efc592009-07-27 20:11:35 +0200504}
505
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200506/* process an incoming TPDU (called from RP-DATA)
507 * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
Holger Hans Peter Freyther18b63f42010-03-23 07:52:17 +0100508static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *msg)
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000509{
510 u_int8_t *smsp = msgb_sms(msg);
Harald Welte7e310b12009-03-30 20:56:32 +0000511 struct gsm_sms *gsms;
Harald Welte76042182009-08-08 16:03:15 +0200512 u_int8_t sms_mti, sms_mms, sms_vpf, sms_alphabet, sms_rp;
513 u_int8_t *sms_vp;
Harald Welte7e310b12009-03-30 20:56:32 +0000514 u_int8_t da_len_bytes;
515 u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
516 int rc = 0;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000517
Holger Hans Peter Freyther18b63f42010-03-23 07:52:17 +0100518 counter_inc(conn->bts->network->stats.sms.submitted);
Harald Welte24ff6ee2009-12-22 00:41:05 +0100519
Harald Welte76042182009-08-08 16:03:15 +0200520 gsms = sms_alloc();
521 if (!gsms)
Harald Welteb9c758b2009-07-05 14:02:46 +0200522 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000523
524 /* invert those fields where 0 means active/present */
Harald Welte76042182009-08-08 16:03:15 +0200525 sms_mti = *smsp & 0x03;
526 sms_mms = !!(*smsp & 0x04);
527 sms_vpf = (*smsp & 0x18) >> 3;
528 gsms->status_rep_req = (*smsp & 0x20);
529 gsms->ud_hdr_ind = (*smsp & 0x40);
530 sms_rp = (*smsp & 0x80);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000531
532 smsp++;
Harald Welte76042182009-08-08 16:03:15 +0200533 gsms->msg_ref = *smsp++;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000534
Harald Welte7e310b12009-03-30 20:56:32 +0000535 /* length in bytes of the destination address */
536 da_len_bytes = 2 + *smsp/2 + *smsp%2;
537 if (da_len_bytes > 12) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100538 LOGP(DSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n");
Harald Welteb9c758b2009-07-05 14:02:46 +0200539 rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
Harald Welte7e310b12009-03-30 20:56:32 +0000540 goto out;
541 }
Harald Welte3cfdb222009-06-12 02:42:11 +0800542 memset(address_lv, 0, sizeof(address_lv));
Harald Welte7e310b12009-03-30 20:56:32 +0000543 memcpy(address_lv, smsp, da_len_bytes);
544 /* mangle first byte to reflect length in bytes, not digits */
Harald Welte3cfdb222009-06-12 02:42:11 +0800545 address_lv[0] = da_len_bytes - 1;
Harald Welte7e310b12009-03-30 20:56:32 +0000546 /* convert to real number */
Harald Welte55c8f352010-03-07 23:40:35 +0100547 gsm48_decode_bcd_number(gsms->dest_addr, sizeof(gsms->dest_addr), address_lv, 1);
Harald Welte7e310b12009-03-30 20:56:32 +0000548 smsp += da_len_bytes;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000549
Harald Welte76042182009-08-08 16:03:15 +0200550 gsms->protocol_id = *smsp++;
551 gsms->data_coding_scheme = *smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000552
Harald Welte76042182009-08-08 16:03:15 +0200553 sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
Harald Welte7e310b12009-03-30 20:56:32 +0000554
Harald Welte76042182009-08-08 16:03:15 +0200555 switch (sms_vpf) {
Harald Welte7e310b12009-03-30 20:56:32 +0000556 case GSM340_TP_VPF_RELATIVE:
Harald Welte76042182009-08-08 16:03:15 +0200557 sms_vp = smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000558 break;
559 case GSM340_TP_VPF_ABSOLUTE:
560 case GSM340_TP_VPF_ENHANCED:
Harald Welte76042182009-08-08 16:03:15 +0200561 sms_vp = smsp;
Steffen Neubauerf3262672009-11-26 12:28:41 +0100562 /* the additional functionality indicator... */
Steffen Neubauerac0c13c2009-12-05 12:44:41 +0100563 if (sms_vpf == GSM340_TP_VPF_ENHANCED && *smsp & (1<<7))
564 smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000565 smsp += 7;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000566 break;
Daniel Willmann58c83d82009-08-13 03:40:49 +0200567 case GSM340_TP_VPF_NONE:
568 sms_vp = 0;
569 break;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000570 default:
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200571 LOGP(DSMS, LOGL_NOTICE,
Harald Welted0cf7ba2009-12-24 15:08:18 +0100572 "SMS Validity period not implemented: 0x%02x\n", sms_vpf);
Harald Welte76042182009-08-08 16:03:15 +0200573 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000574 }
Harald Welte76042182009-08-08 16:03:15 +0200575 gsms->user_data_len = *smsp++;
576 if (gsms->user_data_len) {
577 memcpy(gsms->user_data, smsp, gsms->user_data_len);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000578
Harald Welte76042182009-08-08 16:03:15 +0200579 switch (sms_alphabet) {
Harald Welte7e310b12009-03-30 20:56:32 +0000580 case DCS_7BIT_DEFAULT:
Harald Welte76042182009-08-08 16:03:15 +0200581 gsm_7bit_decode(gsms->text, smsp, gsms->user_data_len);
Harald Welte7e310b12009-03-30 20:56:32 +0000582 break;
583 case DCS_8BIT_DATA:
584 case DCS_UCS2:
585 case DCS_NONE:
Harald Welte7e310b12009-03-30 20:56:32 +0000586 break;
587 }
588 }
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000589
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100590 gsms->sender = subscr_get(msg->lchan->conn.subscr);
Harald Welted0cf7ba2009-12-24 15:08:18 +0100591
592 LOGP(DSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, "
593 "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, "
594 "UserDataLength: 0x%02x, UserData: \"%s\"\n",
595 subscr_name(gsms->sender), sms_mti, sms_vpf, gsms->msg_ref,
596 gsms->protocol_id, gsms->data_coding_scheme, gsms->dest_addr,
597 gsms->user_data_len,
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200598 sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
Harald Welte76042182009-08-08 16:03:15 +0200599 hexdump(gsms->user_data, gsms->user_data_len));
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000600
Harald Welte76042182009-08-08 16:03:15 +0200601 gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
Harald Welteb9c758b2009-07-05 14:02:46 +0200602
Harald Welte76042182009-08-08 16:03:15 +0200603 dispatch_signal(SS_SMS, 0, gsms);
Harald Welteb9c758b2009-07-05 14:02:46 +0200604
Harald Welte7e310b12009-03-30 20:56:32 +0000605 /* determine gsms->receiver based on dialled number */
Holger Hans Peter Freyther18b63f42010-03-23 07:52:17 +0100606 gsms->receiver = subscr_get_by_extension(conn->bts->network, gsms->dest_addr);
Harald Welte7e310b12009-03-30 20:56:32 +0000607 if (!gsms->receiver) {
608 rc = 1; /* cause 1: unknown subscriber */
Holger Hans Peter Freyther18b63f42010-03-23 07:52:17 +0100609 counter_inc(conn->bts->network->stats.sms.no_receiver);
Harald Welte7e310b12009-03-30 20:56:32 +0000610 goto out;
611 }
612
Harald Welte76042182009-08-08 16:03:15 +0200613 switch (sms_mti) {
Harald Welte7e310b12009-03-30 20:56:32 +0000614 case GSM340_SMS_SUBMIT_MS2SC:
615 /* MS is submitting a SMS */
Harald Welte76042182009-08-08 16:03:15 +0200616 rc = gsm340_rx_sms_submit(msg, gsms);
Harald Welte7e310b12009-03-30 20:56:32 +0000617 break;
618 case GSM340_SMS_COMMAND_MS2SC:
619 case GSM340_SMS_DELIVER_REP_MS2SC:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100620 LOGP(DSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200621 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000622 break;
623 default:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100624 LOGP(DSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200625 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000626 break;
627 }
628
Harald Welteb9c758b2009-07-05 14:02:46 +0200629 if (!rc && !gsms->receiver)
630 rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
631
Harald Welte7e310b12009-03-30 20:56:32 +0000632out:
Harald Welte76042182009-08-08 16:03:15 +0200633 sms_free(gsms);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000634
Harald Welte7e310b12009-03-30 20:56:32 +0000635 return rc;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000636}
637
Harald Weltef3efc592009-07-27 20:11:35 +0200638static int gsm411_send_rp_ack(struct gsm_trans *trans, u_int8_t msg_ref)
Daniel Willmann471712b2008-12-29 01:54:02 +0000639{
640 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000641
Daniel Willmann471712b2008-12-29 01:54:02 +0000642 DEBUGP(DSMS, "TX: SMS RP ACK\n");
643
Harald Weltef3efc592009-07-27 20:11:35 +0200644 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ACK_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000645}
646
Harald Weltef3efc592009-07-27 20:11:35 +0200647static int gsm411_send_rp_error(struct gsm_trans *trans,
648 u_int8_t msg_ref, u_int8_t cause)
Daniel Willmann471712b2008-12-29 01:54:02 +0000649{
650 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000651
Harald Welte7e310b12009-03-30 20:56:32 +0000652 msgb_tv_put(msg, 1, cause);
Daniel Willmann471712b2008-12-29 01:54:02 +0000653
Harald Welted0cf7ba2009-12-24 15:08:18 +0100654 LOGP(DSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200655 get_value_string(rp_cause_strs, cause));
Daniel Willmann471712b2008-12-29 01:54:02 +0000656
Harald Weltef3efc592009-07-27 20:11:35 +0200657 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000658}
659
Harald Welte7e310b12009-03-30 20:56:32 +0000660/* Receive a 04.11 TPDU inside RP-DATA / user data */
Harald Weltef3efc592009-07-27 20:11:35 +0200661static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
662 struct gsm411_rp_hdr *rph,
Harald Welte7e310b12009-03-30 20:56:32 +0000663 u_int8_t src_len, u_int8_t *src,
664 u_int8_t dst_len, u_int8_t *dst,
665 u_int8_t tpdu_len, u_int8_t *tpdu)
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000666{
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000667 int rc = 0;
668
Harald Welte7e310b12009-03-30 20:56:32 +0000669 if (src_len && src)
Harald Welted0cf7ba2009-12-24 15:08:18 +0100670 LOGP(DSMS, LOGL_ERROR, "RP-DATA (MO) with SRC ?!?\n");
Harald Welte7e310b12009-03-30 20:56:32 +0000671
672 if (!dst_len || !dst || !tpdu_len || !tpdu) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100673 LOGP(DSMS, LOGL_ERROR,
674 "RP-DATA (MO) without DST or TPDU ?!?\n");
Harald Weltef3efc592009-07-27 20:11:35 +0200675 gsm411_send_rp_error(trans, rph->msg_ref,
Harald Welteb9c758b2009-07-05 14:02:46 +0200676 GSM411_RP_CAUSE_INV_MAND_INF);
Harald Welte7e310b12009-03-30 20:56:32 +0000677 return -EIO;
678 }
Harald Weltee9dd9b02010-04-30 14:27:05 +0200679 msg->l4h = tpdu;
Harald Welte7e310b12009-03-30 20:56:32 +0000680
681 DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
Harald Welte7e310b12009-03-30 20:56:32 +0000682
Holger Hans Peter Freyther18b63f42010-03-23 07:52:17 +0100683 rc = gsm340_rx_tpdu(trans->conn, msg);
Harald Welte7e310b12009-03-30 20:56:32 +0000684 if (rc == 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200685 return gsm411_send_rp_ack(trans, rph->msg_ref);
Harald Welte7e310b12009-03-30 20:56:32 +0000686 else if (rc > 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200687 return gsm411_send_rp_error(trans, rph->msg_ref, rc);
Harald Welte7e310b12009-03-30 20:56:32 +0000688 else
689 return rc;
690}
691
692/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
Harald Weltef3efc592009-07-27 20:11:35 +0200693static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
694 struct gsm411_rp_hdr *rph)
Harald Welte7e310b12009-03-30 20:56:32 +0000695{
696 u_int8_t src_len, dst_len, rpud_len;
697 u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
698
699 /* in the MO case, this should always be zero length */
700 src_len = rph->data[0];
701 if (src_len)
702 src = &rph->data[1];
703
704 dst_len = rph->data[1+src_len];
705 if (dst_len)
706 dst = &rph->data[1+src_len+1];
707
708 rpud_len = rph->data[1+src_len+1+dst_len];
709 if (rpud_len)
710 rp_ud = &rph->data[1+src_len+1+dst_len+1];
711
Harald Welteb9c758b2009-07-05 14:02:46 +0200712 DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
713 src_len, dst_len, rpud_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200714 return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst,
Harald Welte7e310b12009-03-30 20:56:32 +0000715 rpud_len, rp_ud);
716}
717
Harald Weltecb8f4432009-08-09 14:59:02 +0200718/* Receive a 04.11 RP-ACK message (response to RP-DATA from us) */
Harald Weltef3efc592009-07-27 20:11:35 +0200719static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
720 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200721{
Harald Welte76042182009-08-08 16:03:15 +0200722 struct gsm_sms *sms = trans->sms.sms;
723
Harald Welteb9c758b2009-07-05 14:02:46 +0200724 /* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
725 * successfully received a SMS. We can now safely mark it as
726 * transmitted */
727
Harald Weltecb8f4432009-08-09 14:59:02 +0200728 if (!trans->sms.is_mt) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100729 LOGP(DSMS, LOGL_ERROR, "RX RP-ACK on a MO transfer ?\n");
Harald Weltecb8f4432009-08-09 14:59:02 +0200730 return gsm411_send_rp_error(trans, rph->msg_ref,
731 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
732 }
Harald Welte3e0f6172009-07-09 23:52:59 +0200733
Harald Welte76042182009-08-08 16:03:15 +0200734 if (!sms) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100735 LOGP(DSMS, LOGL_ERROR, "RX RP-ACK but no sms in transaction?!?\n");
Harald Weltecb8f4432009-08-09 14:59:02 +0200736 return gsm411_send_rp_error(trans, rph->msg_ref,
737 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte76042182009-08-08 16:03:15 +0200738 }
739
740 /* mark this SMS as sent in database */
741 db_sms_mark_sent(sms);
742
743 dispatch_signal(SS_SMS, S_SMS_DELIVERED, sms);
744
745 sms_free(sms);
746 trans->sms.sms = NULL;
747
Harald Weltecf6a3812009-08-09 19:07:41 +0200748 /* check for more messages for this subscriber */
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +0100749 assert(msg->lchan->conn.subscr == trans->subscr);
750
751 sms = db_sms_get_unsent_for_subscr(trans->subscr);
Harald Weltecf6a3812009-08-09 19:07:41 +0200752 if (sms)
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +0100753 gsm411_send_sms_lchan(trans->conn, sms);
Sylvain Munautd6c35f62009-12-24 13:33:51 +0100754
755 /* free the transaction here */
756 trans_free(trans);
Harald Welte76042182009-08-08 16:03:15 +0200757 return 0;
Harald Welteb9c758b2009-07-05 14:02:46 +0200758}
759
Harald Weltef3efc592009-07-27 20:11:35 +0200760static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
761 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200762{
Holger Hans Peter Freyther18b63f42010-03-23 07:52:17 +0100763 struct gsm_network *net = trans->conn->bts->network;
Harald Welte76042182009-08-08 16:03:15 +0200764 struct gsm_sms *sms = trans->sms.sms;
Harald Weltef3efc592009-07-27 20:11:35 +0200765 u_int8_t cause_len = rph->data[0];
766 u_int8_t cause = rph->data[1];
767
Harald Welteb9c758b2009-07-05 14:02:46 +0200768 /* Error in response to MT RP_DATA, i.e. the MS did not
769 * successfully receive the SMS. We need to investigate
770 * the cause and take action depending on it */
771
Harald Welted0cf7ba2009-12-24 15:08:18 +0100772 LOGP(DSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
Holger Hans Peter Freytherd4c16b12010-03-23 07:56:22 +0100773 subscr_name(trans->conn->subscr), cause_len, cause,
Harald Welted0cf7ba2009-12-24 15:08:18 +0100774 get_value_string(rp_cause_strs, cause));
Harald Weltef3efc592009-07-27 20:11:35 +0200775
Harald Weltecb8f4432009-08-09 14:59:02 +0200776 if (!trans->sms.is_mt) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100777 LOGP(DSMS, LOGL_ERROR, "RX RP-ERR on a MO transfer ?\n");
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200778#if 0
Harald Weltecb8f4432009-08-09 14:59:02 +0200779 return gsm411_send_rp_error(trans, rph->msg_ref,
780 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200781#endif
Harald Weltecb8f4432009-08-09 14:59:02 +0200782 }
Harald Welte3e0f6172009-07-09 23:52:59 +0200783
Harald Welte76042182009-08-08 16:03:15 +0200784 if (!sms) {
Harald Welted0cf7ba2009-12-24 15:08:18 +0100785 LOGP(DSMS, LOGL_ERROR,
786 "RX RP-ERR, but no sms in transaction?!?\n");
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200787 return -EINVAL;
788#if 0
Harald Weltecb8f4432009-08-09 14:59:02 +0200789 return gsm411_send_rp_error(trans, rph->msg_ref,
790 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200791#endif
Harald Weltecb8f4432009-08-09 14:59:02 +0200792 }
793
794 if (cause == GSM411_RP_CAUSE_MT_MEM_EXCEEDED) {
795 /* MS has not enough memory to store the message. We need
796 * to store this in our database and wati for a SMMA message */
797 /* FIXME */
798 dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr);
Harald Welteffa55a42009-12-22 19:07:32 +0100799 counter_inc(net->stats.sms.rp_err_mem);
Harald Welte24ff6ee2009-12-22 00:41:05 +0100800 } else
Harald Welteffa55a42009-12-22 19:07:32 +0100801 counter_inc(net->stats.sms.rp_err_other);
Harald Welte76042182009-08-08 16:03:15 +0200802
803 sms_free(sms);
804 trans->sms.sms = NULL;
805
Harald Welte (local)86b17172009-08-14 14:52:17 +0200806 //trans_free(trans);
Harald Welte76042182009-08-08 16:03:15 +0200807
Harald Weltef3efc592009-07-27 20:11:35 +0200808 return 0;
Harald Welteb9c758b2009-07-05 14:02:46 +0200809}
810
Harald Weltef3efc592009-07-27 20:11:35 +0200811static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans,
812 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200813{
Harald Weltecf6a3812009-08-09 19:07:41 +0200814 struct gsm_sms *sms;
Harald Weltef3efc592009-07-27 20:11:35 +0200815 int rc;
816
Harald Weltecf6a3812009-08-09 19:07:41 +0200817 rc = gsm411_send_rp_ack(trans, rph->msg_ref);
818 trans->sms.rp_state = GSM411_RPS_IDLE;
819
Harald Welteb9c758b2009-07-05 14:02:46 +0200820 /* MS tells us that it has memory for more SMS, we need
821 * to check if we have any pending messages for it and then
822 * transfer those */
Harald Welte76042182009-08-08 16:03:15 +0200823 dispatch_signal(SS_SMS, S_SMS_SMMA, trans->subscr);
Harald Weltef3efc592009-07-27 20:11:35 +0200824
Harald Weltecf6a3812009-08-09 19:07:41 +0200825 /* check for more messages for this subscriber */
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +0100826 assert(msg->lchan->conn.subscr == trans->subscr);
827 sms = db_sms_get_unsent_for_subscr(trans->subscr);
Harald Weltecf6a3812009-08-09 19:07:41 +0200828 if (sms)
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +0100829 gsm411_send_sms_lchan(trans->conn, sms);
Harald Weltef3efc592009-07-27 20:11:35 +0200830
831 return rc;
Harald Welteb9c758b2009-07-05 14:02:46 +0200832}
833
Harald Weltef3efc592009-07-27 20:11:35 +0200834static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
835 struct gsm_trans *trans)
Harald Welte7e310b12009-03-30 20:56:32 +0000836{
Daniel Willmann471712b2008-12-29 01:54:02 +0000837 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000838 u_int8_t msg_type = rp_data->msg_type & 0x07;
Harald Welte7e310b12009-03-30 20:56:32 +0000839 int rc = 0;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000840
841 switch (msg_type) {
842 case GSM411_MT_RP_DATA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200843 DEBUGP(DSMS, "RX SMS RP-DATA (MO)\n");
844 /* start TR2N and enter 'wait to send RP-ACK state' */
845 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
846 rc = gsm411_rx_rp_data(msg, trans, rp_data);
Harald Welte7e310b12009-03-30 20:56:32 +0000847 break;
848 case GSM411_MT_RP_ACK_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200849 DEBUGP(DSMS,"RX SMS RP-ACK (MO)\n");
850 rc = gsm411_rx_rp_ack(msg, trans, rp_data);
Harald Welteb9c758b2009-07-05 14:02:46 +0200851 break;
Harald Welte7e310b12009-03-30 20:56:32 +0000852 case GSM411_MT_RP_SMMA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200853 DEBUGP(DSMS, "RX SMS RP-SMMA\n");
854 /* start TR2N and enter 'wait to send RP-ACK state' */
855 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
856 rc = gsm411_rx_rp_smma(msg, trans, rp_data);
857 break;
858 case GSM411_MT_RP_ERROR_MO:
859 rc = gsm411_rx_rp_error(msg, trans, rp_data);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000860 break;
861 default:
Harald Welted0cf7ba2009-12-24 15:08:18 +0100862 LOGP(DSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type);
Harald Weltef3efc592009-07-27 20:11:35 +0200863 rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
864 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000865 break;
866 }
867
868 return rc;
869}
870
Harald Weltef3efc592009-07-27 20:11:35 +0200871/* send CP-ACK to given transaction */
872static int gsm411_tx_cp_ack(struct gsm_trans *trans)
873{
874 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltecf6a3812009-08-09 19:07:41 +0200875 int rc;
Harald Weltef3efc592009-07-27 20:11:35 +0200876
Harald Weltecf6a3812009-08-09 19:07:41 +0200877 rc = gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ACK);
878
879 if (trans->sms.is_mt) {
880 /* If this is a MT SMS DELIVER, we can clear transaction here */
881 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Welte (local)86b17172009-08-14 14:52:17 +0200882 //trans_free(trans);
Harald Weltecf6a3812009-08-09 19:07:41 +0200883 }
Holger Hans Peter Freyther09e364b2009-08-10 07:59:27 +0200884
885 return rc;
Harald Weltef3efc592009-07-27 20:11:35 +0200886}
887
888static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
889{
890 struct msgb *msg = gsm411_msgb_alloc();
891 u_int8_t *causep;
892
Harald Welted0cf7ba2009-12-24 15:08:18 +0100893 LOGP(DSMS, LOGL_NOTICE, "TX CP-ERROR, cause %d (%s)\n", cause,
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200894 get_value_string(cp_cause_strs, cause));
895
Harald Welte76042182009-08-08 16:03:15 +0200896 causep = msgb_put(msg, 1);
Harald Weltef3efc592009-07-27 20:11:35 +0200897 *causep = cause;
898
899 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ERROR);
900}
901
902/* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */
Harald Welte (local)daef6062009-08-14 11:41:12 +0200903int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id)
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000904{
905 struct gsm48_hdr *gh = msgb_l3(msg);
906 u_int8_t msg_type = gh->msg_type;
Harald Weltef3efc592009-07-27 20:11:35 +0200907 u_int8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
908 struct gsm_lchan *lchan = msg->lchan;
909 struct gsm_trans *trans;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000910 int rc = 0;
911
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100912 if (!lchan->conn.subscr)
Harald Weltef3efc592009-07-27 20:11:35 +0200913 return -EIO;
914 /* FIXME: send some error message */
915
Sylvain Munautc56a1412009-12-18 18:28:08 +0100916 DEBUGP(DSMS, "trans_id=%x ", transaction_id);
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100917 trans = trans_find_by_id(lchan->conn.subscr, GSM48_PDISC_SMS,
Harald Weltef3efc592009-07-27 20:11:35 +0200918 transaction_id);
919 if (!trans) {
Sylvain Munautfeaca922009-12-18 18:28:09 +0100920 DEBUGPC(DSMS, "(new) ");
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100921 trans = trans_alloc(lchan->conn.subscr, GSM48_PDISC_SMS,
Harald Weltef3efc592009-07-27 20:11:35 +0200922 transaction_id, new_callref++);
923 if (!trans) {
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200924 DEBUGPC(DSMS, "No memory for trans\n");
Harald Weltef3efc592009-07-27 20:11:35 +0200925 /* FIXME: send some error message */
926 return -ENOMEM;
927 }
928 trans->sms.cp_state = GSM411_CPS_IDLE;
929 trans->sms.rp_state = GSM411_RPS_IDLE;
930 trans->sms.is_mt = 0;
Harald Welte (local)daef6062009-08-14 11:41:12 +0200931 trans->sms.link_id = link_id;
Harald Weltef3efc592009-07-27 20:11:35 +0200932
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +0100933 trans->conn = &lchan->conn;
934 use_subscr_con(trans->conn);
Harald Weltef3efc592009-07-27 20:11:35 +0200935 }
936
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000937 switch(msg_type) {
938 case GSM411_MT_CP_DATA:
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200939 DEBUGPC(DSMS, "RX SMS CP-DATA\n");
Sylvain Munaut258e2f92009-12-24 16:47:08 +0100940
941 /* 5.4: For MO, if a CP-DATA is received for a new
942 * transaction, equals reception of an implicit
943 * last CP-ACK for previous transaction */
944 if (trans->sms.cp_state == GSM411_CPS_IDLE) {
945 int i;
946 struct gsm_trans *ptrans;
947
948 /* Scan through all remote initiated transactions */
949 for (i=8; i<15; i++) {
950 if (i == transaction_id)
951 continue;
952
Holger Hans Peter Freyther68884aa2010-03-23 06:41:45 +0100953 ptrans = trans_find_by_id(lchan->conn.subscr,
Sylvain Munaut258e2f92009-12-24 16:47:08 +0100954 GSM48_PDISC_SMS, i);
955 if (!ptrans)
956 continue;
957
958 DEBUGP(DSMS, "Implicit CP-ACK for trans_id=%x\n", i);
959
960 /* Finish it for good */
961 bsc_del_timer(&ptrans->sms.cp_timer);
962 ptrans->sms.cp_state = GSM411_CPS_IDLE;
963 trans_free(ptrans);
964 }
965 }
966
Harald Weltecb8f4432009-08-09 14:59:02 +0200967 /* 5.2.3.1.3: MO state exists when SMC has received
968 * CP-DATA, including sending of the assoc. CP-ACK */
969 /* 5.2.3.2.4: MT state exists when SMC has received
970 * CP-DATA, including sending of the assoc. CP-ACK */
971 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Weltef3efc592009-07-27 20:11:35 +0200972
Harald Welte (local)daef6062009-08-14 11:41:12 +0200973 /* SMC instance acknowledges the CP-DATA frame */
974 gsm411_tx_cp_ack(trans);
975
Harald Weltef3efc592009-07-27 20:11:35 +0200976 rc = gsm411_rx_cp_data(msg, gh, trans);
Harald Welte (local)daef6062009-08-14 11:41:12 +0200977#if 0
Harald Weltef3efc592009-07-27 20:11:35 +0200978 /* Send CP-ACK or CP-ERORR in response */
979 if (rc < 0) {
980 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_NET_FAIL);
981 } else
982 rc = gsm411_tx_cp_ack(trans);
Harald Welte (local)daef6062009-08-14 11:41:12 +0200983#endif
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000984 break;
985 case GSM411_MT_CP_ACK:
Harald Weltef3efc592009-07-27 20:11:35 +0200986 /* previous CP-DATA in this transaction was confirmed */
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200987 DEBUGPC(DSMS, "RX SMS CP-ACK\n");
Harald Weltecb8f4432009-08-09 14:59:02 +0200988 /* 5.2.3.1.3: MO state exists when SMC has received CP-ACK */
989 /* 5.2.3.2.4: MT state exists when SMC has received CP-ACK */
990 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Welte41985612009-08-10 00:24:32 +0200991 /* Stop TC1* after CP-ACK has been received */
992 bsc_del_timer(&trans->sms.cp_timer);
Harald Weltecb8f4432009-08-09 14:59:02 +0200993
Harald Weltef3efc592009-07-27 20:11:35 +0200994 if (!trans->sms.is_mt) {
Harald Weltef3efc592009-07-27 20:11:35 +0200995 /* FIXME: we have sont one CP-DATA, which was now
996 * acknowledged. Check if we want to transfer more,
997 * i.e. multi-part message */
998 trans->sms.cp_state = GSM411_CPS_IDLE;
999 trans_free(trans);
1000 }
Daniel Willmannbb16e8e2008-12-29 03:53:50 +00001001 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001002 case GSM411_MT_CP_ERROR:
Harald Welte (local)c89a5112009-08-14 10:42:43 +02001003 DEBUGPC(DSMS, "RX SMS CP-ERROR, cause %d (%s)\n", gh->data[0],
1004 get_value_string(cp_cause_strs, gh->data[0]));
Harald Welte41985612009-08-10 00:24:32 +02001005 bsc_del_timer(&trans->sms.cp_timer);
Harald Weltef3efc592009-07-27 20:11:35 +02001006 trans->sms.cp_state = GSM411_CPS_IDLE;
1007 trans_free(trans);
Daniel Willmannbb16e8e2008-12-29 03:53:50 +00001008 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001009 default:
Harald Welte (local)c89a5112009-08-14 10:42:43 +02001010 DEBUGPC(DSMS, "RX Unimplemented CP msg_type: 0x%02x\n", msg_type);
Harald Weltef3efc592009-07-27 20:11:35 +02001011 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
Harald Weltecb8f4432009-08-09 14:59:02 +02001012 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Weltef3efc592009-07-27 20:11:35 +02001013 trans_free(trans);
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001014 break;
1015 }
1016
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001017 return rc;
1018}
1019
Harald Welte8c2e36e2008-12-30 15:00:14 +00001020#if 0
Daniel Willmann3b3f0012008-12-30 13:56:46 +00001021/* Test TPDU - ALL YOUR */
1022static u_int8_t tpdu_test[] = {
1023 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
1024 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
1025 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
1026 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
Daniel Willmanne2a728d2008-12-30 14:03:09 +00001027};
Harald Welte8c2e36e2008-12-30 15:00:14 +00001028#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001029
Harald Weltecf6a3812009-08-09 19:07:41 +02001030/* Take a SMS in gsm_sms structure and send it through an already
1031 * existing lchan. We also assume that the caller ensured this lchan already
1032 * has a SAPI3 RLL connection! */
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001033int gsm411_send_sms_lchan(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001034{
1035 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltef3efc592009-07-27 20:11:35 +02001036 struct gsm_trans *trans;
Harald Welte76042182009-08-08 16:03:15 +02001037 u_int8_t *data, *rp_ud_len;
Harald Welte87f5d632009-07-04 17:39:00 +02001038 u_int8_t msg_ref = 42;
Sylvain Munautc4052cf2009-12-24 13:27:36 +01001039 int transaction_id;
Harald Welte76042182009-08-08 16:03:15 +02001040 int rc;
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001041
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001042 transaction_id = trans_assign_trans_id(conn->subscr, GSM48_PDISC_SMS, 0);
Harald Welte49839212009-12-22 13:45:58 +01001043 if (transaction_id == -1) {
Harald Welted0cf7ba2009-12-24 15:08:18 +01001044 LOGP(DSMS, LOGL_ERROR, "No available transaction ids\n");
Harald Welte49839212009-12-22 13:45:58 +01001045 return -EBUSY;
1046 }
Harald Weltecf6a3812009-08-09 19:07:41 +02001047
Harald Welte76042182009-08-08 16:03:15 +02001048 DEBUGP(DSMS, "send_sms_lchan()\n");
Harald Weltef3efc592009-07-27 20:11:35 +02001049
Harald Welte76042182009-08-08 16:03:15 +02001050 /* FIXME: allocate transaction with message reference */
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001051 trans = trans_alloc(conn->subscr, GSM48_PDISC_SMS,
Harald Welte76042182009-08-08 16:03:15 +02001052 transaction_id, new_callref++);
1053 if (!trans) {
Harald Welted0cf7ba2009-12-24 15:08:18 +01001054 LOGP(DSMS, LOGL_ERROR, "No memory for trans\n");
Harald Welte76042182009-08-08 16:03:15 +02001055 /* FIXME: send some error message */
1056 return -ENOMEM;
1057 }
1058 trans->sms.cp_state = GSM411_CPS_IDLE;
1059 trans->sms.rp_state = GSM411_RPS_IDLE;
1060 trans->sms.is_mt = 1;
1061 trans->sms.sms = sms;
Harald Welte (local)daef6062009-08-14 11:41:12 +02001062 trans->sms.link_id = UM_SAPI_SMS; /* FIXME: main or SACCH ? */
Harald Welte76042182009-08-08 16:03:15 +02001063
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001064 trans->conn = conn;
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +01001065 use_subscr_con(trans->conn);
Harald Welte76042182009-08-08 16:03:15 +02001066
1067 /* Hardcode SMSC Originating Address for now */
Daniel Willmanna3e29842008-12-29 16:03:54 +00001068 data = (u_int8_t *)msgb_put(msg, 8);
Harald Welte87f5d632009-07-04 17:39:00 +02001069 data[0] = 0x07; /* originator length == 7 */
Harald Welteb9c758b2009-07-05 14:02:46 +02001070 data[1] = 0x91; /* type of number: international, ISDN */
1071 data[2] = 0x44; /* 447785016005 */
Daniel Willmanna3e29842008-12-29 16:03:54 +00001072 data[3] = 0x77;
1073 data[4] = 0x58;
1074 data[5] = 0x10;
1075 data[6] = 0x06;
1076 data[7] = 0x50;
Harald Welte87f5d632009-07-04 17:39:00 +02001077
1078 /* Hardcoded Destination Address */
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001079 data = (u_int8_t *)msgb_put(msg, 1);
Harald Welte87f5d632009-07-04 17:39:00 +02001080 data[0] = 0; /* destination length == 0 */
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001081
Harald Welte76042182009-08-08 16:03:15 +02001082 /* obtain a pointer for the rp_ud_len, so we can fill it later */
1083 rp_ud_len = (u_int8_t *)msgb_put(msg, 1);
Daniel Willmann4a1e8792008-12-29 06:23:56 +00001084
Harald Welte76042182009-08-08 16:03:15 +02001085#if 1
1086 /* generate the 03.40 TPDU */
1087 rc = gsm340_gen_tpdu(msg, sms);
1088 if (rc < 0) {
1089 msgb_free(msg);
1090 return rc;
1091 }
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001092
Harald Welte76042182009-08-08 16:03:15 +02001093 *rp_ud_len = rc;
1094#else
1095 data = msgb_put(msg, sizeof(tpdu_test));
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001096 memcpy(data, tpdu_test, sizeof(tpdu_test));
Harald Welte76042182009-08-08 16:03:15 +02001097 *rp_ud_len = sizeof(tpdu_test);
1098#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001099
Harald Welte76042182009-08-08 16:03:15 +02001100 DEBUGP(DSMS, "TX: SMS DELIVER\n");
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001101
Holger Hans Peter Freytherd4c16b12010-03-23 07:56:22 +01001102 counter_inc(conn->bts->network->stats.sms.delivered);
Harald Welte24ff6ee2009-12-22 00:41:05 +01001103
Harald Weltef3efc592009-07-27 20:11:35 +02001104 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
1105 /* FIXME: enter 'wait for RP-ACK' state, start TR1N */
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001106}
Harald Weltef3efc592009-07-27 20:11:35 +02001107
Harald Weltecf6a3812009-08-09 19:07:41 +02001108/* RLL SAPI3 establish callback. Now we have a RLL connection and
1109 * can deliver the actual message */
Harald Weltecb8f4432009-08-09 14:59:02 +02001110static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
1111 void *_sms, enum bsc_rllr_ind type)
1112{
1113 struct gsm_sms *sms = _sms;
1114
1115 DEBUGP(DSMS, "rll_ind_cb(lchan=%p, link_id=%u, sms=%p, type=%u\n",
1116 lchan, link_id, sms, type);
1117
1118 switch (type) {
1119 case BSC_RLLR_IND_EST_CONF:
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001120#warning "BROKEN: The BSC will establish this transparently"
1121 gsm411_send_sms_lchan(&lchan->conn, sms);
Harald Weltecb8f4432009-08-09 14:59:02 +02001122 break;
1123 case BSC_RLLR_IND_REL_IND:
1124 case BSC_RLLR_IND_ERR_IND:
1125 case BSC_RLLR_IND_TIMEOUT:
Holger Hans Peter Freyther5179c8e2010-03-23 07:32:23 +01001126#warning "BROKEN: We will need to handle SAPI n Reject"
Harald Weltecb8f4432009-08-09 14:59:02 +02001127 sms_free(sms);
1128 break;
1129 }
1130}
1131
Harald Weltecf6a3812009-08-09 19:07:41 +02001132/* paging callback. Here we get called if paging a subscriber has
1133 * succeeded or failed. */
Harald Welte76042182009-08-08 16:03:15 +02001134static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
1135 struct msgb *msg, void *_lchan, void *_sms)
Harald Weltef3efc592009-07-27 20:11:35 +02001136{
Harald Welte76042182009-08-08 16:03:15 +02001137 struct gsm_lchan *lchan = _lchan;
1138 struct gsm_sms *sms = _sms;
1139 int rc;
Harald Weltef3efc592009-07-27 20:11:35 +02001140
Harald Welte76042182009-08-08 16:03:15 +02001141 DEBUGP(DSMS, "paging_cb_send_sms(hooknum=%u, event=%u, msg=%p,"
1142 "lchan=%p, sms=%p)\n", hooknum, event, msg, lchan, sms);
1143
1144 if (hooknum != GSM_HOOK_RR_PAGING)
1145 return -EINVAL;
1146
1147 switch (event) {
1148 case GSM_PAGING_SUCCEEDED:
1149 /* Paging aborted without lchan ?!? */
1150 if (!lchan) {
1151 sms_free(sms);
1152 rc = -EIO;
1153 break;
1154 }
Harald Weltecf6a3812009-08-09 19:07:41 +02001155 /* Establish a SAPI3 RLL connection for SMS */
Harald Weltecb8f4432009-08-09 14:59:02 +02001156 rc = rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
Harald Welte76042182009-08-08 16:03:15 +02001157 break;
1158 case GSM_PAGING_EXPIRED:
1159 sms_free(sms);
1160 rc = -ETIMEDOUT;
1161 break;
1162 default:
1163 rc = -EINVAL;
1164 break;
1165 }
1166
1167 return rc;
1168}
1169
Harald Weltecf6a3812009-08-09 19:07:41 +02001170/* high-level function to send a SMS to a given subscriber. The function
1171 * will take care of paging the subscriber, establishing the RLL SAPI3
1172 * connection, etc. */
Harald Welte76042182009-08-08 16:03:15 +02001173int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
1174 struct gsm_sms *sms)
1175{
Harald Weltecf6a3812009-08-09 19:07:41 +02001176 struct gsm_lchan *lchan;
Harald Weltee903edf2009-08-15 03:16:17 +02001177 int rc;
Harald Weltecf6a3812009-08-09 19:07:41 +02001178
Harald Welte76042182009-08-08 16:03:15 +02001179 /* check if we already have an open lchan to the subscriber.
1180 * if yes, send the SMS this way */
Harald Weltecf6a3812009-08-09 19:07:41 +02001181 lchan = lchan_for_subscr(subscr);
1182 if (lchan)
1183 return rll_establish(lchan, UM_SAPI_SMS,
1184 rll_ind_cb, sms);
Harald Welte76042182009-08-08 16:03:15 +02001185
1186 /* if not, we have to start paging */
Harald Weltee903edf2009-08-15 03:16:17 +02001187 rc = paging_request(subscr->net, subscr, RSL_CHANNEED_SDCCH,
1188 paging_cb_send_sms, sms);
Harald Welte (local)0abaf332009-08-15 11:25:45 +02001189 if (rc <= 0)
Harald Weltee903edf2009-08-15 03:16:17 +02001190 sms_free(sms);
Harald Welte76042182009-08-08 16:03:15 +02001191
1192 return 0;
1193}
Harald Welte3366a942009-07-28 00:44:49 +02001194
Harald Weltecf6a3812009-08-09 19:07:41 +02001195static int subscr_sig_cb(unsigned int subsys, unsigned int signal,
1196 void *handler_data, void *signal_data)
1197{
1198 struct gsm_subscriber *subscr;
1199 struct gsm_lchan *lchan;
1200 struct gsm_sms *sms;
1201
1202 switch (signal) {
1203 case S_SUBSCR_ATTACHED:
1204 /* A subscriber has attached. Check if there are
1205 * any pending SMS for him to be delivered */
1206 subscr = signal_data;
1207 lchan = lchan_for_subscr(subscr);
1208 if (!lchan)
1209 break;
1210 sms = db_sms_get_unsent_for_subscr(subscr);
1211 if (!sms)
1212 break;
1213 /* Establish a SAPI3 RLL connection for SMS */
1214 rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
1215 break;
1216 default:
1217 break;
1218 }
1219 return 0;
1220}
1221
Harald Welte (local)86b17172009-08-14 14:52:17 +02001222void _gsm411_sms_trans_free(struct gsm_trans *trans)
1223{
1224 bsc_del_timer(&trans->sms.cp_timer);
1225}
1226
Harald Welte7bfc2672009-07-28 00:41:45 +02001227static __attribute__((constructor)) void on_dso_load_sms(void)
1228{
Harald Weltecf6a3812009-08-09 19:07:41 +02001229 register_signal_handler(SS_SUBSCR, subscr_sig_cb, NULL);
Harald Welte7bfc2672009-07-28 00:41:45 +02001230}