blob: f941d90a2026da17f848eb68a16be95c138a2c90 [file] [log] [blame]
Daniel Willmann8b3390e2008-12-28 00:31:09 +00001/* Point-to-Point (PP) Short Message Service (SMS)
2 * Support on Mobile Radio Interface
3 * 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0 */
4
5/* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
Harald Welte7e310b12009-03-30 20:56:32 +00006 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
Daniel Willmann8b3390e2008-12-28 00:31:09 +00007 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 *
24 */
25
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <errno.h>
Harald Weltef3efc592009-07-27 20:11:35 +020031#include <time.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000032#include <netinet/in.h>
33
34#include <openbsc/msgb.h>
Harald Welte7e310b12009-03-30 20:56:32 +000035#include <openbsc/tlv.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000036#include <openbsc/debug.h>
Daniel Willmann471712b2008-12-29 01:54:02 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/gsm_subscriber.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000039#include <openbsc/gsm_04_11.h>
40#include <openbsc/gsm_04_08.h>
Holger Freyther76c95692009-02-17 20:31:30 +000041#include <openbsc/gsm_utils.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000042#include <openbsc/abis_rsl.h>
Holger Freyther9b177762009-02-16 19:07:18 +000043#include <openbsc/signal.h>
Harald Welte7e310b12009-03-30 20:56:32 +000044#include <openbsc/db.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020045#include <openbsc/talloc.h>
Harald Weltef3efc592009-07-27 20:11:35 +020046#include <openbsc/transaction.h>
Harald Welte76042182009-08-08 16:03:15 +020047#include <openbsc/paging.h>
Harald Weltecb8f4432009-08-09 14:59:02 +020048#include <openbsc/bsc_rll.h>
Holger Hans Peter Freyther34e97492009-08-10 07:54:02 +020049#include <openbsc/chan_alloc.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000050
Daniel Willmann471712b2008-12-29 01:54:02 +000051#define GSM411_ALLOC_SIZE 1024
52#define GSM411_ALLOC_HEADROOM 128
53
Harald Weltecb8f4432009-08-09 14:59:02 +020054#define UM_SAPI_SMS 3 /* See GSM 04.05/04.06 */
55
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020056void *tall_gsms_ctx;
Harald Weltef3efc592009-07-27 20:11:35 +020057static u_int32_t new_callref = 0x40000001;
58
Harald Welte (local)c89a5112009-08-14 10:42:43 +020059struct value_string {
60 u_int32_t value;
61 const char *str;
62};
63
64static const struct value_string cp_cause_strs[] = {
65 { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
66 { GSM411_CP_CAUSE_CONGESTION, "Congestion" },
67 { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
68 { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
69 { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
70 { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
71 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
72 "Message incompatible with protocol state" },
73 { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
74 { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
75 { 0, 0 }
76};
77
78static const struct value_string rp_cause_strs[] = {
79 { GSM411_RP_CAUSE_MO_NUM_UNASSIGNED, "(MO) Number not assigned" },
80 { GSM411_RP_CAUSE_MO_OP_DET_BARR, "(MO) Operator determined barring" },
81 { GSM411_RP_CAUSE_MO_CALL_BARRED, "(MO) Call barred" },
82 { GSM411_RP_CAUSE_MO_SMS_REJECTED, "(MO) SMS rejected" },
83 { GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER, "(MO) Destination out of order" },
84 { GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR, "(MO) Unidentified subscriber" },
85 { GSM411_RP_CAUSE_MO_FACILITY_REJ, "(MO) Facility reject" },
86 { GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR, "(MO) Unknown subscriber" },
87 { GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER, "(MO) Network out of order" },
88 { GSM411_RP_CAUSE_MO_TEMP_FAIL, "(MO) Temporary failure" },
89 { GSM411_RP_CAUSE_MO_CONGESTION, "(MO) Congestion" },
90 { GSM411_RP_CAUSE_MO_RES_UNAVAIL, "(MO) Resource unavailable" },
91 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR, "(MO) Requested facility not subscribed" },
92 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL, "(MO) Requested facility not implemented" },
93 { GSM411_RP_CAUSE_MO_INTERWORKING, "(MO) Interworking" },
94 /* valid only for MT */
95 { GSM411_RP_CAUSE_MT_MEM_EXCEEDED, "(MT) Memory Exceeded" },
96 /* valid for both directions */
97 { GSM411_RP_CAUSE_INV_TRANS_REF, "Invalid Transaction Reference" },
98 { GSM411_RP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
99 { GSM411_RP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
100 { GSM411_RP_CAUSE_MSGTYPE_NOTEXIST, "Message Type non-existant" },
101 { GSM411_RP_CAUSE_MSG_INCOMP_STATE, "Message incompatible with protocol state" },
102 { GSM411_RP_CAUSE_IE_NOTEXIST, "Information Element not existing" },
103 { GSM411_RP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
104 { 0, NULL }
105};
106
107const char *get_value_string(const struct value_string *vs, u_int32_t val)
108{
109 int i;
110
111 for (i = 0;; i++) {
112 if (vs[i].value == 0 && vs[i].str == NULL)
113 break;
114 if (vs[i].value == val)
115 return vs[i].str;
116 }
117 return "unknown";
118}
119
Harald Welte76042182009-08-08 16:03:15 +0200120struct gsm_sms *sms_alloc(void)
121{
122 return talloc_zero(tall_gsms_ctx, struct gsm_sms);
123}
124
125void sms_free(struct gsm_sms *sms)
126{
127 /* drop references to subscriber structure */
128 if (sms->sender)
129 subscr_put(sms->sender);
130 if (sms->receiver)
131 subscr_put(sms->receiver);
132
133 talloc_free(sms);
134}
135
Holger Freythera553d092009-01-04 20:16:25 +0000136struct msgb *gsm411_msgb_alloc(void)
Daniel Willmann471712b2008-12-29 01:54:02 +0000137{
Harald Welte966636f2009-06-26 19:39:35 +0200138 return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
139 "GSM 04.11");
Daniel Willmann471712b2008-12-29 01:54:02 +0000140}
141
Harald Welte (local)daef6062009-08-14 11:41:12 +0200142static int gsm411_sendmsg(struct msgb *msg, u_int8_t link_id)
Daniel Willmann471712b2008-12-29 01:54:02 +0000143{
144 if (msg->lchan)
145 msg->trx = msg->lchan->ts->trx;
146
147 msg->l3h = msg->data;
148
Harald Welte76042182009-08-08 16:03:15 +0200149 DEBUGP(DSMS, "GSM4.11 TX %s\n", hexdump(msg->data, msg->len));
150
Harald Welte (local)daef6062009-08-14 11:41:12 +0200151 return rsl_data_request(msg, link_id);
Daniel Willmann471712b2008-12-29 01:54:02 +0000152}
153
Harald Welte41985612009-08-10 00:24:32 +0200154/* SMC TC1* is expired */
155static void cp_timer_expired(void *data)
156{
157 struct gsm_trans *trans = data;
158
159 DEBUGP(DSMS, "SMC Timer TC1* is expired, calling trans_free()\n");
160 /* FIXME: we need to re-transmit the last CP-DATA 1..3 times */
161 trans_free(trans);
162}
163
Harald Welte87f5d632009-07-04 17:39:00 +0200164/* Prefix msg with a 04.08/04.11 CP header */
Harald Weltef3efc592009-07-27 20:11:35 +0200165static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
166 u_int8_t msg_type)
Harald Welte87f5d632009-07-04 17:39:00 +0200167{
168 struct gsm48_hdr *gh;
169
170 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
171 /* Outgoing needs the highest bit set */
Harald Weltef3efc592009-07-27 20:11:35 +0200172 gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
Harald Welte87f5d632009-07-04 17:39:00 +0200173 gh->msg_type = msg_type;
174
Harald Weltef3efc592009-07-27 20:11:35 +0200175 /* assign the outgoing lchan */
176 msg->lchan = trans->lchan;
177
178 /* mobile originating */
179 switch (gh->msg_type) {
180 case GSM411_MT_CP_DATA:
181 /* 5.2.3.1.2: enter MO-wait for CP-ack */
Harald Weltecb8f4432009-08-09 14:59:02 +0200182 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
Harald Weltef3efc592009-07-27 20:11:35 +0200183 trans->sms.cp_state = GSM411_CPS_WAIT_CP_ACK;
Harald Welte41985612009-08-10 00:24:32 +0200184 trans->sms.cp_timer.data = trans;
185 trans->sms.cp_timer.cb = cp_timer_expired;
186 /* 5.3.2.1: Set Timer TC1A */
187 bsc_schedule_timer(&trans->sms.cp_timer, GSM411_TMR_TC1A);
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200188 DEBUGP(DSMS, "TX: CP-DATA ");
189 break;
190 case GSM411_MT_CP_ACK:
191 DEBUGP(DSMS, "TX: CP-ACK ");
192 break;
193 case GSM411_MT_CP_ERROR:
194 DEBUGP(DSMS, "TX: CP-ACK ");
Harald Weltef3efc592009-07-27 20:11:35 +0200195 break;
196 }
197
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200198 DEBUGPC(DSMS, "trans=%x\n", trans->transaction_id);
199
Harald Welte (local)daef6062009-08-14 11:41:12 +0200200 return gsm411_sendmsg(msg, trans->sms.link_id);
Harald Welte87f5d632009-07-04 17:39:00 +0200201}
202
203/* Prefix msg with a RP-DATA header and send as CP-DATA */
Harald Weltef3efc592009-07-27 20:11:35 +0200204static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
205 u_int8_t rp_msg_type, u_int8_t rp_msg_ref)
Harald Welte87f5d632009-07-04 17:39:00 +0200206{
207 struct gsm411_rp_hdr *rp;
Harald Welte0d544e72009-08-10 00:22:19 +0200208 u_int8_t len = msg->len;
Harald Welte87f5d632009-07-04 17:39:00 +0200209
210 /* GSM 04.11 RP-DATA header */
211 rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
Harald Welte0d544e72009-08-10 00:22:19 +0200212 rp->len = len + 2;
Harald Welte87f5d632009-07-04 17:39:00 +0200213 rp->msg_type = rp_msg_type;
214 rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */
215
Harald Weltef3efc592009-07-27 20:11:35 +0200216 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA);
Harald Welte87f5d632009-07-04 17:39:00 +0200217}
218
Steffen Neubauer5727cf42009-11-11 23:02:07 +0900219static time_t gsm340_scts(u_int8_t *scts);
220
Harald Welte76042182009-08-08 16:03:15 +0200221static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp)
Harald Welte7e310b12009-03-30 20:56:32 +0000222{
223 u_int8_t vp;
224 unsigned long minutes;
Steffen Neubauer5727cf42009-11-11 23:02:07 +0900225 time_t expires;
226 time_t now;
Harald Welte7e310b12009-03-30 20:56:32 +0000227
Harald Welte76042182009-08-08 16:03:15 +0200228 switch (sms_vpf) {
Harald Welte7e310b12009-03-30 20:56:32 +0000229 case GSM340_TP_VPF_RELATIVE:
230 /* Chapter 9.2.3.12.1 */
Harald Welte76042182009-08-08 16:03:15 +0200231 vp = *(sms_vp);
Harald Welte7e310b12009-03-30 20:56:32 +0000232 if (vp <= 143)
233 minutes = vp + 1 * 5;
234 else if (vp <= 167)
235 minutes = 12*60 + (vp-143) * 30;
236 else if (vp <= 196)
237 minutes = vp-166 * 60 * 24;
238 else
239 minutes = vp-192 * 60 * 24 * 7;
240 break;
241 case GSM340_TP_VPF_ABSOLUTE:
242 /* Chapter 9.2.3.12.2 */
Steffen Neubauer5727cf42009-11-11 23:02:07 +0900243 expires = gsm340_scts(sms_vp);
244 now = mktime(gmtime(NULL));
245 if (expires <= now)
246 minutes = 0;
247 else
248 minutes = (expires-now)/60;
Harald Welte7e310b12009-03-30 20:56:32 +0000249 break;
250 case GSM340_TP_VPF_ENHANCED:
251 /* Chapter 9.2.3.12.3 */
252 /* FIXME: implementation */
253 DEBUGP(DSMS, "VPI enhanced not implemented yet\n");
254 break;
Daniel Willmann58c83d82009-08-13 03:40:49 +0200255 case GSM340_TP_VPF_NONE:
256 /* Default validity: two days */
257 minutes = 24 * 60 * 2;
258 break;
Harald Welte7e310b12009-03-30 20:56:32 +0000259 }
260 return minutes;
261}
262
263/* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */
264enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
265{
266 u_int8_t cgbits = dcs >> 4;
267 enum sms_alphabet alpha = DCS_NONE;
268
269 if ((cgbits & 0xc) == 0) {
270 if (cgbits & 2)
271 DEBUGP(DSMS, "Compressed SMS not supported yet\n");
272
Daniel Willmannd5d5e1d2009-08-15 03:01:17 +0200273 switch ((dcs >> 2)&0x03) {
Harald Welte7e310b12009-03-30 20:56:32 +0000274 case 0:
275 alpha = DCS_7BIT_DEFAULT;
276 break;
277 case 1:
278 alpha = DCS_8BIT_DATA;
279 break;
280 case 2:
281 alpha = DCS_UCS2;
282 break;
283 }
284 } else if (cgbits == 0xc || cgbits == 0xd)
285 alpha = DCS_7BIT_DEFAULT;
286 else if (cgbits == 0xe)
287 alpha = DCS_UCS2;
288 else if (cgbits == 0xf) {
289 if (dcs & 4)
290 alpha = DCS_8BIT_DATA;
291 else
292 alpha = DCS_7BIT_DEFAULT;
293 }
294
295 return alpha;
296}
297
Harald Welte76042182009-08-08 16:03:15 +0200298static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms)
Harald Welte7e310b12009-03-30 20:56:32 +0000299{
300 if (db_sms_store(gsms) != 0) {
301 DEBUGP(DSMS, "Failed to store SMS in Database\n");
Harald Welteb9c758b2009-07-05 14:02:46 +0200302 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000303 }
Harald Welte76042182009-08-08 16:03:15 +0200304 /* dispatch a signal to tell higher level about it */
305 dispatch_signal(SS_SMS, S_SMS_SUBMITTED, gsms);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200306 /* try delivering the SMS right now */
307 //gsm411_send_sms_subscr(gsms->receiver, gsms);
308
Harald Welte7e310b12009-03-30 20:56:32 +0000309 return 0;
310}
311
Harald Welte76042182009-08-08 16:03:15 +0200312/* generate a TPDU address field compliant with 03.40 sec. 9.1.2.5 */
313static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len,
314 struct gsm_subscriber *subscr)
Harald Weltef3efc592009-07-27 20:11:35 +0200315{
Harald Welte76042182009-08-08 16:03:15 +0200316 int len_in_bytes;
Harald Weltef3efc592009-07-27 20:11:35 +0200317
Harald Welte76042182009-08-08 16:03:15 +0200318 oa[1] = 0xb9; /* networks-specific number, private numbering plan */
319
320 len_in_bytes = encode_bcd_number(oa, oa_len, 1, subscr->extension);
321
322 /* GSM 03.40 tells us the length is in 'useful semi-octets' */
323 oa[0] = strlen(subscr->extension) & 0xff;
324
325 return len_in_bytes;
Harald Weltef3efc592009-07-27 20:11:35 +0200326}
327
Steffen Neubauer5727cf42009-11-11 23:02:07 +0900328/* Turn int into semi-octet representation: 98 => 0x89 */
Harald Weltef3efc592009-07-27 20:11:35 +0200329static u_int8_t bcdify(u_int8_t value)
330{
331 u_int8_t ret;
332
Harald Welte76042182009-08-08 16:03:15 +0200333 ret = value / 10;
334 ret |= (value % 10) << 4;
Harald Weltef3efc592009-07-27 20:11:35 +0200335
336 return ret;
337}
338
Steffen Neubauer5727cf42009-11-11 23:02:07 +0900339/* Turn semi-octet representation into int: 0x89 => 98 */
340static u_int8_t unbcdify(u_int8_t value)
341{
342 u_int8_t ret;
343
344 if ((value & 0x0F) > 9 || (value >> 4) > 9)
345 DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value);
346
347 ret = (value&0x0F)*10;
348 if (ret > 90)
349 ret += value>>4;
350
351 return ret;
352}
353
Harald Weltef3efc592009-07-27 20:11:35 +0200354/* Generate 03.40 TP-SCTS */
355static void gsm340_gen_scts(u_int8_t *scts, time_t time)
356{
357 struct tm *tm = localtime(&time);
Harald Weltef3efc592009-07-27 20:11:35 +0200358
359 *scts++ = bcdify(tm->tm_year % 100);
Stefan Schmidt689537a2009-08-13 21:00:44 +0200360 *scts++ = bcdify(tm->tm_mon + 1);
Harald Weltef3efc592009-07-27 20:11:35 +0200361 *scts++ = bcdify(tm->tm_mday);
362 *scts++ = bcdify(tm->tm_hour);
363 *scts++ = bcdify(tm->tm_min);
364 *scts++ = bcdify(tm->tm_sec);
Steffen Neubauer5727cf42009-11-11 23:02:07 +0900365 *scts++ = bcdify(tm->tm_gmtoff/(60*15));
366}
367
368/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */
369static time_t gsm340_scts(u_int8_t *scts)
370{
371 struct tm tm;
372
373 u_int8_t yr = unbcdify(*scts++);
374
375 if (yr <= 80)
376 tm.tm_year = 100 + yr;
377 else
378 tm.tm_year = yr;
379 tm.tm_mon = unbcdify(*scts++) - 1;
380 tm.tm_mday = unbcdify(*scts++);
381 tm.tm_hour = unbcdify(*scts++);
382 tm.tm_min = unbcdify(*scts++);
383 tm.tm_sec = unbcdify(*scts++);
384 /* according to gsm 03.40 time zone is
385 "expressed in quarters of an hour" */
386 tm.tm_gmtoff = unbcdify(*scts++) * 15*60;
387
388 return mktime(&tm);
Harald Weltef3efc592009-07-27 20:11:35 +0200389}
390
Harald Welte76042182009-08-08 16:03:15 +0200391/* generate a msgb containing a TPDU derived from struct gsm_sms,
392 * returns total size of TPDU */
393static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
Harald Weltef3efc592009-07-27 20:11:35 +0200394{
Harald Weltef3efc592009-07-27 20:11:35 +0200395 u_int8_t *smsp;
396 u_int8_t oa[12]; /* max len per 03.40 */
397 u_int8_t oa_len = 0;
Daniel Willmann9aef1452009-08-13 03:39:07 +0200398 u_int8_t octet_len;
Harald Welte76042182009-08-08 16:03:15 +0200399 unsigned int old_msg_len = msg->len;
Harald Weltef3efc592009-07-27 20:11:35 +0200400
401 /* generate first octet with masked bits */
402 smsp = msgb_put(msg, 1);
Harald Welte76042182009-08-08 16:03:15 +0200403 /* TP-MTI (message type indicator) */
Harald Weltef3efc592009-07-27 20:11:35 +0200404 *smsp = GSM340_SMS_DELIVER_SC2MS;
Harald Welte76042182009-08-08 16:03:15 +0200405 /* TP-MMS (more messages to send) */
406 if (0 /* FIXME */)
Harald Weltef3efc592009-07-27 20:11:35 +0200407 *smsp |= 0x04;
Harald Welte76042182009-08-08 16:03:15 +0200408 /* TP-SRI(deliver)/SRR(submit) */
Harald Weltef3efc592009-07-27 20:11:35 +0200409 if (sms->status_rep_req)
410 *smsp |= 0x20;
Harald Welte76042182009-08-08 16:03:15 +0200411 /* TP-UDHI (indicating TP-UD contains a header) */
412 if (sms->ud_hdr_ind)
Harald Weltef3efc592009-07-27 20:11:35 +0200413 *smsp |= 0x40;
Harald Welte76042182009-08-08 16:03:15 +0200414#if 0
415 /* TP-RP (indicating that a reply path exists) */
Harald Weltef3efc592009-07-27 20:11:35 +0200416 if (sms->
417 *smsp |= 0x80;
418#endif
419
420 /* generate originator address */
Harald Welte76042182009-08-08 16:03:15 +0200421 oa_len = gsm340_gen_oa(oa, sizeof(oa), sms->sender);
Harald Weltef3efc592009-07-27 20:11:35 +0200422 smsp = msgb_put(msg, oa_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200423 memcpy(smsp, oa, oa_len);
424
425 /* generate TP-PID */
426 smsp = msgb_put(msg, 1);
427 *smsp = sms->protocol_id;
428
429 /* generate TP-DCS */
430 smsp = msgb_put(msg, 1);
431 *smsp = sms->data_coding_scheme;
432
433 /* generate TP-SCTS */
434 smsp = msgb_put(msg, 7);
435 gsm340_gen_scts(smsp, time(NULL));
Harald Welte76042182009-08-08 16:03:15 +0200436
Harald Weltef3efc592009-07-27 20:11:35 +0200437 /* generate TP-UDL */
438 smsp = msgb_put(msg, 1);
Harald Welte76042182009-08-08 16:03:15 +0200439 *smsp = sms->user_data_len;
Harald Weltef3efc592009-07-27 20:11:35 +0200440
441 /* generate TP-UD */
Daniel Willmann6b024cb2009-08-15 03:01:46 +0200442 switch (gsm338_get_sms_alphabet(sms->data_coding_scheme)) {
443 case DCS_7BIT_DEFAULT:
Daniel Willmann9aef1452009-08-13 03:39:07 +0200444 octet_len = sms->user_data_len*7/8;
445 if (sms->user_data_len*7%8 != 0)
446 octet_len++;
Daniel Willmann6b1e8222009-08-12 21:17:06 +0200447 /* Warning, user_data_len indicates the amount of septets
448 * (characters), we need amount of octets occupied */
Daniel Willmann9aef1452009-08-13 03:39:07 +0200449 smsp = msgb_put(msg, octet_len);
450 memcpy(smsp, sms->user_data, octet_len);
Daniel Willmann6b024cb2009-08-15 03:01:46 +0200451 break;
452 case DCS_UCS2:
453 case DCS_8BIT_DATA:
454 smsp = msgb_put(msg, sms->user_data_len);
455 memcpy(smsp, sms->user_data, sms->user_data_len);
456 break;
457 default:
458 DEBUGP(DSMS, "Unhandled Data Coding Scheme: 0x%02X\n", sms->data_coding_scheme);
459 break;
Daniel Willmann6b1e8222009-08-12 21:17:06 +0200460 }
Harald Weltef3efc592009-07-27 20:11:35 +0200461
Harald Welte76042182009-08-08 16:03:15 +0200462 return msg->len - old_msg_len;
Harald Weltef3efc592009-07-27 20:11:35 +0200463}
464
Harald Welteb9c758b2009-07-05 14:02:46 +0200465/* process an incoming TPDU (called from RP-DATA)
466 * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
Harald Welte7e310b12009-03-30 20:56:32 +0000467static int gsm340_rx_tpdu(struct msgb *msg)
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000468{
Harald Welte9176bd42009-07-23 18:46:00 +0200469 struct gsm_bts *bts = msg->lchan->ts->trx->bts;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000470 u_int8_t *smsp = msgb_sms(msg);
Harald Welte7e310b12009-03-30 20:56:32 +0000471 struct gsm_sms *gsms;
Harald Welte76042182009-08-08 16:03:15 +0200472 u_int8_t sms_mti, sms_mms, sms_vpf, sms_alphabet, sms_rp;
473 u_int8_t *sms_vp;
Harald Welte7e310b12009-03-30 20:56:32 +0000474 u_int8_t da_len_bytes;
475 u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
476 int rc = 0;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000477
Harald Welte76042182009-08-08 16:03:15 +0200478 gsms = sms_alloc();
479 if (!gsms)
Harald Welteb9c758b2009-07-05 14:02:46 +0200480 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Harald Welte7e310b12009-03-30 20:56:32 +0000481
482 /* invert those fields where 0 means active/present */
Harald Welte76042182009-08-08 16:03:15 +0200483 sms_mti = *smsp & 0x03;
484 sms_mms = !!(*smsp & 0x04);
485 sms_vpf = (*smsp & 0x18) >> 3;
486 gsms->status_rep_req = (*smsp & 0x20);
487 gsms->ud_hdr_ind = (*smsp & 0x40);
488 sms_rp = (*smsp & 0x80);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000489
490 smsp++;
Harald Welte76042182009-08-08 16:03:15 +0200491 gsms->msg_ref = *smsp++;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000492
Harald Welte7e310b12009-03-30 20:56:32 +0000493 /* length in bytes of the destination address */
494 da_len_bytes = 2 + *smsp/2 + *smsp%2;
495 if (da_len_bytes > 12) {
496 DEBUGP(DSMS, "Destination Address > 12 bytes ?!?\n");
Harald Welteb9c758b2009-07-05 14:02:46 +0200497 rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
Harald Welte7e310b12009-03-30 20:56:32 +0000498 goto out;
499 }
Harald Welte3cfdb222009-06-12 02:42:11 +0800500 memset(address_lv, 0, sizeof(address_lv));
Harald Welte7e310b12009-03-30 20:56:32 +0000501 memcpy(address_lv, smsp, da_len_bytes);
502 /* mangle first byte to reflect length in bytes, not digits */
Harald Welte3cfdb222009-06-12 02:42:11 +0800503 address_lv[0] = da_len_bytes - 1;
Harald Welte7e310b12009-03-30 20:56:32 +0000504 /* convert to real number */
Harald Welte76042182009-08-08 16:03:15 +0200505 decode_bcd_number(gsms->dest_addr, sizeof(gsms->dest_addr), address_lv, 1);
Harald Welte7e310b12009-03-30 20:56:32 +0000506 smsp += da_len_bytes;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000507
Harald Welte76042182009-08-08 16:03:15 +0200508 gsms->protocol_id = *smsp++;
509 gsms->data_coding_scheme = *smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000510
Harald Welte76042182009-08-08 16:03:15 +0200511 sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
Harald Welte7e310b12009-03-30 20:56:32 +0000512
Harald Welte76042182009-08-08 16:03:15 +0200513 switch (sms_vpf) {
Harald Welte7e310b12009-03-30 20:56:32 +0000514 case GSM340_TP_VPF_RELATIVE:
Harald Welte76042182009-08-08 16:03:15 +0200515 sms_vp = smsp++;
Harald Welte7e310b12009-03-30 20:56:32 +0000516 break;
517 case GSM340_TP_VPF_ABSOLUTE:
518 case GSM340_TP_VPF_ENHANCED:
Harald Welte76042182009-08-08 16:03:15 +0200519 sms_vp = smsp;
Harald Welte7e310b12009-03-30 20:56:32 +0000520 smsp += 7;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000521 break;
Daniel Willmann58c83d82009-08-13 03:40:49 +0200522 case GSM340_TP_VPF_NONE:
523 sms_vp = 0;
524 break;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000525 default:
526 DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n",
Harald Welte76042182009-08-08 16:03:15 +0200527 sms_vpf);
528 return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000529 }
Harald Welte76042182009-08-08 16:03:15 +0200530 gsms->user_data_len = *smsp++;
531 if (gsms->user_data_len) {
532 memcpy(gsms->user_data, smsp, gsms->user_data_len);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000533
Harald Welte76042182009-08-08 16:03:15 +0200534 switch (sms_alphabet) {
Harald Welte7e310b12009-03-30 20:56:32 +0000535 case DCS_7BIT_DEFAULT:
Harald Welte76042182009-08-08 16:03:15 +0200536 gsm_7bit_decode(gsms->text, smsp, gsms->user_data_len);
Harald Welte7e310b12009-03-30 20:56:32 +0000537 break;
538 case DCS_8BIT_DATA:
539 case DCS_UCS2:
540 case DCS_NONE:
Harald Welte7e310b12009-03-30 20:56:32 +0000541 break;
542 }
543 }
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000544
Harald Welte7e310b12009-03-30 20:56:32 +0000545 DEBUGP(DSMS, "SMS:\nMTI: 0x%02x, VPF: 0x%02x, MR: 0x%02x "
546 "PID: 0x%02x, DCS: 0x%02x, DA: %s, UserDataLength: 0x%02x "
Harald Welte76042182009-08-08 16:03:15 +0200547 "UserData: \"%s\"\n", sms_mti, sms_vpf, gsms->msg_ref,
548 gsms->protocol_id, gsms->data_coding_scheme,
549 gsms->dest_addr, gsms->user_data_len,
550 sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
551 hexdump(gsms->user_data, gsms->user_data_len));
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000552
Harald Welte76042182009-08-08 16:03:15 +0200553 gsms->sender = subscr_get(msg->lchan->subscr);
Holger Freyther9b177762009-02-16 19:07:18 +0000554
Harald Welte76042182009-08-08 16:03:15 +0200555 gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
Harald Welteb9c758b2009-07-05 14:02:46 +0200556
Harald Welte76042182009-08-08 16:03:15 +0200557 dispatch_signal(SS_SMS, 0, gsms);
Harald Welteb9c758b2009-07-05 14:02:46 +0200558
Harald Welte7e310b12009-03-30 20:56:32 +0000559 /* determine gsms->receiver based on dialled number */
Harald Welte76042182009-08-08 16:03:15 +0200560 gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr);
Harald Welte7e310b12009-03-30 20:56:32 +0000561 if (!gsms->receiver) {
562 rc = 1; /* cause 1: unknown subscriber */
563 goto out;
564 }
565
Harald Welte76042182009-08-08 16:03:15 +0200566 switch (sms_mti) {
Harald Welte7e310b12009-03-30 20:56:32 +0000567 case GSM340_SMS_SUBMIT_MS2SC:
568 /* MS is submitting a SMS */
Harald Welte76042182009-08-08 16:03:15 +0200569 rc = gsm340_rx_sms_submit(msg, gsms);
Harald Welte7e310b12009-03-30 20:56:32 +0000570 break;
571 case GSM340_SMS_COMMAND_MS2SC:
572 case GSM340_SMS_DELIVER_REP_MS2SC:
Harald Welte76042182009-08-08 16:03:15 +0200573 DEBUGP(DSMS, "Unimplemented MTI 0x%02x\n", sms_mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200574 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000575 break;
576 default:
Harald Welte76042182009-08-08 16:03:15 +0200577 DEBUGP(DSMS, "Undefined MTI 0x%02x\n", sms_mti);
Harald Welteb9c758b2009-07-05 14:02:46 +0200578 rc = GSM411_RP_CAUSE_IE_NOTEXIST;
Harald Welte7e310b12009-03-30 20:56:32 +0000579 break;
580 }
581
Harald Welteb9c758b2009-07-05 14:02:46 +0200582 if (!rc && !gsms->receiver)
583 rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
584
Harald Welte7e310b12009-03-30 20:56:32 +0000585out:
Harald Welte76042182009-08-08 16:03:15 +0200586 sms_free(gsms);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000587
Harald Welte7e310b12009-03-30 20:56:32 +0000588 return rc;
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000589}
590
Harald Weltef3efc592009-07-27 20:11:35 +0200591static int gsm411_send_rp_ack(struct gsm_trans *trans, u_int8_t msg_ref)
Daniel Willmann471712b2008-12-29 01:54:02 +0000592{
593 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000594
Daniel Willmann471712b2008-12-29 01:54:02 +0000595 DEBUGP(DSMS, "TX: SMS RP ACK\n");
596
Harald Weltef3efc592009-07-27 20:11:35 +0200597 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ACK_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000598}
599
Harald Weltef3efc592009-07-27 20:11:35 +0200600static int gsm411_send_rp_error(struct gsm_trans *trans,
601 u_int8_t msg_ref, u_int8_t cause)
Daniel Willmann471712b2008-12-29 01:54:02 +0000602{
603 struct msgb *msg = gsm411_msgb_alloc();
Daniel Willmann471712b2008-12-29 01:54:02 +0000604
Harald Welte7e310b12009-03-30 20:56:32 +0000605 msgb_tv_put(msg, 1, cause);
Daniel Willmann471712b2008-12-29 01:54:02 +0000606
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200607 DEBUGP(DSMS, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
608 get_value_string(rp_cause_strs, cause));
Daniel Willmann471712b2008-12-29 01:54:02 +0000609
Harald Weltef3efc592009-07-27 20:11:35 +0200610 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
Daniel Willmann471712b2008-12-29 01:54:02 +0000611}
612
Harald Welte7e310b12009-03-30 20:56:32 +0000613/* Receive a 04.11 TPDU inside RP-DATA / user data */
Harald Weltef3efc592009-07-27 20:11:35 +0200614static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
615 struct gsm411_rp_hdr *rph,
Harald Welte7e310b12009-03-30 20:56:32 +0000616 u_int8_t src_len, u_int8_t *src,
617 u_int8_t dst_len, u_int8_t *dst,
618 u_int8_t tpdu_len, u_int8_t *tpdu)
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000619{
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000620 int rc = 0;
621
Harald Welte7e310b12009-03-30 20:56:32 +0000622 if (src_len && src)
623 DEBUGP(DSMS, "RP-DATA (MO) with SRC ?!?\n");
624
625 if (!dst_len || !dst || !tpdu_len || !tpdu) {
626 DEBUGP(DSMS, "RP-DATA (MO) without DST or TPDU ?!?\n");
Harald Weltef3efc592009-07-27 20:11:35 +0200627 gsm411_send_rp_error(trans, rph->msg_ref,
Harald Welteb9c758b2009-07-05 14:02:46 +0200628 GSM411_RP_CAUSE_INV_MAND_INF);
Harald Welte7e310b12009-03-30 20:56:32 +0000629 return -EIO;
630 }
631 msg->smsh = tpdu;
632
633 DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
Harald Welte7e310b12009-03-30 20:56:32 +0000634
635 rc = gsm340_rx_tpdu(msg);
636 if (rc == 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200637 return gsm411_send_rp_ack(trans, rph->msg_ref);
Harald Welte7e310b12009-03-30 20:56:32 +0000638 else if (rc > 0)
Harald Weltef3efc592009-07-27 20:11:35 +0200639 return gsm411_send_rp_error(trans, rph->msg_ref, rc);
Harald Welte7e310b12009-03-30 20:56:32 +0000640 else
641 return rc;
642}
643
644/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
Harald Weltef3efc592009-07-27 20:11:35 +0200645static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
646 struct gsm411_rp_hdr *rph)
Harald Welte7e310b12009-03-30 20:56:32 +0000647{
648 u_int8_t src_len, dst_len, rpud_len;
649 u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
650
651 /* in the MO case, this should always be zero length */
652 src_len = rph->data[0];
653 if (src_len)
654 src = &rph->data[1];
655
656 dst_len = rph->data[1+src_len];
657 if (dst_len)
658 dst = &rph->data[1+src_len+1];
659
660 rpud_len = rph->data[1+src_len+1+dst_len];
661 if (rpud_len)
662 rp_ud = &rph->data[1+src_len+1+dst_len+1];
663
Harald Welteb9c758b2009-07-05 14:02:46 +0200664 DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
665 src_len, dst_len, rpud_len);
Harald Weltef3efc592009-07-27 20:11:35 +0200666 return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst,
Harald Welte7e310b12009-03-30 20:56:32 +0000667 rpud_len, rp_ud);
668}
669
Harald Weltecb8f4432009-08-09 14:59:02 +0200670/* Receive a 04.11 RP-ACK message (response to RP-DATA from us) */
Harald Weltef3efc592009-07-27 20:11:35 +0200671static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
672 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200673{
Harald Welte76042182009-08-08 16:03:15 +0200674 struct gsm_sms *sms = trans->sms.sms;
675
Harald Welteb9c758b2009-07-05 14:02:46 +0200676 /* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
677 * successfully received a SMS. We can now safely mark it as
678 * transmitted */
679
Harald Weltecb8f4432009-08-09 14:59:02 +0200680 if (!trans->sms.is_mt) {
681 DEBUGP(DSMS, "RX RP-ACK on a MO transfer ?\n");
682 return gsm411_send_rp_error(trans, rph->msg_ref,
683 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
684 }
Harald Welte3e0f6172009-07-09 23:52:59 +0200685
Harald Welte76042182009-08-08 16:03:15 +0200686 if (!sms) {
Harald Weltecb8f4432009-08-09 14:59:02 +0200687 DEBUGP(DSMS, "RX RP-ACK but no sms in transaction?!?\n");
688 return gsm411_send_rp_error(trans, rph->msg_ref,
689 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte76042182009-08-08 16:03:15 +0200690 }
691
692 /* mark this SMS as sent in database */
693 db_sms_mark_sent(sms);
694
695 dispatch_signal(SS_SMS, S_SMS_DELIVERED, sms);
696
697 sms_free(sms);
698 trans->sms.sms = NULL;
699
Sylvain Munaut6b0b1032009-09-27 11:16:22 +0200700 /* free the transaction here */
701 trans_free(trans);
Harald Weltecf6a3812009-08-09 19:07:41 +0200702
703 /* check for more messages for this subscriber */
704 sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr);
705 if (sms)
706 gsm411_send_sms_lchan(msg->lchan, sms);
707 else
Harald Welte (local)daef6062009-08-14 11:41:12 +0200708 rsl_release_request(msg->lchan, trans->sms.link_id);
Harald Welte76042182009-08-08 16:03:15 +0200709
710 return 0;
Harald Welteb9c758b2009-07-05 14:02:46 +0200711}
712
Harald Weltef3efc592009-07-27 20:11:35 +0200713static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
714 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200715{
Harald Welte76042182009-08-08 16:03:15 +0200716 struct gsm_sms *sms = trans->sms.sms;
Harald Weltef3efc592009-07-27 20:11:35 +0200717 u_int8_t cause_len = rph->data[0];
718 u_int8_t cause = rph->data[1];
719
Harald Welteb9c758b2009-07-05 14:02:46 +0200720 /* Error in response to MT RP_DATA, i.e. the MS did not
721 * successfully receive the SMS. We need to investigate
722 * the cause and take action depending on it */
723
Holger Hans Peter Freytherdc1e1052009-10-22 15:40:33 +0200724 DEBUGP(DSMS, "RX SMS RP-ERROR, cause %d:%d (%s)\n", cause_len, cause,
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200725 get_value_string(rp_cause_strs, cause));
Harald Weltef3efc592009-07-27 20:11:35 +0200726
Harald Weltecb8f4432009-08-09 14:59:02 +0200727 if (!trans->sms.is_mt) {
728 DEBUGP(DSMS, "RX RP-ERR on a MO transfer ?\n");
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200729#if 0
Harald Weltecb8f4432009-08-09 14:59:02 +0200730 return gsm411_send_rp_error(trans, rph->msg_ref,
731 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200732#endif
Harald Weltecb8f4432009-08-09 14:59:02 +0200733 }
Harald Welte3e0f6172009-07-09 23:52:59 +0200734
Harald Welte76042182009-08-08 16:03:15 +0200735 if (!sms) {
Harald Weltecb8f4432009-08-09 14:59:02 +0200736 DEBUGP(DSMS, "RX RP-ERR, but no sms in transaction?!?\n");
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200737 return -EINVAL;
738#if 0
Harald Weltecb8f4432009-08-09 14:59:02 +0200739 return gsm411_send_rp_error(trans, rph->msg_ref,
740 GSM411_RP_CAUSE_PROTOCOL_ERR);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200741#endif
Harald Weltecb8f4432009-08-09 14:59:02 +0200742 }
743
744 if (cause == GSM411_RP_CAUSE_MT_MEM_EXCEEDED) {
745 /* MS has not enough memory to store the message. We need
746 * to store this in our database and wati for a SMMA message */
747 /* FIXME */
748 dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr);
Harald Welte76042182009-08-08 16:03:15 +0200749 }
750
751 sms_free(sms);
752 trans->sms.sms = NULL;
753
Harald Welte (local)86b17172009-08-14 14:52:17 +0200754 //trans_free(trans);
Harald Welte76042182009-08-08 16:03:15 +0200755
Harald Weltef3efc592009-07-27 20:11:35 +0200756 return 0;
Harald Welteb9c758b2009-07-05 14:02:46 +0200757}
758
Harald Weltef3efc592009-07-27 20:11:35 +0200759static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans,
760 struct gsm411_rp_hdr *rph)
Harald Welteb9c758b2009-07-05 14:02:46 +0200761{
Harald Weltecf6a3812009-08-09 19:07:41 +0200762 struct gsm_sms *sms;
Harald Weltef3efc592009-07-27 20:11:35 +0200763 int rc;
764
Harald Weltecf6a3812009-08-09 19:07:41 +0200765 rc = gsm411_send_rp_ack(trans, rph->msg_ref);
766 trans->sms.rp_state = GSM411_RPS_IDLE;
767
Harald Welteb9c758b2009-07-05 14:02:46 +0200768 /* MS tells us that it has memory for more SMS, we need
769 * to check if we have any pending messages for it and then
770 * transfer those */
Harald Welte76042182009-08-08 16:03:15 +0200771 dispatch_signal(SS_SMS, S_SMS_SMMA, trans->subscr);
Harald Weltef3efc592009-07-27 20:11:35 +0200772
Harald Weltecf6a3812009-08-09 19:07:41 +0200773 /* check for more messages for this subscriber */
774 sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr);
775 if (sms)
776 gsm411_send_sms_lchan(msg->lchan, sms);
777 else
Harald Welte (local)daef6062009-08-14 11:41:12 +0200778 rsl_release_request(msg->lchan, trans->sms.link_id);
Harald Weltef3efc592009-07-27 20:11:35 +0200779
780 return rc;
Harald Welteb9c758b2009-07-05 14:02:46 +0200781}
782
Harald Weltef3efc592009-07-27 20:11:35 +0200783static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
784 struct gsm_trans *trans)
Harald Welte7e310b12009-03-30 20:56:32 +0000785{
Daniel Willmann471712b2008-12-29 01:54:02 +0000786 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000787 u_int8_t msg_type = rp_data->msg_type & 0x07;
Harald Welte7e310b12009-03-30 20:56:32 +0000788 int rc = 0;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000789
790 switch (msg_type) {
791 case GSM411_MT_RP_DATA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200792 DEBUGP(DSMS, "RX SMS RP-DATA (MO)\n");
793 /* start TR2N and enter 'wait to send RP-ACK state' */
794 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
795 rc = gsm411_rx_rp_data(msg, trans, rp_data);
Harald Welte7e310b12009-03-30 20:56:32 +0000796 break;
797 case GSM411_MT_RP_ACK_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200798 DEBUGP(DSMS,"RX SMS RP-ACK (MO)\n");
799 rc = gsm411_rx_rp_ack(msg, trans, rp_data);
Harald Welteb9c758b2009-07-05 14:02:46 +0200800 break;
Harald Welte7e310b12009-03-30 20:56:32 +0000801 case GSM411_MT_RP_SMMA_MO:
Harald Weltef3efc592009-07-27 20:11:35 +0200802 DEBUGP(DSMS, "RX SMS RP-SMMA\n");
803 /* start TR2N and enter 'wait to send RP-ACK state' */
804 trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
805 rc = gsm411_rx_rp_smma(msg, trans, rp_data);
806 break;
807 case GSM411_MT_RP_ERROR_MO:
808 rc = gsm411_rx_rp_error(msg, trans, rp_data);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000809 break;
810 default:
Harald Welte7e310b12009-03-30 20:56:32 +0000811 DEBUGP(DSMS, "Invalid RP type 0x%02x\n", msg_type);
Harald Weltef3efc592009-07-27 20:11:35 +0200812 rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
813 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000814 break;
815 }
816
817 return rc;
818}
819
Harald Weltef3efc592009-07-27 20:11:35 +0200820/* send CP-ACK to given transaction */
821static int gsm411_tx_cp_ack(struct gsm_trans *trans)
822{
823 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltecf6a3812009-08-09 19:07:41 +0200824 int rc;
Harald Weltef3efc592009-07-27 20:11:35 +0200825
Harald Weltecf6a3812009-08-09 19:07:41 +0200826 rc = gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ACK);
827
828 if (trans->sms.is_mt) {
829 /* If this is a MT SMS DELIVER, we can clear transaction here */
830 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Welte (local)86b17172009-08-14 14:52:17 +0200831 //trans_free(trans);
Harald Weltecf6a3812009-08-09 19:07:41 +0200832 }
Holger Hans Peter Freyther09e364b2009-08-10 07:59:27 +0200833
834 return rc;
Harald Weltef3efc592009-07-27 20:11:35 +0200835}
836
837static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
838{
839 struct msgb *msg = gsm411_msgb_alloc();
840 u_int8_t *causep;
841
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200842 DEBUGP(DSMS, "TX CP-ERROR, cause %d (%s)\n", cause,
843 get_value_string(cp_cause_strs, cause));
844
Harald Welte76042182009-08-08 16:03:15 +0200845 causep = msgb_put(msg, 1);
Harald Weltef3efc592009-07-27 20:11:35 +0200846 *causep = cause;
847
848 return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ERROR);
849}
850
851/* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */
Harald Welte (local)daef6062009-08-14 11:41:12 +0200852int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id)
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000853{
854 struct gsm48_hdr *gh = msgb_l3(msg);
855 u_int8_t msg_type = gh->msg_type;
Harald Weltef3efc592009-07-27 20:11:35 +0200856 u_int8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
857 struct gsm_lchan *lchan = msg->lchan;
858 struct gsm_trans *trans;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000859 int rc = 0;
860
Harald Weltef3efc592009-07-27 20:11:35 +0200861 if (!lchan->subscr)
862 return -EIO;
863 /* FIXME: send some error message */
864
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200865 DEBUGP(DSMS, "trans_id=%x ", gh->proto_discr >> 4);
Harald Weltef3efc592009-07-27 20:11:35 +0200866 trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS,
867 transaction_id);
868 if (!trans) {
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200869 DEBUGPC(DSMS, "(unknown) ");
Harald Weltef3efc592009-07-27 20:11:35 +0200870 trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
871 transaction_id, new_callref++);
872 if (!trans) {
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200873 DEBUGPC(DSMS, "No memory for trans\n");
Harald Weltef3efc592009-07-27 20:11:35 +0200874 /* FIXME: send some error message */
875 return -ENOMEM;
876 }
877 trans->sms.cp_state = GSM411_CPS_IDLE;
878 trans->sms.rp_state = GSM411_RPS_IDLE;
879 trans->sms.is_mt = 0;
Harald Welte (local)daef6062009-08-14 11:41:12 +0200880 trans->sms.link_id = link_id;
Harald Weltef3efc592009-07-27 20:11:35 +0200881
882 trans->lchan = lchan;
883 use_lchan(lchan);
884 }
885
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000886 switch(msg_type) {
887 case GSM411_MT_CP_DATA:
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200888 DEBUGPC(DSMS, "RX SMS CP-DATA\n");
Harald Weltecb8f4432009-08-09 14:59:02 +0200889 /* 5.2.3.1.3: MO state exists when SMC has received
890 * CP-DATA, including sending of the assoc. CP-ACK */
891 /* 5.2.3.2.4: MT state exists when SMC has received
892 * CP-DATA, including sending of the assoc. CP-ACK */
893 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Weltef3efc592009-07-27 20:11:35 +0200894
Harald Welte (local)daef6062009-08-14 11:41:12 +0200895 /* SMC instance acknowledges the CP-DATA frame */
896 gsm411_tx_cp_ack(trans);
897
Harald Weltef3efc592009-07-27 20:11:35 +0200898 rc = gsm411_rx_cp_data(msg, gh, trans);
Harald Welte (local)daef6062009-08-14 11:41:12 +0200899#if 0
Harald Weltef3efc592009-07-27 20:11:35 +0200900 /* Send CP-ACK or CP-ERORR in response */
901 if (rc < 0) {
902 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_NET_FAIL);
903 } else
904 rc = gsm411_tx_cp_ack(trans);
Harald Welte (local)daef6062009-08-14 11:41:12 +0200905#endif
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000906 break;
907 case GSM411_MT_CP_ACK:
Harald Weltef3efc592009-07-27 20:11:35 +0200908 /* previous CP-DATA in this transaction was confirmed */
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200909 DEBUGPC(DSMS, "RX SMS CP-ACK\n");
Harald Weltecb8f4432009-08-09 14:59:02 +0200910 /* 5.2.3.1.3: MO state exists when SMC has received CP-ACK */
911 /* 5.2.3.2.4: MT state exists when SMC has received CP-ACK */
912 trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
Harald Welte41985612009-08-10 00:24:32 +0200913 /* Stop TC1* after CP-ACK has been received */
914 bsc_del_timer(&trans->sms.cp_timer);
Harald Weltecb8f4432009-08-09 14:59:02 +0200915
Harald Weltef3efc592009-07-27 20:11:35 +0200916 if (!trans->sms.is_mt) {
Harald Weltef3efc592009-07-27 20:11:35 +0200917 /* FIXME: we have sont one CP-DATA, which was now
918 * acknowledged. Check if we want to transfer more,
919 * i.e. multi-part message */
920 trans->sms.cp_state = GSM411_CPS_IDLE;
921 trans_free(trans);
922 }
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000923 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000924 case GSM411_MT_CP_ERROR:
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200925 DEBUGPC(DSMS, "RX SMS CP-ERROR, cause %d (%s)\n", gh->data[0],
926 get_value_string(cp_cause_strs, gh->data[0]));
Harald Welte41985612009-08-10 00:24:32 +0200927 bsc_del_timer(&trans->sms.cp_timer);
Harald Weltef3efc592009-07-27 20:11:35 +0200928 trans->sms.cp_state = GSM411_CPS_IDLE;
929 trans_free(trans);
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000930 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000931 default:
Harald Welte (local)c89a5112009-08-14 10:42:43 +0200932 DEBUGPC(DSMS, "RX Unimplemented CP msg_type: 0x%02x\n", msg_type);
Harald Weltef3efc592009-07-27 20:11:35 +0200933 rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
Harald Weltecb8f4432009-08-09 14:59:02 +0200934 trans->sms.cp_state = GSM411_CPS_IDLE;
Harald Weltef3efc592009-07-27 20:11:35 +0200935 trans_free(trans);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000936 break;
937 }
938
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000939 return rc;
940}
941
Harald Welte8c2e36e2008-12-30 15:00:14 +0000942#if 0
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000943/* Test TPDU - ALL YOUR */
944static u_int8_t tpdu_test[] = {
945 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
946 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
947 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
948 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
Daniel Willmanne2a728d2008-12-30 14:03:09 +0000949};
Harald Welte8c2e36e2008-12-30 15:00:14 +0000950#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000951
Harald Weltecf6a3812009-08-09 19:07:41 +0200952/* Take a SMS in gsm_sms structure and send it through an already
953 * existing lchan. We also assume that the caller ensured this lchan already
954 * has a SAPI3 RLL connection! */
Harald Welte76042182009-08-08 16:03:15 +0200955int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000956{
957 struct msgb *msg = gsm411_msgb_alloc();
Harald Weltef3efc592009-07-27 20:11:35 +0200958 struct gsm_trans *trans;
Harald Welte76042182009-08-08 16:03:15 +0200959 u_int8_t *data, *rp_ud_len;
Harald Welte87f5d632009-07-04 17:39:00 +0200960 u_int8_t msg_ref = 42;
Harald Weltecf6a3812009-08-09 19:07:41 +0200961 u_int8_t transaction_id;
Harald Welte76042182009-08-08 16:03:15 +0200962 int rc;
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000963
Harald Weltecf6a3812009-08-09 19:07:41 +0200964 transaction_id = 4; /* FIXME: we always use 4 for now */
965
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000966 msg->lchan = lchan;
967
Harald Welte76042182009-08-08 16:03:15 +0200968 DEBUGP(DSMS, "send_sms_lchan()\n");
Harald Weltef3efc592009-07-27 20:11:35 +0200969
Harald Welte76042182009-08-08 16:03:15 +0200970 /* FIXME: allocate transaction with message reference */
971 trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
972 transaction_id, new_callref++);
973 if (!trans) {
974 DEBUGP(DSMS, "No memory for trans\n");
975 /* FIXME: send some error message */
976 return -ENOMEM;
977 }
978 trans->sms.cp_state = GSM411_CPS_IDLE;
979 trans->sms.rp_state = GSM411_RPS_IDLE;
980 trans->sms.is_mt = 1;
981 trans->sms.sms = sms;
Harald Welte (local)daef6062009-08-14 11:41:12 +0200982 trans->sms.link_id = UM_SAPI_SMS; /* FIXME: main or SACCH ? */
Harald Welte76042182009-08-08 16:03:15 +0200983
984 trans->lchan = lchan;
985 use_lchan(lchan);
986
987 /* Hardcode SMSC Originating Address for now */
Daniel Willmanna3e29842008-12-29 16:03:54 +0000988 data = (u_int8_t *)msgb_put(msg, 8);
Harald Welte87f5d632009-07-04 17:39:00 +0200989 data[0] = 0x07; /* originator length == 7 */
Harald Welteb9c758b2009-07-05 14:02:46 +0200990 data[1] = 0x91; /* type of number: international, ISDN */
991 data[2] = 0x44; /* 447785016005 */
Daniel Willmanna3e29842008-12-29 16:03:54 +0000992 data[3] = 0x77;
993 data[4] = 0x58;
994 data[5] = 0x10;
995 data[6] = 0x06;
996 data[7] = 0x50;
Harald Welte87f5d632009-07-04 17:39:00 +0200997
998 /* Hardcoded Destination Address */
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000999 data = (u_int8_t *)msgb_put(msg, 1);
Harald Welte87f5d632009-07-04 17:39:00 +02001000 data[0] = 0; /* destination length == 0 */
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001001
Harald Welte76042182009-08-08 16:03:15 +02001002 /* obtain a pointer for the rp_ud_len, so we can fill it later */
1003 rp_ud_len = (u_int8_t *)msgb_put(msg, 1);
Daniel Willmann4a1e8792008-12-29 06:23:56 +00001004
Harald Welte76042182009-08-08 16:03:15 +02001005#if 1
1006 /* generate the 03.40 TPDU */
1007 rc = gsm340_gen_tpdu(msg, sms);
1008 if (rc < 0) {
1009 msgb_free(msg);
1010 return rc;
1011 }
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001012
Harald Welte76042182009-08-08 16:03:15 +02001013 *rp_ud_len = rc;
1014#else
1015 data = msgb_put(msg, sizeof(tpdu_test));
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001016 memcpy(data, tpdu_test, sizeof(tpdu_test));
Harald Welte76042182009-08-08 16:03:15 +02001017 *rp_ud_len = sizeof(tpdu_test);
1018#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001019
Harald Welte76042182009-08-08 16:03:15 +02001020 DEBUGP(DSMS, "TX: SMS DELIVER\n");
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001021
Harald Weltef3efc592009-07-27 20:11:35 +02001022 return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
1023 /* FIXME: enter 'wait for RP-ACK' state, start TR1N */
Daniel Willmann6fe997e2008-12-29 04:20:41 +00001024}
Harald Weltef3efc592009-07-27 20:11:35 +02001025
Harald Weltecf6a3812009-08-09 19:07:41 +02001026/* RLL SAPI3 establish callback. Now we have a RLL connection and
1027 * can deliver the actual message */
Harald Weltecb8f4432009-08-09 14:59:02 +02001028static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
1029 void *_sms, enum bsc_rllr_ind type)
1030{
1031 struct gsm_sms *sms = _sms;
1032
1033 DEBUGP(DSMS, "rll_ind_cb(lchan=%p, link_id=%u, sms=%p, type=%u\n",
1034 lchan, link_id, sms, type);
1035
1036 switch (type) {
1037 case BSC_RLLR_IND_EST_CONF:
1038 gsm411_send_sms_lchan(lchan, sms);
1039 break;
1040 case BSC_RLLR_IND_REL_IND:
1041 case BSC_RLLR_IND_ERR_IND:
1042 case BSC_RLLR_IND_TIMEOUT:
1043 sms_free(sms);
1044 break;
1045 }
1046}
1047
Harald Weltecf6a3812009-08-09 19:07:41 +02001048/* paging callback. Here we get called if paging a subscriber has
1049 * succeeded or failed. */
Harald Welte76042182009-08-08 16:03:15 +02001050static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
1051 struct msgb *msg, void *_lchan, void *_sms)
Harald Weltef3efc592009-07-27 20:11:35 +02001052{
Harald Welte76042182009-08-08 16:03:15 +02001053 struct gsm_lchan *lchan = _lchan;
1054 struct gsm_sms *sms = _sms;
1055 int rc;
Harald Weltef3efc592009-07-27 20:11:35 +02001056
Harald Welte76042182009-08-08 16:03:15 +02001057 DEBUGP(DSMS, "paging_cb_send_sms(hooknum=%u, event=%u, msg=%p,"
1058 "lchan=%p, sms=%p)\n", hooknum, event, msg, lchan, sms);
1059
1060 if (hooknum != GSM_HOOK_RR_PAGING)
1061 return -EINVAL;
1062
1063 switch (event) {
1064 case GSM_PAGING_SUCCEEDED:
1065 /* Paging aborted without lchan ?!? */
1066 if (!lchan) {
1067 sms_free(sms);
1068 rc = -EIO;
1069 break;
1070 }
Harald Weltecf6a3812009-08-09 19:07:41 +02001071 /* Establish a SAPI3 RLL connection for SMS */
Harald Weltecb8f4432009-08-09 14:59:02 +02001072 rc = rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
Harald Welte76042182009-08-08 16:03:15 +02001073 break;
1074 case GSM_PAGING_EXPIRED:
1075 sms_free(sms);
1076 rc = -ETIMEDOUT;
1077 break;
1078 default:
1079 rc = -EINVAL;
1080 break;
1081 }
1082
1083 return rc;
1084}
1085
Harald Weltecf6a3812009-08-09 19:07:41 +02001086/* high-level function to send a SMS to a given subscriber. The function
1087 * will take care of paging the subscriber, establishing the RLL SAPI3
1088 * connection, etc. */
Harald Welte76042182009-08-08 16:03:15 +02001089int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
1090 struct gsm_sms *sms)
1091{
Harald Weltecf6a3812009-08-09 19:07:41 +02001092 struct gsm_lchan *lchan;
Harald Weltee903edf2009-08-15 03:16:17 +02001093 int rc;
Harald Weltecf6a3812009-08-09 19:07:41 +02001094
Harald Welte76042182009-08-08 16:03:15 +02001095 /* check if we already have an open lchan to the subscriber.
1096 * if yes, send the SMS this way */
Harald Weltecf6a3812009-08-09 19:07:41 +02001097 lchan = lchan_for_subscr(subscr);
1098 if (lchan)
1099 return rll_establish(lchan, UM_SAPI_SMS,
1100 rll_ind_cb, sms);
Harald Welte76042182009-08-08 16:03:15 +02001101
1102 /* if not, we have to start paging */
Harald Weltee903edf2009-08-15 03:16:17 +02001103 rc = paging_request(subscr->net, subscr, RSL_CHANNEED_SDCCH,
1104 paging_cb_send_sms, sms);
Harald Welte (local)0abaf332009-08-15 11:25:45 +02001105 if (rc <= 0)
Harald Weltee903edf2009-08-15 03:16:17 +02001106 sms_free(sms);
Harald Welte76042182009-08-08 16:03:15 +02001107
1108 return 0;
1109}
Harald Welte3366a942009-07-28 00:44:49 +02001110
Harald Weltecf6a3812009-08-09 19:07:41 +02001111static int subscr_sig_cb(unsigned int subsys, unsigned int signal,
1112 void *handler_data, void *signal_data)
1113{
1114 struct gsm_subscriber *subscr;
1115 struct gsm_lchan *lchan;
1116 struct gsm_sms *sms;
1117
1118 switch (signal) {
1119 case S_SUBSCR_ATTACHED:
1120 /* A subscriber has attached. Check if there are
1121 * any pending SMS for him to be delivered */
1122 subscr = signal_data;
1123 lchan = lchan_for_subscr(subscr);
1124 if (!lchan)
1125 break;
1126 sms = db_sms_get_unsent_for_subscr(subscr);
1127 if (!sms)
1128 break;
1129 /* Establish a SAPI3 RLL connection for SMS */
1130 rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
1131 break;
1132 default:
1133 break;
1134 }
1135 return 0;
1136}
1137
Harald Welte (local)86b17172009-08-14 14:52:17 +02001138void _gsm411_sms_trans_free(struct gsm_trans *trans)
1139{
1140 bsc_del_timer(&trans->sms.cp_timer);
1141}
1142
Harald Welte7bfc2672009-07-28 00:41:45 +02001143static __attribute__((constructor)) void on_dso_load_sms(void)
1144{
Harald Weltecf6a3812009-08-09 19:07:41 +02001145 register_signal_handler(SS_SUBSCR, subscr_sig_cb, NULL);
Harald Welte7bfc2672009-07-28 00:41:45 +02001146}