blob: f554db1f4239c0367d33004561c614552b2d3cc1 [file] [log] [blame]
Jacob Erlbeck9114bee2014-08-19 12:21:01 +02001/* Gb-proxy TLLI state handling */
2
3/* (C) 2014 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 Affero General Public License as published by
8 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
Harald Welte6e688082014-08-24 17:38:18 +020021#include <osmocom/gsm/gsm48.h>
22
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020023#include <openbsc/gb_proxy.h>
24
25#include <openbsc/gprs_utils.h>
26#include <openbsc/gprs_gb_parse.h>
27
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020028#include <openbsc/debug.h>
29
30#include <osmocom/gsm/gsm_utils.h>
31
32#include <osmocom/core/rate_ctr.h>
33#include <osmocom/core/talloc.h>
34
35struct gbproxy_tlli_info *gbproxy_find_tlli(struct gbproxy_peer *peer,
36 uint32_t tlli)
37{
38 struct gbproxy_tlli_info *tlli_info;
39 struct gbproxy_patch_state *state = &peer->patch_state;
40
41 llist_for_each_entry(tlli_info, &state->enabled_tllis, list)
42 if (tlli_info->tlli.current == tlli ||
43 tlli_info->tlli.assigned == tlli)
44 return tlli_info;
45
46 return NULL;
47}
48
49struct gbproxy_tlli_info *gbproxy_find_tlli_by_ptmsi(
50 struct gbproxy_peer *peer,
51 uint32_t ptmsi)
52{
53 struct gbproxy_tlli_info *tlli_info;
54 struct gbproxy_patch_state *state = &peer->patch_state;
55
56 llist_for_each_entry(tlli_info, &state->enabled_tllis, list)
57 if (tlli_info->tlli.ptmsi == ptmsi)
58 return tlli_info;
59
60 return NULL;
61}
62
63struct gbproxy_tlli_info *gbproxy_find_tlli_by_sgsn_tlli(
64 struct gbproxy_peer *peer,
65 uint32_t tlli)
66{
67 struct gbproxy_tlli_info *tlli_info;
68 struct gbproxy_patch_state *state = &peer->patch_state;
69
70 llist_for_each_entry(tlli_info, &state->enabled_tllis, list)
71 if (tlli_info->sgsn_tlli.current == tlli ||
72 tlli_info->sgsn_tlli.assigned == tlli)
73 return tlli_info;
74
75 return NULL;
76}
77
78struct gbproxy_tlli_info *gbproxy_find_tlli_by_mi(
79 struct gbproxy_peer *peer,
80 const uint8_t *mi_data,
81 size_t mi_data_len)
82{
83 struct gbproxy_tlli_info *tlli_info;
84 struct gbproxy_patch_state *state = &peer->patch_state;
85
86 if (!gprs_is_mi_imsi(mi_data, mi_data_len))
87 return NULL;
88
89 llist_for_each_entry(tlli_info, &state->enabled_tllis, list) {
90 if (tlli_info->mi_data_len != mi_data_len)
91 continue;
92 if (memcmp(tlli_info->mi_data, mi_data, mi_data_len) != 0)
93 continue;
94
95 return tlli_info;
96 }
97
98 return NULL;
99}
100
101void gbproxy_delete_tlli(struct gbproxy_peer *peer,
102 struct gbproxy_tlli_info *tlli_info)
103{
104 struct gbproxy_patch_state *state = &peer->patch_state;
105
106 llist_del(&tlli_info->list);
107 talloc_free(tlli_info);
108 state->enabled_tllis_count -= 1;
109
110 peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
111 state->enabled_tllis_count;
112}
113
114void gbproxy_delete_tllis(struct gbproxy_peer *peer)
115{
116 struct gbproxy_tlli_info *tlli_info, *nxt;
117 struct gbproxy_patch_state *state = &peer->patch_state;
118
119 llist_for_each_entry_safe(tlli_info, nxt, &state->enabled_tllis, list)
120 gbproxy_delete_tlli(peer, tlli_info);
121
122 OSMO_ASSERT(state->enabled_tllis_count == 0);
123 OSMO_ASSERT(llist_empty(&state->enabled_tllis));
124}
125
126static void gbproxy_attach_tlli_info(struct gbproxy_peer *peer, time_t now,
127 struct gbproxy_tlli_info *tlli_info)
128{
129 struct gbproxy_patch_state *state = &peer->patch_state;
130
131 tlli_info->timestamp = now;
132 llist_add(&tlli_info->list, &state->enabled_tllis);
133 state->enabled_tllis_count += 1;
134
135 peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
136 state->enabled_tllis_count;
137}
138
139int gbproxy_remove_stale_tllis(struct gbproxy_peer *peer, time_t now)
140{
141 struct gbproxy_patch_state *state = &peer->patch_state;
142 int exceeded_max_len = 0;
143 int deleted_count = 0;
144 int check_for_age;
145
146 if (peer->cfg->tlli_max_len > 0)
147 exceeded_max_len =
148 state->enabled_tllis_count - peer->cfg->tlli_max_len;
149
150 check_for_age = peer->cfg->tlli_max_age > 0;
151
152 for (; exceeded_max_len > 0; exceeded_max_len--) {
153 struct gbproxy_tlli_info *tlli_info;
154 OSMO_ASSERT(!llist_empty(&state->enabled_tllis));
155 tlli_info = llist_entry(state->enabled_tllis.prev,
156 struct gbproxy_tlli_info,
157 list);
158 LOGP(DGPRS, LOGL_INFO,
159 "Removing TLLI %08x from list "
160 "(stale, length %d, max_len exceeded)\n",
161 tlli_info->tlli.current, state->enabled_tllis_count);
162
163 gbproxy_delete_tlli(peer, tlli_info);
164 deleted_count += 1;
165 }
166
167 while (check_for_age && !llist_empty(&state->enabled_tllis)) {
168 time_t age;
169 struct gbproxy_tlli_info *tlli_info;
170 tlli_info = llist_entry(state->enabled_tllis.prev,
171 struct gbproxy_tlli_info,
172 list);
173 age = now - tlli_info->timestamp;
174 /* age < 0 only happens after system time jumps, discard entry */
175 if (age <= peer->cfg->tlli_max_age && age >= 0) {
176 check_for_age = 0;
177 continue;
178 }
179
180 LOGP(DGPRS, LOGL_INFO,
181 "Removing TLLI %08x from list "
182 "(stale, age %d, max_age exceeded)\n",
183 tlli_info->tlli.current, (int)age);
184
185 gbproxy_delete_tlli(peer, tlli_info);
186 deleted_count += 1;
187 }
188
189 return deleted_count;
190}
191
192static struct gbproxy_tlli_info *gbproxy_tlli_info_alloc(
193 struct gbproxy_peer *peer)
194{
195 struct gbproxy_tlli_info *tlli_info;
196
197 tlli_info = talloc_zero(peer, struct gbproxy_tlli_info);
198 tlli_info->tlli.ptmsi = GSM_RESERVED_TMSI;
199 tlli_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI;
200
201 return tlli_info;
202}
203
204static void gbproxy_detach_tlli_info(
205 struct gbproxy_peer *peer,
206 struct gbproxy_tlli_info *tlli_info)
207{
208 struct gbproxy_patch_state *state = &peer->patch_state;
209
210 llist_del(&tlli_info->list);
211 OSMO_ASSERT(state->enabled_tllis_count > 0);
212 state->enabled_tllis_count -= 1;
213
214 peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
215 state->enabled_tllis_count;
216}
217
218static void gbproxy_update_tlli_info(struct gbproxy_tlli_info *tlli_info,
219 const uint8_t *imsi, size_t imsi_len)
220{
221 if (!gprs_is_mi_imsi(imsi, imsi_len))
222 return;
223
224 tlli_info->mi_data_len = imsi_len;
225 tlli_info->mi_data =
226 talloc_realloc_size(tlli_info, tlli_info->mi_data, imsi_len);
227 OSMO_ASSERT(tlli_info->mi_data != NULL);
228 memcpy(tlli_info->mi_data, imsi, imsi_len);
229}
230
231void gbproxy_reassign_tlli(struct gbproxy_tlli_state *tlli_state,
232 struct gbproxy_peer *peer, uint32_t new_tlli)
233{
234 if (new_tlli == tlli_state->current)
235 return;
236
237 LOGP(DGPRS, LOGL_INFO,
238 "The TLLI has been reassigned from %08x to %08x\n",
239 tlli_state->current, new_tlli);
240
241 /* Remember assigned TLLI */
242 tlli_state->assigned = new_tlli;
243 tlli_state->bss_validated = 0;
244 tlli_state->net_validated = 0;
245}
246
247uint32_t gbproxy_map_tlli(uint32_t other_tlli,
248 struct gbproxy_tlli_info *tlli_info, int to_bss)
249{
250 uint32_t tlli = 0;
251 struct gbproxy_tlli_state *src, *dst;
252 if (to_bss) {
253 src = &tlli_info->sgsn_tlli;
254 dst = &tlli_info->tlli;
255 } else {
256 src = &tlli_info->tlli;
257 dst = &tlli_info->sgsn_tlli;
258 }
259 if (src->current == other_tlli)
260 tlli = dst->current;
261 else if (src->assigned == other_tlli)
262 tlli = dst->assigned;
263
264 return tlli;
265}
266
267static void gbproxy_validate_tlli(struct gbproxy_tlli_state *tlli_state,
268 uint32_t tlli, int to_bss)
269{
270 LOGP(DGPRS, LOGL_DEBUG,
271 "%s({current = %08x, assigned = %08x, net_vld = %d, bss_vld = %d}, %08x)\n",
272 __func__, tlli_state->current, tlli_state->assigned,
273 tlli_state->net_validated, tlli_state->bss_validated, tlli);
274
275 if (!tlli_state->assigned || tlli_state->assigned != tlli)
276 return;
277
278 /* TODO: Is this ok? Check spec */
279 if (gprs_tlli_type(tlli) != TLLI_LOCAL)
280 return;
281
282 /* See GSM 04.08, 4.7.1.5 */
283 if (to_bss)
284 tlli_state->net_validated = 1;
285 else
286 tlli_state->bss_validated = 1;
287
288 if (!tlli_state->bss_validated || !tlli_state->net_validated)
289 return;
290
291 LOGP(DGPRS, LOGL_INFO,
292 "The TLLI %08x has been validated (was %08x)\n",
293 tlli_state->assigned, tlli_state->current);
294
295 tlli_state->current = tlli;
296 tlli_state->assigned = 0;
297}
298
299void gbproxy_touch_tlli(struct gbproxy_peer *peer,
300 struct gbproxy_tlli_info *tlli_info, time_t now)
301{
302 gbproxy_detach_tlli_info(peer, tlli_info);
303 gbproxy_attach_tlli_info(peer, now, tlli_info);
304}
305
306struct gbproxy_tlli_info *gbproxy_register_tlli(
307 struct gbproxy_peer *peer, uint32_t tlli,
308 const uint8_t *imsi, size_t imsi_len, time_t now)
309{
310 struct gbproxy_tlli_info *tlli_info;
311 int enable_patching = -1;
312 int tlli_already_known;
313
314 /* Check, whether the IMSI matches */
315 if (gprs_is_mi_imsi(imsi, imsi_len)) {
316 enable_patching = gbproxy_check_imsi(peer, imsi, imsi_len);
317 if (enable_patching < 0)
318 return NULL;
319 }
320
321 tlli_info = gbproxy_find_tlli(peer, tlli);
322
323 if (!tlli_info) {
324 tlli_info = gbproxy_find_tlli_by_mi(peer, imsi, imsi_len);
325
326 if (tlli_info) {
327 /* TLLI has changed somehow, adjust it */
328 LOGP(DGPRS, LOGL_INFO,
329 "The TLLI has changed from %08x to %08x\n",
330 tlli_info->tlli.current, tlli);
331 tlli_info->tlli.current = tlli;
332 }
333 }
334
335 if (!tlli_info) {
336 tlli_info = gbproxy_tlli_info_alloc(peer);
337 tlli_info->tlli.current = tlli;
338 } else {
339 gbproxy_detach_tlli_info(peer, tlli_info);
340 tlli_already_known = 1;
341 }
342
343 OSMO_ASSERT(tlli_info != NULL);
344
345 if (!tlli_already_known)
346 LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n", tlli);
347
348 gbproxy_attach_tlli_info(peer, now, tlli_info);
349 gbproxy_update_tlli_info(tlli_info, imsi, imsi_len);
350
351 if (enable_patching >= 0)
352 tlli_info->enable_patching = enable_patching;
353
354 return tlli_info;
355}
356
357static void gbproxy_unregister_tlli(struct gbproxy_peer *peer, uint32_t tlli)
358{
359 struct gbproxy_tlli_info *tlli_info;
360
361 tlli_info = gbproxy_find_tlli(peer, tlli);
362 if (tlli_info) {
363 LOGP(DGPRS, LOGL_INFO,
364 "Removing TLLI %08x from list\n",
365 tlli);
366 gbproxy_delete_tlli(peer, tlli_info);
367 }
368}
369
370int gbproxy_check_tlli(struct gbproxy_peer *peer, uint32_t tlli)
371{
372 struct gbproxy_tlli_info *tlli_info;
373
374 LOGP(DGPRS, LOGL_INFO, "Checking TLLI %08x, class: %d\n",
375 tlli, gprs_tlli_type(tlli));
376
377 if (!peer->cfg->check_imsi)
378 return 1;
379
380 tlli_info = gbproxy_find_tlli(peer, tlli);
381
382 return tlli_info != NULL && tlli_info->enable_patching;
383}
384
385struct gbproxy_tlli_info *gbproxy_update_tlli_state_ul(
386 struct gbproxy_peer *peer,
387 time_t now,
388 struct gprs_gb_parse_context *parse_ctx)
389{
390 struct gbproxy_tlli_info *tlli_info = NULL;
391
392 if (parse_ctx->tlli_enc)
393 tlli_info = gbproxy_find_tlli(peer, parse_ctx->tlli);
394
395 if (parse_ctx->tlli_enc && parse_ctx->llc) {
396 uint32_t sgsn_tlli;
397 if (!tlli_info) {
398 tlli_info =
399 gbproxy_register_tlli(peer, parse_ctx->tlli,
400 parse_ctx->imsi,
401 parse_ctx->imsi_len, now);
402 /* Setup TLLIs */
403 sgsn_tlli = gbproxy_make_sgsn_tlli(peer, tlli_info,
404 parse_ctx->tlli);
405 tlli_info->sgsn_tlli.current = sgsn_tlli;
406 } else {
407 sgsn_tlli = gbproxy_map_tlli(parse_ctx->tlli, tlli_info, 0);
408 if (!sgsn_tlli)
409 sgsn_tlli = gbproxy_make_sgsn_tlli(peer, tlli_info,
410 parse_ctx->tlli);
411
412 gbproxy_validate_tlli(&tlli_info->tlli,
413 parse_ctx->tlli, 0);
414 gbproxy_validate_tlli(&tlli_info->sgsn_tlli,
415 sgsn_tlli, 0);
416 gbproxy_touch_tlli(peer, tlli_info, now);
417 }
418 } else if (tlli_info) {
419 gbproxy_touch_tlli(peer, tlli_info, now);
420 }
421
422 if (parse_ctx->imsi && tlli_info && tlli_info->mi_data_len == 0) {
423 int enable_patching;
424 gbproxy_update_tlli_info(tlli_info,
425 parse_ctx->imsi, parse_ctx->imsi_len);
426
427 /* Check, whether the IMSI matches */
428 enable_patching = gbproxy_check_imsi(peer, parse_ctx->imsi,
429 parse_ctx->imsi_len);
430 if (enable_patching >= 0)
431 tlli_info->enable_patching = enable_patching;
432 }
433
434 return tlli_info;
435}
436
437struct gbproxy_tlli_info *gbproxy_update_tlli_state_dl(
438 struct gbproxy_peer *peer,
439 time_t now,
440 struct gprs_gb_parse_context *parse_ctx)
441{
442 struct gbproxy_tlli_info *tlli_info = NULL;
443
444 if (parse_ctx->tlli_enc)
445 tlli_info = gbproxy_find_tlli_by_sgsn_tlli(peer, parse_ctx->tlli);
446
447 if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc) {
448 /* A new PTMSI has been signaled in the message,
449 * register new TLLI */
450 uint32_t new_sgsn_ptmsi;
451 uint32_t new_sgsn_tlli;
452 uint32_t new_bss_ptmsi;
453 uint32_t new_bss_tlli = 0;
454 if (!gprs_parse_mi_tmsi(parse_ctx->new_ptmsi_enc, GSM48_TMSI_LEN,
455 &new_sgsn_ptmsi)) {
456 LOGP(DGPRS, LOGL_ERROR,
457 "Failed to parse new TLLI/PTMSI (current is %08x)\n",
458 parse_ctx->tlli);
459 return tlli_info;
460 }
461 new_sgsn_tlli = gprs_tmsi2tlli(new_sgsn_ptmsi, TLLI_LOCAL);
462 new_bss_ptmsi = gbproxy_make_bss_ptmsi(peer, new_sgsn_ptmsi);
463 if (new_bss_ptmsi != GSM_RESERVED_TMSI)
464 new_bss_tlli = gprs_tmsi2tlli(new_bss_ptmsi, TLLI_LOCAL);
465 LOGP(DGPRS, LOGL_INFO,
466 "Got new TLLI(PTMSI) %08x(%08x) from SGSN, using %08x(%08x)\n",
467 new_sgsn_tlli, new_sgsn_ptmsi, new_bss_tlli, new_bss_ptmsi);
468 if (tlli_info) {
469 gbproxy_reassign_tlli(&tlli_info->sgsn_tlli,
470 peer, new_sgsn_tlli);
471 gbproxy_reassign_tlli(&tlli_info->tlli,
472 peer, new_bss_tlli);
473 gbproxy_touch_tlli(peer, tlli_info, now);
474 } else {
475 tlli_info = gbproxy_tlli_info_alloc(peer);
476 LOGP(DGPRS, LOGL_INFO,
477 "Adding TLLI %08x to list (SGSN, new P-TMSI)\n",
478 new_sgsn_tlli);
479
480 gbproxy_attach_tlli_info(peer, now, tlli_info);
481 /* Setup TLLIs */
482 tlli_info->sgsn_tlli.current = new_sgsn_tlli;
483 }
484 /* Setup PTMSIs */
485 tlli_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi;
486 tlli_info->tlli.ptmsi = new_bss_ptmsi;
487 } else if (parse_ctx->tlli_enc && parse_ctx->llc && !tlli_info) {
488 /* Unknown SGSN TLLI */
489 tlli_info = gbproxy_tlli_info_alloc(peer);
490 LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list (SGSN)\n",
491 parse_ctx->tlli);
492
493 gbproxy_attach_tlli_info(peer, now, tlli_info);
494 /* Setup TLLIs */
495 tlli_info->sgsn_tlli.current = parse_ctx->tlli;
496 if (peer->cfg->patch_ptmsi) {
497 /* TODO: We don't know the local TLLI here, perhaps add
498 * a workaround that derives a PTMSI from the SGSN TLLI
499 * and use that to get the missing values. This may
500 * only happen when the gbproxy has been restarted or a
501 * tlli_info has been discarded due to age or queue
502 * length.
503 */
504 tlli_info->tlli.current = 0;
505 } else {
506 tlli_info->tlli.current = tlli_info->sgsn_tlli.current;
507 }
508 } else if (parse_ctx->tlli_enc && parse_ctx->llc && tlli_info) {
509 uint32_t bss_tlli = gbproxy_map_tlli(parse_ctx->tlli,
510 tlli_info, 1);
511 gbproxy_validate_tlli(&tlli_info->sgsn_tlli, parse_ctx->tlli, 1);
512 gbproxy_validate_tlli(&tlli_info->tlli, bss_tlli, 1);
513 gbproxy_touch_tlli(peer, tlli_info, now);
514 } else if (tlli_info) {
515 gbproxy_touch_tlli(peer, tlli_info, now);
516 }
517
518 if (parse_ctx->imsi && tlli_info && tlli_info->mi_data_len == 0) {
519 int enable_patching;
520 gbproxy_update_tlli_info(tlli_info,
521 parse_ctx->imsi, parse_ctx->imsi_len);
522
523 /* Check, whether the IMSI matches */
524 enable_patching = gbproxy_check_imsi(peer, parse_ctx->imsi,
525 parse_ctx->imsi_len);
526 if (enable_patching >= 0)
527 tlli_info->enable_patching = enable_patching;
528 }
529
530 return tlli_info;
531}
532
533void gbproxy_update_tlli_state_after(
534 struct gbproxy_peer *peer,
535 struct gbproxy_tlli_info *tlli_info,
536 time_t now,
537 struct gprs_gb_parse_context *parse_ctx)
538{
539 if (parse_ctx->invalidate_tlli)
540 gbproxy_unregister_tlli(peer, parse_ctx->tlli);
541
542 gbproxy_remove_stale_tllis(peer, now);
543}
544
545