blob: 49ee2df204cd69d466e19e8d9a21dff4d5fcfe80 [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
343 foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN);
344
345 /* Create a LLE/LLME */
346 OSMO_ASSERT(count(gprs_llme_list()) == 0);
347 lle = gprs_lle_get_or_create(foreign_tlli, 3);
348 OSMO_ASSERT(count(gprs_llme_list()) == 1);
349
350 /* inject the attach request */
351 send_0408_message(lle->llme, foreign_tlli,
352 attach_req, ARRAY_SIZE(attach_req));
353
354 ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid);
355 OSMO_ASSERT(ctx != NULL);
356 OSMO_ASSERT(ctx->mm_state == GMM_COMMON_PROC_INIT);
357
358 /* we expect an identity request (IMEI) */
359 OSMO_ASSERT(sgsn_tx_counter == 1);
360
361 /* inject the identity response (IMEI) */
362 send_0408_message(ctx->llme, foreign_tlli,
363 ident_resp_imei, ARRAY_SIZE(ident_resp_imei));
364
365 /* we expect an identity request (IMSI) */
366 OSMO_ASSERT(sgsn_tx_counter == 1);
367
368 /* inject the identity response (IMSI) */
369 send_0408_message(ctx->llme, foreign_tlli,
370 ident_resp_imsi, ARRAY_SIZE(ident_resp_imsi));
371
372 /* FIXME: We are not authorized and should get an Attach Reject, fix
373 * authorization in gprs_gmm.c */
374
375 /* check that the MM context has not been removed due to a failed
376 * authorization */
377 OSMO_ASSERT(ctx == sgsn_mm_ctx_by_tlli(foreign_tlli, &raid));
378
Jacob Erlbeck67318ef2014-10-28 16:23:46 +0100379 OSMO_ASSERT(ctx->mm_state == GMM_COMMON_PROC_INIT);
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100380
381 /* we expect an attach accept/reject */
382 OSMO_ASSERT(sgsn_tx_counter == 1);
383
384 /* this has been randomly assigned by the SGSN */
385 local_tlli = gprs_tmsi2tlli(0xeb8b4567, TLLI_LOCAL);
386
387 /* inject the attach complete */
388 send_0408_message(ctx->llme, local_tlli,
389 attach_compl, ARRAY_SIZE(attach_compl));
390
391 OSMO_ASSERT(ctx->mm_state == GMM_REGISTERED_NORMAL);
392
393 /* we don't expect a response */
394 OSMO_ASSERT(sgsn_tx_counter == 0);
395
396 /* inject the detach */
397 send_0408_message(ctx->llme, local_tlli,
398 detach_req, ARRAY_SIZE(detach_req));
399
400 /* verify that things are gone */
401 OSMO_ASSERT(count(gprs_llme_list()) == 0);
402 ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid);
403 OSMO_ASSERT(!ictx);
404}
405
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200406static struct log_info_cat gprs_categories[] = {
407 [DMM] = {
408 .name = "DMM",
409 .description = "Layer3 Mobility Management (MM)",
410 .color = "\033[1;33m",
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100411 .enabled = 1, .loglevel = LOGL_DEBUG,
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200412 },
413 [DPAG] = {
414 .name = "DPAG",
415 .description = "Paging Subsystem",
416 .color = "\033[1;38m",
417 .enabled = 1, .loglevel = LOGL_NOTICE,
418 },
419 [DMEAS] = {
420 .name = "DMEAS",
421 .description = "Radio Measurement Processing",
422 .enabled = 0, .loglevel = LOGL_NOTICE,
423 },
424 [DREF] = {
425 .name = "DREF",
426 .description = "Reference Counting",
427 .enabled = 0, .loglevel = LOGL_NOTICE,
428 },
429 [DGPRS] = {
430 .name = "DGPRS",
431 .description = "GPRS Packet Service",
432 .enabled = 1, .loglevel = LOGL_DEBUG,
433 },
434 [DNS] = {
435 .name = "DNS",
436 .description = "GPRS Network Service (NS)",
437 .enabled = 1, .loglevel = LOGL_INFO,
438 },
439 [DBSSGP] = {
440 .name = "DBSSGP",
441 .description = "GPRS BSS Gateway Protocol (BSSGP)",
442 .enabled = 1, .loglevel = LOGL_DEBUG,
443 },
444 [DLLC] = {
445 .name = "DLLC",
446 .description = "GPRS Logical Link Control Protocol (LLC)",
447 .enabled = 1, .loglevel = LOGL_DEBUG,
448 },
449 [DSNDCP] = {
450 .name = "DSNDCP",
451 .description = "GPRS Sub-Network Dependent Control Protocol (SNDCP)",
452 .enabled = 1, .loglevel = LOGL_DEBUG,
453 },
454};
455
456static struct log_info info = {
457 .cat = gprs_categories,
458 .num_cat = ARRAY_SIZE(gprs_categories),
459};
460
Holger Hans Peter Freyther232f6212014-09-30 09:10:25 +0200461int main(int argc, char **argv)
462{
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200463 osmo_init_logging(&info);
464 tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn");
465 tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
466
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100467 sgsn_auth_init(sgsn);
468
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200469 test_llme();
Holger Hans Peter Freyther94246842014-10-02 22:24:47 +0200470 test_gmm_detach();
Jacob Erlbeck0b2da872014-10-27 14:34:13 +0100471 test_gmm_detach_power_off();
Jacob Erlbeck42d284f2014-10-21 13:09:55 +0200472 test_gmm_detach_no_mmctx();
Jacob Erlbeckb35ee6b2014-10-28 09:47:03 +0100473 test_gmm_status_no_mmctx();
Jacob Erlbeck7c24b3e2014-10-29 12:11:58 +0100474 test_gmm_attach();
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200475 printf("Done\n");
Holger Hans Peter Freyther232f6212014-09-30 09:10:25 +0200476 return 0;
477}
Holger Hans Peter Freyther49dbcd92014-10-02 21:27:24 +0200478
479
480/* stubs */
481struct osmo_prim_hdr;
482int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
483{
484 abort();
485}