blob: 802507115f173a138e35eb4dc55e8d9742aafea3 [file] [log] [blame]
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +02001/*
2 * (C) 2010 by Holger Hans Peter Freyther
3 * (C) 2010 by On-Waves
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
Holger Hans Peter Freytherbf128002011-11-13 22:48:37 +010022#include <osmocom/core/application.h>
23#include <osmocom/core/logging.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010024#include <osmocom/gsm/gsm0480.h>
Andreas Eversberg95975552013-08-08 12:38:53 +020025#include <osmocom/gsm/gsm_utils.h>
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +020026#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30static const uint8_t ussd_request[] = {
31 0x0b, 0x7b, 0x1c, 0x15, 0xa1, 0x13, 0x02, 0x01,
32 0x03, 0x02, 0x01, 0x3b, 0x30, 0x0b, 0x04, 0x01,
33 0x0f, 0x04, 0x06, 0x2a, 0xd5, 0x4c, 0x16, 0x1b,
34 0x01, 0x7f, 0x01, 0x00
35};
36
Vadim Yanitskiy52e44122018-06-11 03:51:11 +070037static const uint8_t ussd_facility[] = {
38 0x1b, 0x3a, 0x12, 0xa2, 0x10, 0x02, 0x01, 0x01,
39 0x30, 0x0b, 0x02, 0x01, 0x3c, 0x30, 0x06, 0x04,
40 0x01, 0x0f, 0x04, 0x01, 0x32
41};
42
43static const uint8_t ussd_release[] = {
44 0x8b, 0x2a, 0x1c, 0x08, 0xa3, 0x06, 0x02, 0x01,
45 0x05, 0x02, 0x01, 0x24
46};
47
Holger Hans Peter Freyther4a62dbb2016-07-12 17:45:34 +020048static const uint8_t interrogate_ss[] = {
49 0x0b, 0x7b, 0x1c, 0x0d, 0xa1, 0x0b, 0x02, 0x01,
50 0x03, 0x02, 0x01, 0x0e, 0x30, 0x03, 0x04, 0x01,
51 0x21, 0x7f, 0x01, 0x00
52};
53
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +020054static int parse_ussd(const uint8_t *_data, int len)
55{
56 uint8_t *data;
57 int rc;
Tobias Engel419684e2012-03-08 13:31:52 +010058 struct ss_request req;
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +020059 struct gsm48_hdr *hdr;
60
61 data = malloc(len);
62 memcpy(data, _data, len);
63 hdr = (struct gsm48_hdr *) &data[0];
Tobias Engel419684e2012-03-08 13:31:52 +010064 rc = gsm0480_decode_ss_request(hdr, len, &req);
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +020065 free(data);
66
67 return rc;
68}
69
Holger Hans Peter Freytherc88a44f2010-10-11 08:21:00 +020070static int parse_mangle_ussd(const uint8_t *_data, int len)
71{
72 uint8_t *data;
73 int rc;
Tobias Engel419684e2012-03-08 13:31:52 +010074 struct ss_request req;
Holger Hans Peter Freytherc88a44f2010-10-11 08:21:00 +020075 struct gsm48_hdr *hdr;
76
77 data = malloc(len);
78 memcpy(data, _data, len);
79 hdr = (struct gsm48_hdr *) &data[0];
80 hdr->data[1] = len - sizeof(*hdr) - 2;
Tobias Engel419684e2012-03-08 13:31:52 +010081 rc = gsm0480_decode_ss_request(hdr, len, &req);
Holger Hans Peter Freytherc88a44f2010-10-11 08:21:00 +020082 free(data);
83
84 return rc;
85}
86
Holger Hans Peter Freytherbf128002011-11-13 22:48:37 +010087struct log_info info = {};
88
Jacob Erlbeck8a1666b2013-08-08 12:38:54 +020089static void test_7bit_ussd(const char *text, const char *encoded_hex, const char *appended_after_decode)
Andreas Eversberg95975552013-08-08 12:38:53 +020090{
91 uint8_t coded[256];
92 char decoded[256];
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +020093 int octets_written;
94 int buffer_size;
95 int nchars;
Andreas Eversberg95975552013-08-08 12:38:53 +020096
97 printf("original = %s\n", osmo_hexdump((uint8_t *)text, strlen(text)));
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +020098 gsm_7bit_encode_n_ussd(coded, sizeof(coded), text, &octets_written);
99 printf("encoded = %s\n", osmo_hexdump(coded, octets_written));
Jacob Erlbeck8a1666b2013-08-08 12:38:54 +0200100
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200101 OSMO_ASSERT(strcmp(encoded_hex, osmo_hexdump_nospc(coded, octets_written)) == 0);
Jacob Erlbeck8a1666b2013-08-08 12:38:54 +0200102
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200103 gsm_7bit_decode_n_ussd(decoded, sizeof(decoded), coded, octets_written * 8 / 7);
Vadim Yanitskiybd33a952018-01-20 04:52:43 +0600104 printf("decoded = %s\n\n", osmo_hexdump((uint8_t *)decoded, strlen(decoded)));
Jacob Erlbeck8a1666b2013-08-08 12:38:54 +0200105
106 OSMO_ASSERT(strncmp(text, decoded, strlen(text)) == 0);
107 OSMO_ASSERT(strcmp(appended_after_decode, decoded + strlen(text)) == 0);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200108
109 /* check buffer limiting */
110 memset(decoded, 0xaa, sizeof(decoded));
111
112 for (buffer_size = 1; buffer_size < sizeof(decoded) - 1; ++buffer_size)
113 {
114 nchars = gsm_7bit_decode_n_ussd(decoded, buffer_size, coded, octets_written * 8 / 7);
115 OSMO_ASSERT(nchars <= buffer_size);
116 OSMO_ASSERT(decoded[buffer_size] == (char)0xaa);
117 OSMO_ASSERT(decoded[nchars] == '\0');
118 }
119
120 memset(coded, 0xaa, sizeof(coded));
121
122 for (buffer_size = 0; buffer_size < sizeof(coded) - 1; ++buffer_size)
123 {
124 gsm_7bit_encode_n_ussd(coded, buffer_size, text, &octets_written);
125 OSMO_ASSERT(octets_written <= buffer_size);
126 OSMO_ASSERT(coded[buffer_size] == 0xaa);
127 }
Andreas Eversberg95975552013-08-08 12:38:53 +0200128}
129
Vadim Yanitskiy52e44122018-06-11 03:51:11 +0700130static void test_extract_ie_by_tag(void)
131{
132 uint16_t ie_len;
133 uint8_t *ie;
134 int rc;
135
136 printf("[i] Testing gsm0480_extract_ie_by_tag()\n");
137
138 /* REGISTER message with Facility IE */
139 rc = gsm0480_extract_ie_by_tag((struct gsm48_hdr *) ussd_request,
140 sizeof(ussd_request), &ie, &ie_len, GSM0480_IE_FACILITY);
141 OSMO_ASSERT(rc == 0);
142 OSMO_ASSERT(ie != NULL && ie_len > 0);
143 printf("[?] REGISTER message with Facility IE "
144 "(len=%u): %s\n", ie_len, osmo_hexdump(ie, ie_len));
145
146 /* REGISTER message with SS version IE */
147 rc = gsm0480_extract_ie_by_tag((struct gsm48_hdr *) ussd_request,
148 sizeof(ussd_request), &ie, &ie_len, GSM0480_IE_SS_VERSION);
149 OSMO_ASSERT(rc == 0);
150 OSMO_ASSERT(ie != NULL && ie_len > 0);
151 printf("[?] REGISTER message with SS version IE "
152 "(len=%u): %s\n", ie_len, osmo_hexdump(ie, ie_len));
153
154 /* REGISTER message with unknown IE */
155 rc = gsm0480_extract_ie_by_tag((struct gsm48_hdr *) ussd_request,
156 sizeof(ussd_request), &ie, &ie_len, 0xff);
157 OSMO_ASSERT(rc == 0);
158 OSMO_ASSERT(ie == NULL && ie_len == 0);
159
160 /* FACILITY message with Facility IE */
161 rc = gsm0480_extract_ie_by_tag((struct gsm48_hdr *) ussd_facility,
162 sizeof(ussd_facility), &ie, &ie_len, GSM0480_IE_FACILITY);
163 OSMO_ASSERT(rc == 0);
164 OSMO_ASSERT(ie != NULL && ie_len > 0);
165 printf("[?] FACILITY message with Facility IE "
166 "(len=%u): %s\n", ie_len, osmo_hexdump(ie, ie_len));
167
168 /* FACILITY message with unknown IE */
169 rc = gsm0480_extract_ie_by_tag((struct gsm48_hdr *) ussd_facility,
170 sizeof(ussd_facility), &ie, &ie_len, 0xff);
171 OSMO_ASSERT(rc == 0);
172 OSMO_ASSERT(ie == NULL && ie_len == 0);
173
174 /* RELEASE COMPLETE message with Facility IE */
175 rc = gsm0480_extract_ie_by_tag((struct gsm48_hdr *) ussd_release,
176 sizeof(ussd_release), &ie, &ie_len, GSM0480_IE_FACILITY);
177 OSMO_ASSERT(rc == 0);
178 OSMO_ASSERT(ie != NULL && ie_len > 0);
179 printf("[?] RELEASE COMPLETE message with Facility IE "
180 "(len=%u): %s\n", ie_len, osmo_hexdump(ie, ie_len));
181
182 /* RELEASE COMPLETE message without Facility IE */
183 rc = gsm0480_extract_ie_by_tag((struct gsm48_hdr *) ussd_release,
184 sizeof(struct gsm48_hdr), &ie, &ie_len, GSM0480_IE_FACILITY);
185 OSMO_ASSERT(rc == 0);
186 OSMO_ASSERT(ie == NULL && ie_len == 0);
187
188 printf("\n");
189}
190
Vadim Yanitskiy5a09f752018-06-11 04:58:53 +0700191static void test_parse_facility_ie(void)
192{
193 struct ss_request req;
194 uint16_t ie_len;
195 uint8_t *ie;
196 int rc;
197
198 printf("[i] Testing gsm0480_parse_facility_ie()\n");
199
200 /* Extract Facility IE from FACILITY message */
201 rc = gsm0480_extract_ie_by_tag((struct gsm48_hdr *) ussd_facility,
202 sizeof(ussd_facility), &ie, &ie_len, GSM0480_IE_FACILITY);
203 OSMO_ASSERT(rc == 0);
204 OSMO_ASSERT(ie != NULL && ie_len > 0);
205 printf("[?] FACILITY message with Facility IE "
206 "(len=%u): %s\n", ie_len, osmo_hexdump(ie, ie_len));
207
208 /* Attempt to decode */
209 memset(&req, 0x00, sizeof(req));
210 rc = gsm0480_parse_facility_ie(ie, ie_len, &req);
211 OSMO_ASSERT(rc == 0);
212
213 /* Verify expected vs decoded data */
214 printf("[?] InvokeID: expected 0x%02x, decoded 0x%02x\n",
215 0x01, req.invoke_id);
216 printf("[?] Operation code: expected 0x%02x, decoded 0x%02x\n",
217 0x3c, req.opcode);
218 printf("[?] Data Coding Scheme: expected 0x%02x, decoded 0x%02x\n",
219 0x0f, req.ussd_data_dcs);
220 printf("[?] Data length: expected 0x%02x, decoded 0x%02x\n",
221 0x01, req.ussd_data_len);
222 printf("[?] Data: expected %s, decoded %s\n", "32",
223 osmo_hexdump_nospc(req.ussd_data, req.ussd_data_len));
224
225 printf("\n");
226}
227
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +0200228int main(int argc, char **argv)
229{
Tobias Engel419684e2012-03-08 13:31:52 +0100230 struct ss_request req;
Vadim Yanitskiyac3b6ac2018-01-17 15:03:32 +0600231 uint16_t size;
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +0200232 int i;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200233 struct msgb *msg;
Neels Hofmeyra829b452018-04-05 03:02:35 +0200234 void *ctx = talloc_named_const(NULL, 0, "ussd_test");
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +0200235
Neels Hofmeyra829b452018-04-05 03:02:35 +0200236 osmo_init_logging2(ctx, &info);
Holger Hans Peter Freytherbf128002011-11-13 22:48:37 +0100237
Vadim Yanitskiy52e44122018-06-11 03:51:11 +0700238 /* Test gsm0480_extract_ie_by_tag() */
239 test_extract_ie_by_tag();
240
Vadim Yanitskiy5a09f752018-06-11 04:58:53 +0700241 /* Test gsm0480_parse_facility_ie() */
242 test_parse_facility_ie();
243
Holger Hans Peter Freyther4a62dbb2016-07-12 17:45:34 +0200244 memset(&req, 0, sizeof(req));
Vadim Yanitskiyac3b6ac2018-01-17 15:03:32 +0600245 gsm0480_decode_ss_request((struct gsm48_hdr *) ussd_request,
246 sizeof(ussd_request), &req);
Tobias Engel419684e2012-03-08 13:31:52 +0100247 printf("Tested if it still works. Text was: %s\n", req.ussd_text);
Holger Hans Peter Freytherf6323712010-10-11 08:49:27 +0200248
Holger Hans Peter Freyther4a62dbb2016-07-12 17:45:34 +0200249 memset(&req, 0, sizeof(req));
Vadim Yanitskiyac3b6ac2018-01-17 15:03:32 +0600250 gsm0480_decode_ss_request((struct gsm48_hdr *) interrogate_ss,
251 sizeof(interrogate_ss), &req);
Holger Hans Peter Freyther4a62dbb2016-07-12 17:45:34 +0200252 OSMO_ASSERT(strlen((char *) req.ussd_text) == 0);
253 OSMO_ASSERT(req.ss_code == 33);
254 printf("interrogateSS CFU text..'%s' code %d\n", req.ussd_text, req.ss_code);
Holger Hans Peter Freytherf6323712010-10-11 08:49:27 +0200255
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +0200256 printf("Testing parsing a USSD request and truncated versions\n");
257
Vadim Yanitskiyac3b6ac2018-01-17 15:03:32 +0600258 size = sizeof(ussd_request);
259
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +0200260 for (i = size; i > sizeof(struct gsm48_hdr); --i) {
261 int rc = parse_ussd(&ussd_request[0], i);
Vadim Yanitskiyc0771d62018-01-10 23:42:19 +0600262 printf("Result for len=%d is %d\n", i, rc);
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +0200263 }
264
Holger Hans Peter Freytherc88a44f2010-10-11 08:21:00 +0200265 printf("Mangling the container now\n");
266 for (i = size; i > sizeof(struct gsm48_hdr) + 2; --i) {
267 int rc = parse_mangle_ussd(&ussd_request[0], i);
Vadim Yanitskiyc0771d62018-01-10 23:42:19 +0600268 printf("Result for len=%d is %d\n", i, rc);
Holger Hans Peter Freytherc88a44f2010-10-11 08:21:00 +0200269 }
270
Andreas Eversberg95975552013-08-08 12:38:53 +0200271 printf("<CR> case test for 7 bit encode\n");
Jacob Erlbeck8a1666b2013-08-08 12:38:54 +0200272 test_7bit_ussd("01234567", "b0986c46abd96e", "");
273 test_7bit_ussd("0123456", "b0986c46abd91a", "");
274 test_7bit_ussd("01234567\r", "b0986c46abd96e0d", "");
275 /* The appended \r is compliant to GSM 03.38 section 6.1.2.3.1: */
276 test_7bit_ussd("0123456\r", "b0986c46abd91a0d", "\r");
277 test_7bit_ussd("012345\r", "b0986c46ab351a", "");
Andreas Eversberg95975552013-08-08 12:38:53 +0200278
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200279 printf("Checking GSM 04.80 USSD message generation.\n");
280
281 test_7bit_ussd("", "", "");
282 msg = gsm0480_create_unstructuredSS_Notify (0x00, "");
283 printf ("Created unstructuredSS_Notify (0x00): %s\n",
284 osmo_hexdump(msgb_data(msg), msgb_length(msg)));
285 msgb_free (msg);
286
287 test_7bit_ussd("forty-two", "e6b79c9e6fd1ef6f", "");
288 msg = gsm0480_create_unstructuredSS_Notify (0x42, "forty-two");
289 printf ("Created unstructuredSS_Notify (0x42): %s\n",
290 osmo_hexdump(msgb_data(msg), msgb_length(msg)));
291 msgb_free (msg);
Holger Hans Peter Freytherdaa653f2010-10-11 07:56:06 +0200292 return 0;
293}