blob: 9c3cafd292c08cdad36a956fda34a98b075e686c [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
43static struct msgb *gsm411_msgb_alloc(void)
44{
45 return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM);
46}
47
48static int gsm0411_sendmsg(struct msgb *msg)
49{
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 Willmann6fe997e2008-12-29 04:20:41 +0000225/* Test TPDU */
226static u_int8_t tpdu_test[] = {
227 0x00, 0x01, 0x00, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x24, 0xD7, 0x32, 0x7B, 0xFC, 0x6E, 0x97, 0x41, 0xF4, 0x37, 0x88, 0x8E, 0x2E, 0x83, 0x64, 0xB5, 0xE1, 0x0C, 0x74, 0x9C, 0x36, 0x41, 0xF4, 0xF2, 0x9C, 0x0E, 0x72, 0x97, 0xE9, 0xF7, 0xB7, 0x7C, 0x0D
228};
Daniel Willmanna3e29842008-12-29 16:03:54 +0000229/* Alternative TPDU 040DD0F334FC1CA6970100008080312170224008D4F29CDE0EA7D9 */
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000230
231int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms)
232{
233 struct msgb *msg = gsm411_msgb_alloc();
234 struct gsm48_hdr *gh;
235 struct gsm411_rp_hdr *rp;
236 u_int8_t *data, *tpdu, smslen;
237
238 msg->lchan = lchan;
239
240 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
241 gh->proto_discr = GSM48_PDISC_SMS;
242 gh->msg_type = GSM411_MT_CP_DATA;
243
244 rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
Daniel Willmanna3e29842008-12-29 16:03:54 +0000245 rp->len = sizeof(tpdu_test) + 10;
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000246 rp->msg_type = GSM411_MT_RP_DATA_MT;
247 rp->msg_ref = 42; /* FIXME: Choose randomly */
248 /* No OA or DA for now */
Daniel Willmanna3e29842008-12-29 16:03:54 +0000249 data = (u_int8_t *)msgb_put(msg, 8);
250 data[0] = 0x07;
251 data[1] = 0x91;
252 data[2] = 0x44;
253 data[3] = 0x77;
254 data[4] = 0x58;
255 data[5] = 0x10;
256 data[6] = 0x06;
257 data[7] = 0x50;
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000258 data = (u_int8_t *)msgb_put(msg, 1);
259 data[0] = 0;
260
261 /* FIXME: Hardcoded for now */
Daniel Willmann4a1e8792008-12-29 06:23:56 +0000262 //smslen = gsm0411_tpdu_from_sms(tpdu, sms);
263
264 /* RPDU length */
265 data = (u_int8_t *)msgb_put(msg, 1);
266 data[0] = sizeof(tpdu_test);
Daniel Willmann6fe997e2008-12-29 04:20:41 +0000267
268 data = (u_int8_t *)msgb_put(msg, sizeof(tpdu_test));
269
270 //memcpy(data, tpdu, smslen);
271 memcpy(data, tpdu_test, sizeof(tpdu_test));
272
273 free(tpdu);
274
275 DEBUGP(DSMS, "TX: SMS SUBMIT\n");
276
277 return gsm0411_sendmsg(msg);
278}
279