2 * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
3 * (C) 2010 by Nico Golde <nico@ngolde.de>
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.
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.
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.
25 #include <osmocom/core/msgb.h>
26 #include <osmocom/gsm/gsm_utils.h>
27 #include <osmocom/core/utils.h>
31 const uint16_t input_length;
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;
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
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,
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,
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,
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.";
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,
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,
116 static const struct test_case test_multiple_encode[] =
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,
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,
134 static const struct test_case test_encode[] =
137 .input = simple_text,
138 .expected = simple_enc,
139 .expected_octet_length = sizeof(simple_enc),
140 .expected_septet_length = simple_septet_length,
144 .input = escape_text,
145 .expected = escape_enc,
146 .expected_octet_length = sizeof(escape_enc),
147 .expected_septet_length = escape_septet_length,
151 .input = enhanced_text,
152 .expected = enhanced_enc,
153 .expected_octet_length = sizeof(enhanced_enc),
154 .expected_septet_length = enhanced_septet_length,
158 .input = enhancedV2_text,
159 .expected = enhancedV2_enc,
160 .expected_octet_length = sizeof(enhancedV2_enc),
161 .expected_septet_length = enhancedV2_septet_length,
166 static const struct test_case test_decode[] =
170 .input_length = sizeof(simple_enc),
171 .expected = simple_text,
172 .expected_septet_length = simple_septet_length,
177 .input_length = sizeof(escape_enc),
178 .expected = escape_text,
179 .expected_septet_length = escape_septet_length,
183 .input = enhanced_enc,
184 .input_length = sizeof(enhanced_enc),
185 .expected = enhanced_text,
186 .expected_septet_length = enhanced_septet_length,
190 .input = enhancedV2_enc,
191 .input_length = sizeof(enhancedV2_enc),
192 .expected = enhancedV2_text,
193 .expected_septet_length = enhancedV2_septet_length,
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,
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,
212 int main(int argc, char** argv)
214 printf("SMS testing\n");
218 uint8_t octet_length;
219 uint8_t septet_length;
220 uint8_t gsm_septet_length;
223 uint8_t septet_data[256];
224 uint8_t ud_header[6];
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);
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);
244 if (memcmp(coded, test_encode[i].expected, octet_length) != 0) {
245 fprintf(stderr, "Encoded content does not match for case %d\n",
252 /* Test: encode multiple SMS */
253 int number_of_septets = gsm_septet_encode(septet_data, test_multiple_encode[0].input);
256 memset(tmp, 0x42, sizeof(tmp));
257 memset(coded, 0x42, sizeof(coded));
258 memcpy(tmp, septet_data, concatenated_part1_septet_length);
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);
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);
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");
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);
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);
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);
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");
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);
306 if (strcmp(result, test_decode[i].expected) != 0) {
307 fprintf(stderr, "Test case %d failed to decode.\n", i);
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);