sms: SMS where cropped (from VTY), concatenation of SMS where not possible
[osmocom-bb.git] / tests / sms / sms_test.c
1 /*
2  * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
3  * (C) 2010 by Nico Golde <nico@ngolde.de>
4  * All Rights Reserved
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <osmocom/core/msgb.h>
26 #include <osmocom/gsm/gsm_utils.h>
27 #include <osmocom/core/utils.h>
28
29 struct test_case {
30         const uint8_t *input;
31         const uint16_t input_length;
32
33         const uint8_t *expected;
34         const uint16_t expected_octet_length;
35         const uint16_t expected_septet_length;
36         const uint8_t ud_hdr_ind;
37 };
38
39 static const char simple_text[] = "test text";
40 #define simple_septet_length 9
41 static const uint8_t simple_enc[] = {
42         0xf4, 0xf2, 0x9c, 0x0e, 0xa2, 0x97, 0xf1, 0x74
43 };
44
45 static const char escape_text[] = "!$ a more#^- complicated test@@?_%! case";
46 #define escape_septet_length 41 /* note: the ^ counts as two, because it is a extension character */
47 static const uint8_t escape_enc[] = {
48         0x21, 0x01, 0x28, 0x0c, 0x6a, 0xbf, 0xe5, 0xe5, 0xd1,
49         0x86, 0xd2, 0x02, 0x8d, 0xdf, 0x6d, 0x38, 0x3b, 0x3d,
50         0x0e, 0xd3, 0xcb, 0x64, 0x10, 0xbd, 0x3c, 0xa7, 0x03,
51         0x00, 0xbf, 0x48, 0x29, 0x04, 0x1a, 0x87, 0xe7, 0x65,
52 };
53
54 static const char enhanced_text[] = "enhanced ^ {][} test |+~ ^ test";
55 #define enhanced_septet_length 39 /* note: the characters { } [ ] ^ | ~ count as two (each of them), because they are extension characters */
56 static const uint8_t enhanced_enc[] = {
57         0x65, 0x37, 0x3A, 0xEC, 0x1E, 0x97, 0xC9, 0xA0, 0x0D,
58         0x05, 0xB4, 0x41, 0x6D, 0x7C, 0x1B, 0xDE, 0x26, 0x05,
59         0xA2, 0x97, 0xE7, 0x74, 0xD0, 0x06, 0xB8, 0xDA, 0xF4,
60         0x40, 0x1B, 0x0A, 0x88, 0x5E, 0x9E, 0xD3, 0x01,
61 };
62
63 static const char enhancedV2_text[] = "enhanced ^ {][} test |+~ ^ tests";
64 #define enhancedV2_septet_length 40 /* note: number of octets are equal to the enhanced_text! */
65 static const uint8_t enhancedV2_enc[] = {
66         0x65, 0x37, 0x3A, 0xEC, 0x1E, 0x97, 0xC9, 0xA0, 0x0D,
67         0x05, 0xB4, 0x41, 0x6D, 0x7C, 0x1B, 0xDE, 0x26, 0x05,
68         0xA2, 0x97, 0xE7, 0x74, 0xD0, 0x06, 0xB8, 0xDA, 0xF4,
69         0x40, 0x1B, 0x0A, 0x88, 0x5E, 0x9E, 0xD3, 0xE7,
70 };
71
72
73
74 static const char concatenated_text[] =
75                 "this is a testmessage. this is a testmessage. this is a testmessage. this is a testmessage. "
76                 "this is a testmessage. this is a testmessage. cut here .....: this is a second testmessage. end here.";
77
78 static const char splitted_text_part1[] =
79                 "this is a testmessage. this is a testmessage. this is a testmessage. this is a testmessage. "
80                 "this is a testmessage. this is a testmessage. cut here .....:";
81 #define concatenated_part1_septet_length_with_header 160
82 #define concatenated_part1_septet_length 153
83 static const uint8_t concatenated_part1_enc[] = {
84                 0x05, 0x00, 0x03, 0x6f, 0x02, 0x01,
85                 0xe8, 0xe8, 0xf4, 0x1c, 0x94, 0x9e, 0x83, 0xc2,
86                 0x20, 0x7a, 0x79, 0x4e, 0x6f, 0x97, 0xe7, 0xf3,
87                 0xf0, 0xb9, 0xec, 0x02, 0xd1, 0xd1, 0xe9, 0x39,
88                 0x28, 0x3d, 0x07, 0x85, 0x41, 0xf4, 0xf2, 0x9c,
89                 0xde, 0x2e, 0xcf, 0xe7, 0xe1, 0x73, 0xd9, 0x05,
90                 0xa2, 0xa3, 0xd3, 0x73, 0x50, 0x7a, 0x0e, 0x0a,
91                 0x83, 0xe8, 0xe5, 0x39, 0xbd, 0x5d, 0x9e, 0xcf,
92                 0xc3, 0xe7, 0xb2, 0x0b, 0x44, 0x47, 0xa7, 0xe7,
93                 0xa0, 0xf4, 0x1c, 0x14, 0x06, 0xd1, 0xcb, 0x73,
94                 0x7a, 0xbb, 0x3c, 0x9f, 0x87, 0xcf, 0x65, 0x17,
95                 0x88, 0x8e, 0x4e, 0xcf, 0x41, 0xe9, 0x39, 0x28,
96                 0x0c, 0xa2, 0x97, 0xe7, 0xf4, 0x76, 0x79, 0x3e,
97                 0x0f, 0x9f, 0xcb, 0x2e, 0x10, 0x1d, 0x9d, 0x9e,
98                 0x83, 0xd2, 0x73, 0x50, 0x18, 0x44, 0x2f, 0xcf,
99                 0xe9, 0xed, 0xf2, 0x7c, 0x1e, 0x3e, 0x97, 0x5d,
100                 0xa0, 0x71, 0x9d, 0x0e, 0x42, 0x97, 0xe5, 0x65,
101                 0x90, 0xcb, 0xe5, 0x72, 0xb9, 0x74,
102 };
103
104 static const char splitted_text_part2[] = " this is a second testmessage. end here.";
105 #define concatenated_part2_septet_length_with_header 47
106 #define concatenated_part2_septet_length 40
107 static const uint8_t concatenated_part2_enc[] = {
108                 0x05, 0x00, 0x03, 0x6f, 0x02, 0x02,
109                 0x40, 0x74, 0x74, 0x7a, 0x0e, 0x4a, 0xcf, 0x41,
110                 0x61, 0xd0, 0xbc, 0x3c, 0x7e, 0xbb, 0xc9, 0x20,
111                 0x7a, 0x79, 0x4e, 0x6f, 0x97, 0xe7, 0xf3, 0xf0,
112                 0xb9, 0xec, 0x02, 0x95, 0xdd, 0x64, 0x10, 0xba,
113                 0x2c, 0x2f, 0xbb, 0x00,
114 };
115
116 static const struct test_case test_multiple_encode[] =
117 {
118         {
119                 .input = concatenated_text,
120                 .expected = concatenated_part1_enc,
121                 .expected_octet_length = sizeof(concatenated_part1_enc),
122                 .expected_septet_length = concatenated_part1_septet_length,
123                 .ud_hdr_ind = 1,
124         },
125         {
126                 .input = concatenated_text,
127                 .expected = concatenated_part2_enc,
128                 .expected_octet_length = sizeof(concatenated_part2_enc),
129                 .expected_septet_length = concatenated_part2_septet_length,
130                 .ud_hdr_ind = 1,
131         },
132 };
133
134 static const struct test_case test_encode[] =
135 {
136         {
137                 .input = simple_text,
138                 .expected = simple_enc,
139                 .expected_octet_length = sizeof(simple_enc),
140                 .expected_septet_length = simple_septet_length,
141                 .ud_hdr_ind = 0,
142         },
143         {
144                 .input = escape_text,
145                 .expected = escape_enc,
146                 .expected_octet_length = sizeof(escape_enc),
147                 .expected_septet_length = escape_septet_length,
148                 .ud_hdr_ind = 0,
149         },
150         {
151                 .input = enhanced_text,
152                 .expected = enhanced_enc,
153                 .expected_octet_length = sizeof(enhanced_enc),
154                 .expected_septet_length = enhanced_septet_length,
155                 .ud_hdr_ind = 0,
156         },
157         {
158                 .input = enhancedV2_text,
159                 .expected = enhancedV2_enc,
160                 .expected_octet_length = sizeof(enhancedV2_enc),
161                 .expected_septet_length = enhancedV2_septet_length,
162                 .ud_hdr_ind = 0,
163         },
164 };
165
166 static const struct test_case test_decode[] =
167 {
168         {
169                 .input = simple_enc,
170                 .input_length = sizeof(simple_enc),
171                 .expected = simple_text,
172                 .expected_septet_length = simple_septet_length,
173                 .ud_hdr_ind = 0,
174         },
175         {
176                 .input = escape_enc,
177                 .input_length = sizeof(escape_enc),
178                 .expected = escape_text,
179                 .expected_septet_length = escape_septet_length,
180                 .ud_hdr_ind = 0,
181         },
182         {
183                 .input = enhanced_enc,
184                 .input_length = sizeof(enhanced_enc),
185                 .expected = enhanced_text,
186                 .expected_septet_length = enhanced_septet_length,
187                 .ud_hdr_ind = 0,
188         },
189         {
190                 .input = enhancedV2_enc,
191                 .input_length = sizeof(enhancedV2_enc),
192                 .expected = enhancedV2_text,
193                 .expected_septet_length = enhancedV2_septet_length,
194                 .ud_hdr_ind = 0,
195         },
196         {
197                 .input = concatenated_part1_enc,
198                 .input_length = sizeof(concatenated_part1_enc),
199                 .expected = splitted_text_part1,
200                 .expected_septet_length = concatenated_part1_septet_length_with_header,
201                 .ud_hdr_ind = 1,
202         },
203         {
204                 .input = concatenated_part2_enc,
205                 .input_length = sizeof(concatenated_part2_enc),
206                 .expected = splitted_text_part2,
207                 .expected_septet_length = concatenated_part2_septet_length_with_header,
208                 .ud_hdr_ind = 1,
209         },
210 };
211
212 int main(int argc, char** argv)
213 {
214         printf("SMS testing\n");
215         struct msgb *msg;
216         uint8_t i;
217
218         uint8_t octet_length;
219         uint8_t septet_length;
220         uint8_t gsm_septet_length;
221         uint8_t coded[256];
222         uint8_t tmp[160];
223         uint8_t septet_data[256];
224         uint8_t ud_header[6];
225         char result[256];
226
227         /* test 7-bit encoding */
228         for (i = 0; i < ARRAY_SIZE(test_encode); ++i) {
229                 memset(coded, 0x42, sizeof(coded));
230                 septet_length = gsm_7bit_encode(coded, test_encode[i].input);
231                 octet_length = gsm_get_octet_len(septet_length);
232                 if (octet_length != test_encode[i].expected_octet_length) {
233                         fprintf(stderr, "Encode case %d: Octet length failure. Got %d, expected %d\n",
234                                 i, octet_length, test_encode[i].expected_octet_length);
235                         return -1;
236                 }
237
238                 if (septet_length != test_encode[i].expected_septet_length){
239                         fprintf(stderr, "Encode case %d: Septet length failure. Got %d, expected %d\n",
240                                 i, septet_length, test_encode[i].expected_septet_length);
241                         return -1;
242                 }
243
244                 if (memcmp(coded, test_encode[i].expected, octet_length) != 0) {
245                         fprintf(stderr, "Encoded content does not match for case %d\n",
246                                 i);
247                         return -1;
248                 }
249         }
250
251
252         /* Test: encode multiple SMS */
253         int number_of_septets = gsm_septet_encode(septet_data, test_multiple_encode[0].input);
254
255         /* SMS part 1 */
256         memset(tmp, 0x42, sizeof(tmp));
257         memset(coded, 0x42, sizeof(coded));
258         memcpy(tmp, septet_data, concatenated_part1_septet_length);
259
260         /* In our case: test_multiple_decode[0].ud_hdr_ind equals number of padding bits*/
261         octet_length = gsm_septets2octets(coded, tmp, concatenated_part1_septet_length, test_multiple_encode[0].ud_hdr_ind);
262
263         /* copy header */
264         memset(tmp, 0x42, sizeof(tmp));
265         int udh_length = test_multiple_encode[0].expected[0] + 1;
266         memcpy(tmp, test_multiple_encode[0].expected, udh_length);
267         memcpy(tmp + udh_length, coded, octet_length);
268         memset(coded, 0x42, sizeof(coded));
269         memcpy(coded, tmp, octet_length + 6);
270
271         if (memcmp(coded, test_multiple_encode[0].expected, octet_length) != 0) {
272                 fprintf(stderr, "Multiple-SMS encoded content does not match for part 1\n");
273                 return -1;
274         }
275
276
277         /* SMS part 2 */
278         memset(tmp, 0x42, sizeof(tmp));
279         memset(coded, 0x42, sizeof(coded));
280         memcpy(tmp, septet_data + concatenated_part1_septet_length, concatenated_part2_septet_length);
281
282         /* In our case: test_multiple_decode[1].ud_hdr_ind equals number of padding bits*/
283         octet_length = gsm_septets2octets(coded, tmp, concatenated_part2_septet_length, test_multiple_encode[1].ud_hdr_ind);
284
285         /* copy header */
286         memset(tmp, 0x42, sizeof(tmp));
287         udh_length = test_multiple_encode[1].expected[0] + 1;
288         memcpy(tmp, test_multiple_encode[1].expected, udh_length);
289         memcpy(tmp + udh_length, coded, octet_length);
290         memset(coded, 0x42, sizeof(coded));
291         memcpy(coded, tmp, octet_length + 6);
292
293         if (memcmp(coded, test_multiple_encode[1].expected, octet_length) != 0) {
294                 fprintf(stderr, "Multiple-SMS encoded content does not match for part 2\n");
295                 return -1;
296         }
297
298
299
300         /* test 7-bit decoding */
301         for (i = 0; i < ARRAY_SIZE(test_decode); ++i) {
302                 memset(result, 0x42, sizeof(coded));
303                 septet_length = gsm_7bit_decode_hdr(result, test_decode[i].input,
304                                 test_decode[i].expected_septet_length, test_decode[i].ud_hdr_ind);
305
306                 if (strcmp(result, test_decode[i].expected) != 0) {
307                         fprintf(stderr, "Test case %d failed to decode.\n", i);
308                         return -1;
309                 }
310                 if (septet_length != test_decode[i].expected_septet_length) {
311                         fprintf(stderr, "Decode case %d: Septet length failure. Got %d, expected %d\n",
312                                 i, septet_length, test_decode[i].expected_septet_length);
313                         return -1;
314                 }
315         }
316
317         printf("OK\n");
318         return 0;
319 }