blob: 218092f2c5275736c5cc8060ae00914a6afe059a [file] [log] [blame]
Holger Hans Peter Freyther232f6212014-09-30 09:10:25 +02001/* Test the SGSN */
2/*
3 * (C) 2014 by Holger Hans Peter Freyther
4 * (C) 2014 by sysmocom s.f.m.c. GmbH
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +020022#include <openbsc/gprs_llc.h>
23#include <openbsc/sgsn.h>
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +020024#include <openbsc/gprs_gmm.h>
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +020025#include <openbsc/debug.h>
26
Jacob Erlbeck0b2da872014-10-27 14:34:13 +010027#include <osmocom/gprs/gprs_bssgp.h>
28
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +020029#include <osmocom/gsm/gsm_utils.h>
30
31#include <osmocom/core/application.h>
32#include <osmocom/core/msgb.h>
Jacob Erlbeck0b2da872014-10-27 14:34:13 +010033#include <osmocom/core/rate_ctr.h>
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +020034
Holger Hans Peter Freyther232f6212014-09-30 09:10:25 +020035#include <stdio.h>
36
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +020037extern void *tall_msgb_ctx;
38
39void *tall_bsc_ctx;
40static struct sgsn_instance sgsn_inst = {
41 .config_file = "osmo_sgsn.cfg",
42 .cfg = {
43 .gtp_statedir = "./",
44 .acl_enabled = 1,
45 },
46};
47struct sgsn_instance *sgsn = &sgsn_inst;
Jacob Erlbeck0b2da872014-10-27 14:34:13 +010048unsigned sgsn_tx_counter = 0;
49
50/* override */
51int bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime,
52 struct bssgp_dl_ud_par *dup)
53{
54 sgsn_tx_counter += 1;
55 return 0;
56}
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +020057
58static int count(struct llist_head *head)
59{
60 struct llist_head *cur;
61 int count = 0;
62
63 llist_for_each(cur, head)
64 count += 1;
65
66 return count;
67}
68
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +020069static struct msgb *create_msg(const uint8_t *data, size_t len)
70{
71 struct msgb *msg = msgb_alloc(len + 8, "test message");
72 msg->l1h = msgb_put(msg, 8);
73 msg->l2h = msgb_put(msg, len);
74 memcpy(msg->l2h, data, len);
75
76 msgb_bcid(msg) = msg->l1h;
77 msgb_gmmh(msg) = msg->l2h;
78 return msg;
79}
80
Jacob Erlbeckf43a2992014-10-27 13:23:49 +010081/*
82 * Create a context and search for it
83 */
84static struct sgsn_mm_ctx *alloc_mm_ctx(uint32_t tlli, struct gprs_ra_id *raid)
85{
86 struct sgsn_mm_ctx *ctx, *ictx;
87 struct gprs_llc_lle *lle;
88 int old_count = count(gprs_llme_list());
89
90 lle = gprs_lle_get_or_create(tlli, 3);
91 ctx = sgsn_mm_ctx_alloc(tlli, raid);
92 ctx->mm_state = GMM_REGISTERED_NORMAL;
93 ctx->llme = lle->llme;
94
95 ictx = sgsn_mm_ctx_by_tlli(tlli, raid);
96 OSMO_ASSERT(ictx == ctx);
97
98 OSMO_ASSERT(count(gprs_llme_list()) == old_count + 1);
99
100 return ctx;
101}
102
Jacob Erlbeck75488292014-10-29 10:31:18 +0100103static void send_0408_message(struct gprs_llc_llme *llme, uint32_t tlli,
104 const uint8_t *data, size_t data_len)
105{
106 struct msgb *msg;
107
108 sgsn_tx_counter = 0;
109
110 msg = create_msg(data, data_len);
111 msgb_tlli(msg) = tlli;
112 gsm0408_gprs_rcvmsg(msg, llme);
113 msgb_free(msg);
114}
115
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200116static void test_llme(void)
117{
118 struct gprs_llc_lle *lle, *lle_copy;
119 uint32_t local_tlli;
120 uint32_t foreign_tlli;
121
122 printf("Testing LLME allocations\n");
123 local_tlli = gprs_tmsi2tlli(0x234, TLLI_LOCAL);
124 foreign_tlli = gprs_tmsi2tlli(0x234, TLLI_FOREIGN);
125
126 /* initial state */
127 OSMO_ASSERT(count(gprs_llme_list()) == 0);
128
129 /* Create a new entry */
130 lle = gprs_lle_get_or_create(local_tlli, 3);
131 OSMO_ASSERT(lle);
132 OSMO_ASSERT(count(gprs_llme_list()) == 1);
133
134 /* No new entry is created */
135 lle_copy = gprs_lle_get_or_create(local_tlli, 3);
136 OSMO_ASSERT(lle == lle_copy);
137 OSMO_ASSERT(count(gprs_llme_list()) == 1);
138 lle_copy = gprs_lle_get_or_create(foreign_tlli, 3);
139 OSMO_ASSERT(lle == lle_copy);
140 OSMO_ASSERT(count(gprs_llme_list()) == 1);
141
142 /* unassign which should delete it*/
143 gprs_llgmm_assign(lle->llme, lle->llme->tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL);
144
145 /* Check that everything was cleaned up */
146 OSMO_ASSERT(count(gprs_llme_list()) == 0);
147}
148
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +0200149/*
150 * Test that a GMM Detach will remove the MMCTX and the
151 * associated LLME.
152 */
153static void test_gmm_detach(void)
154{
155 struct gprs_ra_id raid = { 0, };
156 struct sgsn_mm_ctx *ctx, *ictx;
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +0200157 uint32_t local_tlli;
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +0200158
159 printf("Testing GMM detach\n");
160
161 /* DTAP - Detach Request (MO) */
162 /* normal detach, power_off = 0 */
163 static const unsigned char detach_req[] = {
164 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4, 0xef, 0xe2,
165 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb
166 };
167
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +0200168 local_tlli = gprs_tmsi2tlli(0x23, TLLI_LOCAL);
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +0200169
Jacob Erlbeckf43a2992014-10-27 13:23:49 +0100170 /* Create a context */
171 OSMO_ASSERT(count(gprs_llme_list()) == 0);
172 ctx = alloc_mm_ctx(local_tlli, &raid);
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +0200173
174 /* inject the detach */
Jacob Erlbeck75488292014-10-29 10:31:18 +0100175 send_0408_message(ctx->llme, local_tlli,
176 detach_req, ARRAY_SIZE(detach_req));
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +0200177
Jacob Erlbeck0b2da872014-10-27 14:34:13 +0100178 /* verify that a single message (hopefully the Detach Accept) has been
179 * sent by the SGSN */
Jacob Erlbeck75488292014-10-29 10:31:18 +0100180 OSMO_ASSERT(sgsn_tx_counter == 1);
Jacob Erlbeck0b2da872014-10-27 14:34:13 +0100181
182 /* verify that things are gone */
183 OSMO_ASSERT(count(gprs_llme_list()) == 0);
184 ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid);
185 OSMO_ASSERT(!ictx);
186}
187
188/*
189 * Test that a GMM Detach will remove the MMCTX and the associated LLME but
190 * will not sent a Detach Accept message (power_off = 1)
191 */
192static void test_gmm_detach_power_off(void)
193{
194 struct gprs_ra_id raid = { 0, };
195 struct sgsn_mm_ctx *ctx, *ictx;
196 uint32_t local_tlli;
Jacob Erlbeck0b2da872014-10-27 14:34:13 +0100197
198 printf("Testing GMM detach (power off)\n");
199
200 /* DTAP - Detach Request (MO) */
201 /* normal detach, power_off = 1 */
202 static const unsigned char detach_req[] = {
203 0x08, 0x05, 0x09, 0x18, 0x05, 0xf4, 0xef, 0xe2,
204 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb
205 };
206
207 local_tlli = gprs_tmsi2tlli(0x23, TLLI_LOCAL);
208
209 /* Create a context */
210 OSMO_ASSERT(count(gprs_llme_list()) == 0);
211 ctx = alloc_mm_ctx(local_tlli, &raid);
212
213 /* inject the detach */
Jacob Erlbeck75488292014-10-29 10:31:18 +0100214 send_0408_message(ctx->llme, local_tlli,
215 detach_req, ARRAY_SIZE(detach_req));
Jacob Erlbeck0b2da872014-10-27 14:34:13 +0100216
217 /* verify that no message (and therefore no Detach Accept) has been
218 * sent by the SGSN */
Jacob Erlbeck75488292014-10-29 10:31:18 +0100219 OSMO_ASSERT(sgsn_tx_counter == 0);
Jacob Erlbeck0b2da872014-10-27 14:34:13 +0100220
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +0200221 /* verify that things are gone */
222 OSMO_ASSERT(count(gprs_llme_list()) == 0);
223 ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid);
Jacob Erlbeck12396bd2014-09-30 13:51:45 +0200224 OSMO_ASSERT(!ictx);
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +0200225}
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200226
Jacob Erlbeck42d284f2014-10-21 13:09:55 +0200227/*
228 * Test that a GMM Detach will remove the associated LLME if there is no MMCTX.
229 */
230static void test_gmm_detach_no_mmctx(void)
231{
232 struct gprs_llc_lle *lle;
233 uint32_t local_tlli;
Jacob Erlbeck42d284f2014-10-21 13:09:55 +0200234
235 printf("Testing GMM detach (no MMCTX)\n");
236
237 /* DTAP - Detach Request (MO) */
238 /* normal detach, power_off = 0 */
239 static const unsigned char detach_req[] = {
240 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4, 0xef, 0xe2,
241 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb
242 };
243
244 /* Create an LLME */
245 OSMO_ASSERT(count(gprs_llme_list()) == 0);
246 local_tlli = gprs_tmsi2tlli(0x23, TLLI_LOCAL);
247 lle = gprs_lle_get_or_create(local_tlli, 3);
248
249 OSMO_ASSERT(count(gprs_llme_list()) == 1);
250
251 /* inject the detach */
Jacob Erlbeck75488292014-10-29 10:31:18 +0100252 send_0408_message(lle->llme, local_tlli,
253 detach_req, ARRAY_SIZE(detach_req));
Jacob Erlbeck42d284f2014-10-21 13:09:55 +0200254
255 /* verify that the LLME is gone */
256 OSMO_ASSERT(count(gprs_llme_list()) == 0);
257}
258
Jacob Erlbeckb35ee6b2014-10-28 09:47:03 +0100259/*
260 * Test that a GMM Status will remove the associated LLME if there is no MMCTX.
261 */
262static void test_gmm_status_no_mmctx(void)
263{
264 struct gprs_llc_lle *lle;
265 uint32_t local_tlli;
Jacob Erlbeckb35ee6b2014-10-28 09:47:03 +0100266
267 printf("Testing GMM Status (no MMCTX)\n");
268
269 /* DTAP - GMM Status, protocol error */
270 static const unsigned char gmm_status[] = {
271 0x08, 0x20, 0x6f
272 };
273
274 /* Create an LLME */
275 OSMO_ASSERT(count(gprs_llme_list()) == 0);
276 local_tlli = gprs_tmsi2tlli(0x23, TLLI_LOCAL);
277 lle = gprs_lle_get_or_create(local_tlli, 3);
278
279 OSMO_ASSERT(count(gprs_llme_list()) == 1);
280
281 /* inject the detach */
Jacob Erlbeck75488292014-10-29 10:31:18 +0100282 send_0408_message(lle->llme, local_tlli,
283 gmm_status, ARRAY_SIZE(gmm_status));
Jacob Erlbeckb35ee6b2014-10-28 09:47:03 +0100284
285 /* verify that no message has been sent by the SGSN */
Jacob Erlbeck75488292014-10-29 10:31:18 +0100286 OSMO_ASSERT(sgsn_tx_counter == 0);
Jacob Erlbeckb35ee6b2014-10-28 09:47:03 +0100287
288 /* verify that the LLME is gone */
289 OSMO_ASSERT(count(gprs_llme_list()) == 0);
290}
291
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100292/*
293 * Test the GMM Attach procedure
294 */
295static void test_gmm_attach(void)
296{
297 struct gprs_ra_id raid = { 0, };
298 struct sgsn_mm_ctx *ctx = NULL;
299 struct sgsn_mm_ctx *ictx;
300 uint32_t foreign_tlli;
301 uint32_t local_tlli = 0;
302 struct gprs_llc_lle *lle;
303
304 /* DTAP - Attach Request */
305 /* The P-TMSI is not known by the SGSN */
306 static const unsigned char attach_req[] = {
307 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, 0x05, 0xf4,
308 0xfb, 0xc5, 0x46, 0x79, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60,
309 0x19, 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60,
310 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, 0xc8,
311 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00
312 };
313
314 /* DTAP - Identity Response IMEI */
315 static const unsigned char ident_resp_imei[] = {
316 0x08, 0x16, 0x08, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78,
317 0x56
318 };
319
320 /* DTAP - Identity Response IMSI */
321 static const unsigned char ident_resp_imsi[] = {
322 0x08, 0x16, 0x08, 0x19, 0x32, 0x54, 0x76, 0x98, 0x10, 0x32,
323 0x54
324 };
325
326 /* DTAP - Attach Complete */
327 static const unsigned char attach_compl[] = {
328 0x08, 0x03
329 };
330
331 /* DTAP - Detach Request (MO) */
332 /* normal detach, power_off = 0 */
333 static const unsigned char detach_req[] = {
334 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4, 0xeb, 0x8b,
335 0x45, 0x67, 0x19, 0x03, 0xb9, 0x97, 0xcb
336 };
337
338 printf("Testing GMM attach\n");
339
340 /* reset the PRNG used by sgsn_alloc_ptmsi */
341 srand(1);
342
Jacob Erlbeck79d438a2014-10-29 22:12:20 +0100343 sgsn_acl_add("123456789012345", &sgsn->cfg);
344
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100345 foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN);
346
347 /* Create a LLE/LLME */
348 OSMO_ASSERT(count(gprs_llme_list()) == 0);
349 lle = gprs_lle_get_or_create(foreign_tlli, 3);
350 OSMO_ASSERT(count(gprs_llme_list()) == 1);
351
352 /* inject the attach request */
353 send_0408_message(lle->llme, foreign_tlli,
354 attach_req, ARRAY_SIZE(attach_req));
355
356 ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid);
357 OSMO_ASSERT(ctx != NULL);
358 OSMO_ASSERT(ctx->mm_state == GMM_COMMON_PROC_INIT);
359
360 /* we expect an identity request (IMEI) */
361 OSMO_ASSERT(sgsn_tx_counter == 1);
362
363 /* inject the identity response (IMEI) */
364 send_0408_message(ctx->llme, foreign_tlli,
365 ident_resp_imei, ARRAY_SIZE(ident_resp_imei));
366
367 /* we expect an identity request (IMSI) */
368 OSMO_ASSERT(sgsn_tx_counter == 1);
369
370 /* inject the identity response (IMSI) */
371 send_0408_message(ctx->llme, foreign_tlli,
372 ident_resp_imsi, ARRAY_SIZE(ident_resp_imsi));
373
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100374 /* check that the MM context has not been removed due to a failed
375 * authorization */
376 OSMO_ASSERT(ctx == sgsn_mm_ctx_by_tlli(foreign_tlli, &raid));
377
Jacob Erlbeck67318ef2014-10-28 16:23:46 +0100378 OSMO_ASSERT(ctx->mm_state == GMM_COMMON_PROC_INIT);
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100379
380 /* we expect an attach accept/reject */
381 OSMO_ASSERT(sgsn_tx_counter == 1);
382
383 /* this has been randomly assigned by the SGSN */
384 local_tlli = gprs_tmsi2tlli(0xeb8b4567, TLLI_LOCAL);
385
386 /* inject the attach complete */
387 send_0408_message(ctx->llme, local_tlli,
388 attach_compl, ARRAY_SIZE(attach_compl));
389
390 OSMO_ASSERT(ctx->mm_state == GMM_REGISTERED_NORMAL);
391
392 /* we don't expect a response */
393 OSMO_ASSERT(sgsn_tx_counter == 0);
394
395 /* inject the detach */
396 send_0408_message(ctx->llme, local_tlli,
397 detach_req, ARRAY_SIZE(detach_req));
398
399 /* verify that things are gone */
400 OSMO_ASSERT(count(gprs_llme_list()) == 0);
401 ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid);
402 OSMO_ASSERT(!ictx);
Jacob Erlbeck79d438a2014-10-29 22:12:20 +0100403
404 sgsn_acl_del("123456789012345", &sgsn->cfg);
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100405}
406
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200407static struct log_info_cat gprs_categories[] = {
408 [DMM] = {
409 .name = "DMM",
410 .description = "Layer3 Mobility Management (MM)",
411 .color = "\033[1;33m",
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100412 .enabled = 1, .loglevel = LOGL_DEBUG,
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200413 },
414 [DPAG] = {
415 .name = "DPAG",
416 .description = "Paging Subsystem",
417 .color = "\033[1;38m",
418 .enabled = 1, .loglevel = LOGL_NOTICE,
419 },
420 [DMEAS] = {
421 .name = "DMEAS",
422 .description = "Radio Measurement Processing",
423 .enabled = 0, .loglevel = LOGL_NOTICE,
424 },
425 [DREF] = {
426 .name = "DREF",
427 .description = "Reference Counting",
428 .enabled = 0, .loglevel = LOGL_NOTICE,
429 },
430 [DGPRS] = {
431 .name = "DGPRS",
432 .description = "GPRS Packet Service",
433 .enabled = 1, .loglevel = LOGL_DEBUG,
434 },
435 [DNS] = {
436 .name = "DNS",
437 .description = "GPRS Network Service (NS)",
438 .enabled = 1, .loglevel = LOGL_INFO,
439 },
440 [DBSSGP] = {
441 .name = "DBSSGP",
442 .description = "GPRS BSS Gateway Protocol (BSSGP)",
443 .enabled = 1, .loglevel = LOGL_DEBUG,
444 },
445 [DLLC] = {
446 .name = "DLLC",
447 .description = "GPRS Logical Link Control Protocol (LLC)",
448 .enabled = 1, .loglevel = LOGL_DEBUG,
449 },
450 [DSNDCP] = {
451 .name = "DSNDCP",
452 .description = "GPRS Sub-Network Dependent Control Protocol (SNDCP)",
453 .enabled = 1, .loglevel = LOGL_DEBUG,
454 },
455};
456
457static struct log_info info = {
458 .cat = gprs_categories,
459 .num_cat = ARRAY_SIZE(gprs_categories),
460};
461
Holger Hans Peter Freyther232f6212014-09-30 09:10:25 +0200462int main(int argc, char **argv)
463{
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200464 osmo_init_logging(&info);
465 tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn");
466 tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
467
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100468 sgsn_auth_init(sgsn);
469
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200470 test_llme();
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +0200471 test_gmm_detach();
Jacob Erlbeck0b2da872014-10-27 14:34:13 +0100472 test_gmm_detach_power_off();
Jacob Erlbeck42d284f2014-10-21 13:09:55 +0200473 test_gmm_detach_no_mmctx();
Jacob Erlbeckb35ee6b2014-10-28 09:47:03 +0100474 test_gmm_status_no_mmctx();
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100475 test_gmm_attach();
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200476 printf("Done\n");
Holger Hans Peter Freyther232f6212014-09-30 09:10:25 +0200477 return 0;
478}
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200479
480
481/* stubs */
482struct osmo_prim_hdr;
483int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
484{
485 abort();
486}