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