blob: ede89ef68e82853dd299beba1120cdeacd7cad50 [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>
39
Daniel Willmann471712b2008-12-29 01:54:02 +000040#define GSM411_ALLOC_SIZE 1024
41#define GSM411_ALLOC_HEADROOM 128
42
Holger Freythera553d092009-01-04 20:16:25 +000043struct msgb *gsm411_msgb_alloc(void)
Daniel Willmann471712b2008-12-29 01:54:02 +000044{
45 return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM);
46}
47
Holger Freythera553d092009-01-04 20:16:25 +000048int gsm0411_sendmsg(struct msgb *msg)
Daniel Willmann471712b2008-12-29 01:54:02 +000049{
50 if (msg->lchan)
51 msg->trx = msg->lchan->ts->trx;
52
53 msg->l3h = msg->data;
54
55 return rsl_data_request(msg, 0);
56}
57
Daniel Willmanne0fbec82008-12-29 00:44:41 +000058static char *gsm411_7bit_decode(u_int8_t *user_data, u_int8_t length)
59{
60 u_int8_t d_off = 0, b_off = 0;
61 u_int8_t i;
62 char *text = malloc(length+1);
63
64 for (i=0;i<length;i++) {
65 text[i] = ((user_data[d_off] + (user_data[d_off+1]<<8)) & (0x7f<<b_off))>>b_off;
66 b_off += 7;
67 if (b_off >= 8) {
68 d_off += 1;
69 b_off -= 8;
70 }
71 }
72 text[i] = 0;
73 return text;
74}
75
Daniel Willmann6fe997e2008-12-29 04:20:41 +000076static u_int8_t gsm0411_tpdu_from_sms(u_int8_t *tpdu, struct sms_deliver *sms)
77{
78 u_int8_t len = 0;
79
80}
81
Daniel Willmanne0fbec82008-12-29 00:44:41 +000082static int gsm411_sms_submit_from_msgb(struct msgb *msg)
83{
84 u_int8_t *smsp = msgb_sms(msg);
85 struct sms_submit *sms;
86
87 sms = malloc(sizeof(*sms));
88 sms->mti = *smsp & 0x03;
89 sms->mms = !!(*smsp & 0x04);
90 sms->vpf = (*smsp & 0x18) >> 3;
91 sms->sri = !!(*smsp & 0x20);
92 sms->udhi= !!(*smsp & 0x40);
93 sms->rp = !!(*smsp & 0x80);
94
95 smsp++;
96 sms->msg_ref = *smsp++;
97
98 /* Skip destination address for now */
99 smsp += 2 + *smsp/2 + *smsp%2;
100
101 sms->pid = *smsp++;
102 sms->dcs = *smsp++;
103 switch (sms->vpf)
104 {
105 case 2: /* relative */
106 sms->vp = *smsp++;
107 break;
108 default:
109 DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n",
110 sms->vpf);
111 }
112 sms->ud_len = *smsp++;
113
114 sms->user_data = gsm411_7bit_decode(smsp, sms->ud_len);
115
116 DEBUGP(DSMS, "SMS:\nMTI: 0x%02x, VPF: 0x%02x, MR: 0x%02x\n"
117 "PID: 0x%02x, DCS: 0x%02x, UserDataLength: 0x%02x\n"
118 "UserData: \"%s\"\n", sms->mti, sms->vpf, sms->msg_ref,
119 sms->pid, sms->dcs, sms->ud_len, sms->user_data);
120
121 free(sms);
122
123 return 0;
124}
125
Daniel Willmann9dfbf252008-12-29 03:24:29 +0000126static int gsm411_send_rp_ack(struct gsm_lchan *lchan, u_int8_t trans_id,
127 u_int8_t msg_ref)
Daniel Willmann471712b2008-12-29 01:54:02 +0000128{
129 struct msgb *msg = gsm411_msgb_alloc();
130 struct gsm48_hdr *gh;
131 struct gsm411_rp_hdr *rp;
132
133 msg->lchan = lchan;
134
135 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Daniel Willmannaecbbed2008-12-29 03:45:50 +0000136 // Outgoing needs the highest bit set
137 gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
138 gh->msg_type = GSM411_MT_CP_DATA;
Daniel Willmann471712b2008-12-29 01:54:02 +0000139
140 rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
Daniel Willmannaecbbed2008-12-29 03:45:50 +0000141 rp->len = 2;
Daniel Willmann471712b2008-12-29 01:54:02 +0000142 rp->msg_type = GSM411_MT_RP_ACK_MT;
143 rp->msg_ref = msg_ref;
144
145 DEBUGP(DSMS, "TX: SMS RP ACK\n");
146
147 return gsm0411_sendmsg(msg);
148}
149
Daniel Willmann9dfbf252008-12-29 03:24:29 +0000150static int gsm411_send_rp_error(struct gsm_lchan *lchan, u_int8_t trans_id,
151 u_int8_t msg_ref)
Daniel Willmann471712b2008-12-29 01:54:02 +0000152{
153 struct msgb *msg = gsm411_msgb_alloc();
154 struct gsm48_hdr *gh;
155 struct gsm411_rp_hdr *rp;
156
157 msg->lchan = lchan;
158
159 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
Daniel Willmannaecbbed2008-12-29 03:45:50 +0000160 // Outgoing needs the highest bit set
161 gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
162 gh->msg_type = GSM411_MT_CP_DATA;
Daniel Willmann471712b2008-12-29 01:54:02 +0000163
164 rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
165 rp->msg_type = GSM411_MT_RP_ERROR_MT;
166 rp->msg_ref = msg_ref;
167
168 DEBUGP(DSMS, "TX: SMS RP ERROR\n");
169
170 return gsm0411_sendmsg(msg);
171}
172
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000173static int gsm411_cp_data(struct msgb *msg)
174{
175 struct gsm48_hdr *gh = msgb_l3(msg);
176 int rc = 0;
177
Daniel Willmann471712b2008-12-29 01:54:02 +0000178 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000179 u_int8_t msg_type = rp_data->msg_type & 0x07;
180
181 switch (msg_type) {
182 case GSM411_MT_RP_DATA_MO:
Daniel Willmanne0fbec82008-12-29 00:44:41 +0000183 DEBUGP(DSMS, "SMS RP-DATA (MO)\n");
184 /* Skip SMSC no and RP-UD length */
185 msg->smsh = &rp_data->data[1] + rp_data->data[1] + 2;
186 gsm411_sms_submit_from_msgb(msg);
Daniel Willmann9dfbf252008-12-29 03:24:29 +0000187 gsm411_send_rp_ack(msg->lchan, (gh->proto_discr & 0xf0)>>4, rp_data->msg_ref);
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000188 break;
189 default:
190 DEBUGP(DSMS, "Unimplemented RP type 0x%02x\n", msg_type);
191 break;
192 }
193
194 return rc;
195}
196
197int gsm0411_rcv_sms(struct msgb *msg)
198{
199 struct gsm48_hdr *gh = msgb_l3(msg);
200 u_int8_t msg_type = gh->msg_type;
201 int rc = 0;
202
203 DEBUGP(DSMS, "SMS Message\n");
204
205 switch(msg_type) {
206 case GSM411_MT_CP_DATA:
207 DEBUGP(DSMS, "SMS CP-DATA\n");
208 rc = gsm411_cp_data(msg);
209 break;
210 case GSM411_MT_CP_ACK:
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000211 DEBUGP(DSMS, "SMS CP-ACK\n");
212 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000213 case GSM411_MT_CP_ERROR:
Daniel Willmannbb16e8e2008-12-29 03:53:50 +0000214 DEBUGP(DSMS, "SMS CP-ERROR, cause 0x%02x\n", gh->data[0]);
215 break;
Daniel Willmann8b3390e2008-12-28 00:31:09 +0000216 default:
217 DEBUGP(DSMS, "Unimplemented CP msg_type: 0x%02x\n", msg_type);
218 break;
219 }
220
221
222 return rc;
223}
224
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000225/* Test TPDU - 25c3 welcome */
Harald Welte8c2e36e2008-12-30 15:00:14 +0000226#if 0
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000227static u_int8_t tpdu_test[] = {
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000228 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x92, 0x90, 0x32,
229 0x24, 0x40, 0x4D, 0xB2, 0xDA, 0x70, 0xD6, 0x9A, 0x97, 0xE5, 0xF6, 0xF4,
230 0xB8, 0x0C, 0x0A, 0xBB, 0xDD, 0xEF, 0xBA, 0x7B, 0x5C, 0x6E, 0x97, 0xDD,
231 0x74, 0x1D, 0x08, 0xCA, 0x2E, 0x87, 0xE7, 0x65, 0x50, 0x98, 0x4E, 0x2F,
232 0xBB, 0xC9, 0x20, 0x3A, 0xBA, 0x0C, 0x3A, 0x4E, 0x9B, 0x20, 0x7A, 0x98,
233 0xBD, 0x06, 0x85, 0xE9, 0xA0, 0x58, 0x4C, 0x37, 0x83, 0x81, 0xD2, 0x6E,
234 0xD0, 0x34, 0x1C, 0x66, 0x83, 0x62, 0x21, 0x90, 0xAE, 0x95, 0x02
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000235};
Harald Welte8c2e36e2008-12-30 15:00:14 +0000236#else
Daniel Willmann3b3f0012008-12-30 13:56:46 +0000237/* Test TPDU - ALL YOUR */
238static u_int8_t tpdu_test[] = {
239 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
240 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
241 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
242 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
Daniel Willmanne2a728d2008-12-30 14:03:09 +0000243};
Harald Welte8c2e36e2008-12-30 15:00:14 +0000244#endif
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000245
246int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms)
247{
248 struct msgb *msg = gsm411_msgb_alloc();
249 struct gsm48_hdr *gh;
250 struct gsm411_rp_hdr *rp;
251 u_int8_t *data, *tpdu, smslen;
252
253 msg->lchan = lchan;
254
255 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
256 gh->proto_discr = GSM48_PDISC_SMS;
257 gh->msg_type = GSM411_MT_CP_DATA;
258
259 rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
Daniel Willmanna3e29842008-12-29 16:03:54 +0000260 rp->len = sizeof(tpdu_test) + 10;
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000261 rp->msg_type = GSM411_MT_RP_DATA_MT;
262 rp->msg_ref = 42; /* FIXME: Choose randomly */
Daniel Willmannfad5d0d2008-12-29 16:04:14 +0000263 /* Hardcode OA for now */
Daniel Willmanna3e29842008-12-29 16:03:54 +0000264 data = (u_int8_t *)msgb_put(msg, 8);
265 data[0] = 0x07;
266 data[1] = 0x91;
267 data[2] = 0x44;
268 data[3] = 0x77;
269 data[4] = 0x58;
270 data[5] = 0x10;
271 data[6] = 0x06;
272 data[7] = 0x50;
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000273 data = (u_int8_t *)msgb_put(msg, 1);
274 data[0] = 0;
275
276 /* FIXME: Hardcoded for now */
Daniel Willmann4a1e8792008-12-29 06:23:56 +0000277 //smslen = gsm0411_tpdu_from_sms(tpdu, sms);
278
279 /* RPDU length */
280 data = (u_int8_t *)msgb_put(msg, 1);
281 data[0] = sizeof(tpdu_test);
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000282
283 data = (u_int8_t *)msgb_put(msg, sizeof(tpdu_test));
284
285 //memcpy(data, tpdu, smslen);
286 memcpy(data, tpdu_test, sizeof(tpdu_test));
287
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000288 DEBUGP(DSMS, "TX: SMS SUBMIT\n");
289
290 return gsm0411_sendmsg(msg);
291}
292