blob: a7b603e11cbc99cdaaf1a9fc723ccdc6fb174a95 [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>
6 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <errno.h>
30#include <netinet/in.h>
31
32#include <openbsc/msgb.h>
33#include <openbsc/debug.h>
Daniel Willmann471712b2008-12-29 01:54:02 +000034#include <openbsc/gsm_data.h>
35#include <openbsc/gsm_subscriber.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000036#include <openbsc/gsm_04_11.h>
37#include <openbsc/gsm_04_08.h>
38#include <openbsc/abis_rsl.h>
Holger Freyther9b177762009-02-16 19:07:18 +000039#include <openbsc/signal.h>
Daniel Willmann8b3390e2008-12-28 00:31:09 +000040
Daniel Willmann471712b2008-12-29 01:54:02 +000041#define GSM411_ALLOC_SIZE 1024
42#define GSM411_ALLOC_HEADROOM 128
43
Holger Freythera553d092009-01-04 20:16:25 +000044struct msgb *gsm411_msgb_alloc(void)
Daniel Willmann471712b2008-12-29 01:54:02 +000045{
46 return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM);
47}
48
Holger Freythera553d092009-01-04 20:16:25 +000049int gsm0411_sendmsg(struct msgb *msg)
Daniel Willmann471712b2008-12-29 01:54:02 +000050{
51 if (msg->lchan)
52 msg->trx = msg->lchan->ts->trx;
53
54 msg->l3h = msg->data;
55
56 return rsl_data_request(msg, 0);
57}
58
Daniel Willmanne0fbec82008-12-29 00:44:41 +000059static char *gsm411_7bit_decode(u_int8_t *user_data, u_int8_t length)
60{
61 u_int8_t d_off = 0, b_off = 0;
62 u_int8_t i;
63 char *text = malloc(length+1);
64
65 for (i=0;i<length;i++) {
66 text[i] = ((user_data[d_off] + (user_data[d_off+1]<<8)) & (0x7f<<b_off))>>b_off;
67 b_off += 7;
68 if (b_off >= 8) {
69 d_off += 1;
70 b_off -= 8;
71 }
72 }
73 text[i] = 0;
74 return text;
75}
76
Holger Freytherca362a62009-01-04 21:05:01 +000077#if 0
Daniel Willmann6fe997e2008-12-29 04:20:41 +000078static u_int8_t gsm0411_tpdu_from_sms(u_int8_t *tpdu, struct sms_deliver *sms)
79{
Daniel Willmann6fe997e2008-12-29 04:20:41 +000080}
Holger Freytherca362a62009-01-04 21:05:01 +000081#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +000082
Daniel Willmanne0fbec82008-12-29 00:44:41 +000083static int gsm411_sms_submit_from_msgb(struct msgb *msg)
84{
85 u_int8_t *smsp = msgb_sms(msg);
86 struct sms_submit *sms;
87
88 sms = malloc(sizeof(*sms));
89 sms->mti = *smsp & 0x03;
90 sms->mms = !!(*smsp & 0x04);
91 sms->vpf = (*smsp & 0x18) >> 3;
92 sms->sri = !!(*smsp & 0x20);
93 sms->udhi= !!(*smsp & 0x40);
94 sms->rp = !!(*smsp & 0x80);
95
96 smsp++;
97 sms->msg_ref = *smsp++;
98
99 /* Skip destination address for now */
100 smsp += 2 + *smsp/2 + *smsp%2;
101
102 sms->pid = *smsp++;
103 sms->dcs = *smsp++;
104 switch (sms->vpf)
105 {
106 case 2: /* relative */
107 sms->vp = *smsp++;
108 break;
109 default:
110 DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n",
111 sms->vpf);
112 }
113 sms->ud_len = *smsp++;
114
Holger Freytherca362a62009-01-04 21:05:01 +0000115 sms->user_data = (u_int8_t *)gsm411_7bit_decode(smsp, sms->ud_len);
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000116
117 DEBUGP(DSMS, "SMS:\nMTI: 0x%02x, VPF: 0x%02x, MR: 0x%02x\n"
118 "PID: 0x%02x, DCS: 0x%02x, UserDataLength: 0x%02x\n"
119 "UserData: \"%s\"\n", sms->mti, sms->vpf, sms->msg_ref,
120 sms->pid, sms->dcs, sms->ud_len, sms->user_data);
121
Harald Welte595ad7b2009-02-16 22:05:44 +0000122 dispatch_signal(SS_SMS, 0, sms);
Holger Freyther9b177762009-02-16 19:07:18 +0000123
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000124 free(sms);
125
126 return 0;
127}
128
Daniel Willmann9dfbf252008-12-29 03:24:29 +0000129static int gsm411_send_rp_ack(struct gsm_lchan *lchan, u_int8_t trans_id,
130 u_int8_t msg_ref)
Daniel Willmann471712b2008-12-29 01:54:02 +0000131{
132 struct msgb *msg = gsm411_msgb_alloc();
133 struct gsm48_hdr *gh;
134 struct gsm411_rp_hdr *rp;
135
136 msg->lchan = lchan;
137
138 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Daniel Willmannaecbbed2008-12-29 03:45:50 +0000139 // Outgoing needs the highest bit set
140 gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
141 gh->msg_type = GSM411_MT_CP_DATA;
Daniel Willmann471712b2008-12-29 01:54:02 +0000142
143 rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
Daniel Willmannaecbbed2008-12-29 03:45:50 +0000144 rp->len = 2;
Daniel Willmann471712b2008-12-29 01:54:02 +0000145 rp->msg_type = GSM411_MT_RP_ACK_MT;
146 rp->msg_ref = msg_ref;
147
148 DEBUGP(DSMS, "TX: SMS RP ACK\n");
149
150 return gsm0411_sendmsg(msg);
151}
152
Holger Freytherca362a62009-01-04 21:05:01 +0000153#if 0
Daniel Willmann9dfbf252008-12-29 03:24:29 +0000154static int gsm411_send_rp_error(struct gsm_lchan *lchan, u_int8_t trans_id,
155 u_int8_t msg_ref)
Daniel Willmann471712b2008-12-29 01:54:02 +0000156{
157 struct msgb *msg = gsm411_msgb_alloc();
158 struct gsm48_hdr *gh;
159 struct gsm411_rp_hdr *rp;
160
161 msg->lchan = lchan;
162
163 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Daniel Willmannaecbbed2008-12-29 03:45:50 +0000164 // Outgoing needs the highest bit set
165 gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
166 gh->msg_type = GSM411_MT_CP_DATA;
Daniel Willmann471712b2008-12-29 01:54:02 +0000167
168 rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
169 rp->msg_type = GSM411_MT_RP_ERROR_MT;
170 rp->msg_ref = msg_ref;
171
172 DEBUGP(DSMS, "TX: SMS RP ERROR\n");
173
174 return gsm0411_sendmsg(msg);
175}
Holger Freytherca362a62009-01-04 21:05:01 +0000176#endif
Daniel Willmann471712b2008-12-29 01:54:02 +0000177
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000178static int gsm411_cp_data(struct msgb *msg)
179{
180 struct gsm48_hdr *gh = msgb_l3(msg);
181 int rc = 0;
182
Daniel Willmann471712b2008-12-29 01:54:02 +0000183 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000184 u_int8_t msg_type = rp_data->msg_type & 0x07;
185
186 switch (msg_type) {
187 case GSM411_MT_RP_DATA_MO:
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000188 DEBUGP(DSMS, "SMS RP-DATA (MO)\n");
189 /* Skip SMSC no and RP-UD length */
190 msg->smsh = &rp_data->data[1] + rp_data->data[1] + 2;
191 gsm411_sms_submit_from_msgb(msg);
Daniel Willmann9dfbf252008-12-29 03:24:29 +0000192 gsm411_send_rp_ack(msg->lchan, (gh->proto_discr & 0xf0)>>4, rp_data->msg_ref);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000193 break;
194 default:
195 DEBUGP(DSMS, "Unimplemented RP type 0x%02x\n", msg_type);
196 break;
197 }
198
199 return rc;
200}
201
202int gsm0411_rcv_sms(struct msgb *msg)
203{
204 struct gsm48_hdr *gh = msgb_l3(msg);
205 u_int8_t msg_type = gh->msg_type;
206 int rc = 0;
207
208 DEBUGP(DSMS, "SMS Message\n");
209
210 switch(msg_type) {
211 case GSM411_MT_CP_DATA:
212 DEBUGP(DSMS, "SMS CP-DATA\n");
213 rc = gsm411_cp_data(msg);
214 break;
215 case GSM411_MT_CP_ACK:
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000216 DEBUGP(DSMS, "SMS CP-ACK\n");
217 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000218 case GSM411_MT_CP_ERROR:
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000219 DEBUGP(DSMS, "SMS CP-ERROR, cause 0x%02x\n", gh->data[0]);
220 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000221 default:
222 DEBUGP(DSMS, "Unimplemented CP msg_type: 0x%02x\n", msg_type);
223 break;
224 }
225
226
227 return rc;
228}
229
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000230/* Test TPDU - 25c3 welcome */
Harald Welte8c2e36e2008-12-30 15:00:14 +0000231#if 0
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000232static u_int8_t tpdu_test[] = {
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000233 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x92, 0x90, 0x32,
234 0x24, 0x40, 0x4D, 0xB2, 0xDA, 0x70, 0xD6, 0x9A, 0x97, 0xE5, 0xF6, 0xF4,
235 0xB8, 0x0C, 0x0A, 0xBB, 0xDD, 0xEF, 0xBA, 0x7B, 0x5C, 0x6E, 0x97, 0xDD,
236 0x74, 0x1D, 0x08, 0xCA, 0x2E, 0x87, 0xE7, 0x65, 0x50, 0x98, 0x4E, 0x2F,
237 0xBB, 0xC9, 0x20, 0x3A, 0xBA, 0x0C, 0x3A, 0x4E, 0x9B, 0x20, 0x7A, 0x98,
238 0xBD, 0x06, 0x85, 0xE9, 0xA0, 0x58, 0x4C, 0x37, 0x83, 0x81, 0xD2, 0x6E,
239 0xD0, 0x34, 0x1C, 0x66, 0x83, 0x62, 0x21, 0x90, 0xAE, 0x95, 0x02
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000240};
Harald Welte8c2e36e2008-12-30 15:00:14 +0000241#else
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000242/* Test TPDU - ALL YOUR */
243static u_int8_t tpdu_test[] = {
244 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
245 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
246 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
247 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
Daniel Willmanne2a728d2008-12-30 14:03:09 +0000248};
Harald Welte8c2e36e2008-12-30 15:00:14 +0000249#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000250
251int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms)
252{
253 struct msgb *msg = gsm411_msgb_alloc();
254 struct gsm48_hdr *gh;
255 struct gsm411_rp_hdr *rp;
Holger Freytherca362a62009-01-04 21:05:01 +0000256 u_int8_t *data;
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000257
258 msg->lchan = lchan;
259
260 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
261 gh->proto_discr = GSM48_PDISC_SMS;
262 gh->msg_type = GSM411_MT_CP_DATA;
263
264 rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
Daniel Willmanna3e29842008-12-29 16:03:54 +0000265 rp->len = sizeof(tpdu_test) + 10;
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000266 rp->msg_type = GSM411_MT_RP_DATA_MT;
267 rp->msg_ref = 42; /* FIXME: Choose randomly */
Daniel Willmannfad5d0d2008-12-29 16:04:14 +0000268 /* Hardcode OA for now */
Daniel Willmanna3e29842008-12-29 16:03:54 +0000269 data = (u_int8_t *)msgb_put(msg, 8);
270 data[0] = 0x07;
271 data[1] = 0x91;
272 data[2] = 0x44;
273 data[3] = 0x77;
274 data[4] = 0x58;
275 data[5] = 0x10;
276 data[6] = 0x06;
277 data[7] = 0x50;
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000278 data = (u_int8_t *)msgb_put(msg, 1);
279 data[0] = 0;
280
281 /* FIXME: Hardcoded for now */
Daniel Willmann4a1e8792008-12-29 06:23:56 +0000282 //smslen = gsm0411_tpdu_from_sms(tpdu, sms);
283
284 /* RPDU length */
285 data = (u_int8_t *)msgb_put(msg, 1);
286 data[0] = sizeof(tpdu_test);
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000287
288 data = (u_int8_t *)msgb_put(msg, sizeof(tpdu_test));
289
290 //memcpy(data, tpdu, smslen);
291 memcpy(data, tpdu_test, sizeof(tpdu_test));
292
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000293 DEBUGP(DSMS, "TX: SMS SUBMIT\n");
294
295 return gsm0411_sendmsg(msg);
296}
297