blob: e9271c22c74c99864306921338fa95b9e93961dd [file] [log] [blame]
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +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 <osmocom/gsm/gsm48.h>
22
23#include <osmocom/sgsn/gb_proxy.h>
24
25#include <osmocom/sgsn/gprs_utils.h>
26#include <osmocom/sgsn/gprs_gb_parse.h>
27
28#include <osmocom/sgsn/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_link_info *gbproxy_link_info_by_tlli(struct gbproxy_peer *peer,
36 uint32_t tlli)
37{
38 struct gbproxy_link_info *link_info;
39 struct gbproxy_patch_state *state = &peer->patch_state;
40
41 if (!tlli)
42 return NULL;
43
44 llist_for_each_entry(link_info, &state->logical_links, list)
45 if (link_info->tlli.current == tlli ||
46 link_info->tlli.assigned == tlli)
47 return link_info;
48
49 return NULL;
50}
51
52struct gbproxy_link_info *gbproxy_link_info_by_ptmsi(
53 struct gbproxy_peer *peer,
54 uint32_t ptmsi)
55{
56 struct gbproxy_link_info *link_info;
57 struct gbproxy_patch_state *state = &peer->patch_state;
58
59 if (ptmsi == GSM_RESERVED_TMSI)
60 return NULL;
61
62 llist_for_each_entry(link_info, &state->logical_links, list)
63 if (link_info->tlli.ptmsi == ptmsi)
64 return link_info;
65
66 return NULL;
67}
68
69struct gbproxy_link_info *gbproxy_link_info_by_any_sgsn_tlli(
70 struct gbproxy_peer *peer,
71 uint32_t tlli)
72{
73 struct gbproxy_link_info *link_info;
74 struct gbproxy_patch_state *state = &peer->patch_state;
75
76 if (!tlli)
77 return NULL;
78
79 /* Don't care about the NSEI */
80 llist_for_each_entry(link_info, &state->logical_links, list)
81 if (link_info->sgsn_tlli.current == tlli ||
82 link_info->sgsn_tlli.assigned == tlli)
83 return link_info;
84
85 return NULL;
86}
87
88struct gbproxy_link_info *gbproxy_link_info_by_sgsn_tlli(
89 struct gbproxy_peer *peer,
90 uint32_t tlli, uint32_t sgsn_nsei)
91{
92 struct gbproxy_link_info *link_info;
93 struct gbproxy_patch_state *state = &peer->patch_state;
94
95 if (!tlli)
96 return NULL;
97
98 llist_for_each_entry(link_info, &state->logical_links, list)
99 if ((link_info->sgsn_tlli.current == tlli ||
100 link_info->sgsn_tlli.assigned == tlli) &&
101 link_info->sgsn_nsei == sgsn_nsei)
102 return link_info;
103
104 return NULL;
105}
106
107struct gbproxy_link_info *gbproxy_link_info_by_imsi(
108 struct gbproxy_peer *peer,
109 const uint8_t *imsi,
110 size_t imsi_len)
111{
112 struct gbproxy_link_info *link_info;
113 struct gbproxy_patch_state *state = &peer->patch_state;
114
115 if (!gprs_is_mi_imsi(imsi, imsi_len))
116 return NULL;
117
118 llist_for_each_entry(link_info, &state->logical_links, list) {
119 if (link_info->imsi_len != imsi_len)
120 continue;
121 if (memcmp(link_info->imsi, imsi, imsi_len) != 0)
122 continue;
123
124 return link_info;
125 }
126
127 return NULL;
128}
129
130void gbproxy_link_info_discard_messages(struct gbproxy_link_info *link_info)
131{
132 struct msgb *msg, *nxt;
133
134 llist_for_each_entry_safe(msg, nxt, &link_info->stored_msgs, list) {
135 llist_del(&msg->list);
136 msgb_free(msg);
137 }
138}
139
140void gbproxy_delete_link_info(struct gbproxy_peer *peer,
141 struct gbproxy_link_info *link_info)
142{
143 struct gbproxy_patch_state *state = &peer->patch_state;
144
145 gbproxy_link_info_discard_messages(link_info);
146
147 llist_del(&link_info->list);
148 talloc_free(link_info);
149 state->logical_link_count -= 1;
150
151 peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
152 state->logical_link_count;
153}
154
155void gbproxy_delete_link_infos(struct gbproxy_peer *peer)
156{
157 struct gbproxy_link_info *link_info, *nxt;
158 struct gbproxy_patch_state *state = &peer->patch_state;
159
160 llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list)
161 gbproxy_delete_link_info(peer, link_info);
162
163 OSMO_ASSERT(state->logical_link_count == 0);
164 OSMO_ASSERT(llist_empty(&state->logical_links));
165}
166
167void gbproxy_attach_link_info(struct gbproxy_peer *peer, time_t now,
168 struct gbproxy_link_info *link_info)
169{
170 struct gbproxy_patch_state *state = &peer->patch_state;
171
172 link_info->timestamp = now;
173 llist_add(&link_info->list, &state->logical_links);
174 state->logical_link_count += 1;
175
176 peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
177 state->logical_link_count;
178}
179
180int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now)
181{
182 struct gbproxy_patch_state *state = &peer->patch_state;
183 int exceeded_max_len = 0;
184 int deleted_count = 0;
185 int check_for_age;
186
187 if (peer->cfg->tlli_max_len > 0)
188 exceeded_max_len =
189 state->logical_link_count - peer->cfg->tlli_max_len;
190
191 check_for_age = peer->cfg->tlli_max_age > 0;
192
193 for (; exceeded_max_len > 0; exceeded_max_len--) {
194 struct gbproxy_link_info *link_info;
195 OSMO_ASSERT(!llist_empty(&state->logical_links));
196 link_info = llist_entry(state->logical_links.prev,
197 struct gbproxy_link_info,
198 list);
199 LOGP(DGPRS, LOGL_INFO,
200 "Removing TLLI %08x from list "
201 "(stale, length %d, max_len exceeded)\n",
202 link_info->tlli.current, state->logical_link_count);
203
204 gbproxy_delete_link_info(peer, link_info);
205 deleted_count += 1;
206 }
207
208 while (check_for_age && !llist_empty(&state->logical_links)) {
209 time_t age;
210 struct gbproxy_link_info *link_info;
211 link_info = llist_entry(state->logical_links.prev,
212 struct gbproxy_link_info,
213 list);
214 age = now - link_info->timestamp;
215 /* age < 0 only happens after system time jumps, discard entry */
216 if (age <= peer->cfg->tlli_max_age && age >= 0) {
217 check_for_age = 0;
218 continue;
219 }
220
221 LOGP(DGPRS, LOGL_INFO,
222 "Removing TLLI %08x from list "
223 "(stale, age %d, max_age exceeded)\n",
224 link_info->tlli.current, (int)age);
225
226 gbproxy_delete_link_info(peer, link_info);
227 deleted_count += 1;
228 }
229
230 return deleted_count;
231}
232
233struct gbproxy_link_info *gbproxy_link_info_alloc( struct gbproxy_peer *peer)
234{
235 struct gbproxy_link_info *link_info;
236
237 link_info = talloc_zero(peer, struct gbproxy_link_info);
238 link_info->tlli.ptmsi = GSM_RESERVED_TMSI;
239 link_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI;
240
241 link_info->vu_gen_tx_bss = GBPROXY_INIT_VU_GEN_TX;
242
243 INIT_LLIST_HEAD(&link_info->stored_msgs);
244
245 return link_info;
246}
247
248void gbproxy_detach_link_info(
249 struct gbproxy_peer *peer,
250 struct gbproxy_link_info *link_info)
251{
252 struct gbproxy_patch_state *state = &peer->patch_state;
253
254 llist_del(&link_info->list);
255 OSMO_ASSERT(state->logical_link_count > 0);
256 state->logical_link_count -= 1;
257
258 peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
259 state->logical_link_count;
260}
261
262void gbproxy_update_link_info(struct gbproxy_link_info *link_info,
263 const uint8_t *imsi, size_t imsi_len)
264{
265 if (!gprs_is_mi_imsi(imsi, imsi_len))
266 return;
267
268 link_info->imsi_len = imsi_len;
269 link_info->imsi =
270 talloc_realloc_size(link_info, link_info->imsi, imsi_len);
271 OSMO_ASSERT(link_info->imsi != NULL);
272 memcpy(link_info->imsi, imsi, imsi_len);
273}
274
275void gbproxy_reassign_tlli(struct gbproxy_tlli_state *tlli_state,
276 struct gbproxy_peer *peer, uint32_t new_tlli)
277{
278 if (new_tlli == tlli_state->current)
279 return;
280
281 LOGP(DGPRS, LOGL_INFO,
282 "The TLLI has been reassigned from %08x to %08x\n",
283 tlli_state->current, new_tlli);
284
285 /* Remember assigned TLLI */
286 tlli_state->assigned = new_tlli;
287 tlli_state->bss_validated = false;
288 tlli_state->net_validated = false;
289}
290
291uint32_t gbproxy_map_tlli(uint32_t other_tlli,
292 struct gbproxy_link_info *link_info, int to_bss)
293{
294 uint32_t tlli = 0;
295 struct gbproxy_tlli_state *src, *dst;
296 if (to_bss) {
297 src = &link_info->sgsn_tlli;
298 dst = &link_info->tlli;
299 } else {
300 src = &link_info->tlli;
301 dst = &link_info->sgsn_tlli;
302 }
303 if (src->current == other_tlli)
304 tlli = dst->current;
305 else if (src->assigned == other_tlli)
306 tlli = dst->assigned;
307
308 return tlli;
309}
310
311static void gbproxy_validate_tlli(struct gbproxy_tlli_state *tlli_state,
312 uint32_t tlli, int to_bss)
313{
314 LOGP(DGPRS, LOGL_DEBUG,
315 "%s({current = %08x, assigned = %08x, net_vld = %d, bss_vld = %d}, %08x)\n",
316 __func__, tlli_state->current, tlli_state->assigned,
317 tlli_state->net_validated, tlli_state->bss_validated, tlli);
318
319 if (!tlli_state->assigned || tlli_state->assigned != tlli)
320 return;
321
322 /* TODO: Is this ok? Check spec */
323 if (gprs_tlli_type(tlli) != TLLI_LOCAL)
324 return;
325
326 /* See GSM 04.08, 4.7.1.5 */
327 if (to_bss)
328 tlli_state->net_validated = true;
329 else
330 tlli_state->bss_validated = true;
331
332 if (!tlli_state->bss_validated || !tlli_state->net_validated)
333 return;
334
335 LOGP(DGPRS, LOGL_INFO,
336 "The TLLI %08x has been validated (was %08x)\n",
337 tlli_state->assigned, tlli_state->current);
338
339 tlli_state->current = tlli;
340 tlli_state->assigned = 0;
341}
342
343static void gbproxy_touch_link_info(struct gbproxy_peer *peer,
344 struct gbproxy_link_info *link_info,
345 time_t now)
346{
347 gbproxy_detach_link_info(peer, link_info);
348 gbproxy_attach_link_info(peer, now, link_info);
349}
350
351static int gbproxy_unregister_link_info(struct gbproxy_peer *peer,
352 struct gbproxy_link_info *link_info)
353{
354 if (!link_info)
355 return 1;
356
357 if (link_info->tlli.ptmsi == GSM_RESERVED_TMSI && !link_info->imsi_len) {
358 LOGP(DGPRS, LOGL_INFO,
359 "Removing TLLI %08x from list (P-TMSI or IMSI are not set)\n",
360 link_info->tlli.current);
361 gbproxy_delete_link_info(peer, link_info);
362 return 1;
363 }
364
365 link_info->tlli.current = 0;
366 link_info->tlli.assigned = 0;
367 link_info->sgsn_tlli.current = 0;
368 link_info->sgsn_tlli.assigned = 0;
369
370 link_info->is_deregistered = true;
371
372 gbproxy_reset_link(link_info);
373
374 return 0;
375}
376
377int gbproxy_imsi_matches(struct gbproxy_config *cfg,
378 enum gbproxy_match_id match_id,
379 struct gbproxy_link_info *link_info)
380{
381 struct gbproxy_match *match;
382 OSMO_ASSERT(match_id >= 0 && match_id < ARRAY_SIZE(cfg->matches));
383
384 match = &cfg->matches[match_id];
385 if (!match->enable)
386 return 1;
387
388 return link_info != NULL && link_info->is_matching[match_id];
389}
390
391static void gbproxy_assign_imsi(struct gbproxy_peer *peer,
392 struct gbproxy_link_info *link_info,
393 struct gprs_gb_parse_context *parse_ctx)
394{
395 int imsi_matches;
396 struct gbproxy_link_info *other_link_info;
397 enum gbproxy_match_id match_id;
398
399 /* Make sure that there is a second entry with the same IMSI */
400 other_link_info = gbproxy_link_info_by_imsi(
401 peer, parse_ctx->imsi, parse_ctx->imsi_len);
402
403 if (other_link_info && other_link_info != link_info) {
Neels Hofmeyr7facc862020-05-29 16:53:23 +0200404 struct osmo_mobile_identity mi;
405 if (osmo_mobile_identity_decode(&mi, parse_ctx->imsi, parse_ctx->imsi_len, false)
406 || mi.type != GSM_MI_TYPE_IMSI) {
407 LOGP(DGPRS, LOGL_ERROR, "Failed to decode Mobile Identity\n");
408 } else {
409 LOGP(DGPRS, LOGL_INFO,
410 "Removing TLLI %08x from list (IMSI %s re-used)\n",
411 other_link_info->tlli.current, mi.imsi);
412 gbproxy_delete_link_info(peer, other_link_info);
413 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200414 }
415
416 /* Update the IMSI field */
417 gbproxy_update_link_info(link_info,
418 parse_ctx->imsi, parse_ctx->imsi_len);
419
420 /* Check, whether the IMSI matches */
421 OSMO_ASSERT(ARRAY_SIZE(link_info->is_matching) ==
422 ARRAY_SIZE(peer->cfg->matches));
423 for (match_id = 0; match_id < ARRAY_SIZE(link_info->is_matching);
424 ++match_id) {
425 imsi_matches = gbproxy_check_imsi(
426 &peer->cfg->matches[match_id],
427 parse_ctx->imsi, parse_ctx->imsi_len);
428 if (imsi_matches >= 0)
429 link_info->is_matching[match_id] = imsi_matches ? true : false;
430 }
431}
432
433static int gbproxy_tlli_match(const struct gbproxy_tlli_state *a,
434 const struct gbproxy_tlli_state *b)
435{
436 if (a->current && a->current == b->current)
437 return 1;
438
439 if (a->assigned && a->assigned == b->assigned)
440 return 1;
441
442 if (a->ptmsi != GSM_RESERVED_TMSI && a->ptmsi == b->ptmsi)
443 return 1;
444
445 return 0;
446}
447
448static void gbproxy_remove_matching_link_infos(
449 struct gbproxy_peer *peer, struct gbproxy_link_info *link_info)
450{
451 struct gbproxy_link_info *info, *nxt;
452 struct gbproxy_patch_state *state = &peer->patch_state;
453
454 /* Make sure that there is no second entry with the same P-TMSI or TLLI */
455 llist_for_each_entry_safe(info, nxt, &state->logical_links, list) {
456 if (info == link_info)
457 continue;
458
459 if (!gbproxy_tlli_match(&link_info->tlli, &info->tlli) &&
460 (link_info->sgsn_nsei != info->sgsn_nsei ||
461 !gbproxy_tlli_match(&link_info->sgsn_tlli, &info->sgsn_tlli)))
462 continue;
463
464 LOGP(DGPRS, LOGL_INFO,
465 "Removing TLLI %08x from list (P-TMSI/TLLI re-used)\n",
466 info->tlli.current);
467 gbproxy_delete_link_info(peer, info);
468 }
469}
470
471static struct gbproxy_link_info *gbproxy_get_link_info_ul(
472 struct gbproxy_peer *peer,
473 int *tlli_is_valid,
474 struct gprs_gb_parse_context *parse_ctx)
475{
476 struct gbproxy_link_info *link_info = NULL;
477
478 if (parse_ctx->tlli_enc) {
479 link_info = gbproxy_link_info_by_tlli(peer, parse_ctx->tlli);
480
481 if (link_info) {
482 *tlli_is_valid = 1;
483 return link_info;
484 }
485 }
486
487 *tlli_is_valid = 0;
488
489 if (!link_info && parse_ctx->imsi) {
490 link_info = gbproxy_link_info_by_imsi(
491 peer, parse_ctx->imsi, parse_ctx->imsi_len);
492 }
493
494 if (!link_info && parse_ctx->ptmsi_enc && !parse_ctx->old_raid_is_foreign) {
495 uint32_t bss_ptmsi;
496 gprs_parse_tmsi(parse_ctx->ptmsi_enc, &bss_ptmsi);
497 link_info = gbproxy_link_info_by_ptmsi(peer, bss_ptmsi);
498 }
499
500 if (!link_info)
501 return NULL;
502
503 link_info->is_deregistered = false;
504
505 return link_info;
506}
507
508struct gbproxy_link_info *gbproxy_update_link_state_ul(
509 struct gbproxy_peer *peer,
510 time_t now,
511 struct gprs_gb_parse_context *parse_ctx)
512{
513 struct gbproxy_link_info *link_info;
514 int tlli_is_valid;
515
516 link_info = gbproxy_get_link_info_ul(peer, &tlli_is_valid, parse_ctx);
517
518 if (parse_ctx->tlli_enc && parse_ctx->llc) {
519 uint32_t sgsn_tlli;
520
521 if (!link_info) {
522 LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n",
523 parse_ctx->tlli);
524 link_info = gbproxy_link_info_alloc(peer);
525 gbproxy_attach_link_info(peer, now, link_info);
526
527 /* Setup TLLIs */
528 sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
529 parse_ctx->tlli);
530 link_info->sgsn_tlli.current = sgsn_tlli;
531 link_info->tlli.current = parse_ctx->tlli;
532 } else if (!tlli_is_valid) {
533 /* New TLLI (info found by IMSI or P-TMSI) */
534 link_info->tlli.current = parse_ctx->tlli;
535 link_info->tlli.assigned = 0;
536 link_info->sgsn_tlli.current =
537 gbproxy_make_sgsn_tlli(peer, link_info,
538 parse_ctx->tlli);
539 link_info->sgsn_tlli.assigned = 0;
540 gbproxy_touch_link_info(peer, link_info, now);
541 } else {
542 sgsn_tlli = gbproxy_map_tlli(parse_ctx->tlli, link_info, 0);
543 if (!sgsn_tlli)
544 sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
545 parse_ctx->tlli);
546
547 gbproxy_validate_tlli(&link_info->tlli,
548 parse_ctx->tlli, 0);
549 gbproxy_validate_tlli(&link_info->sgsn_tlli,
550 sgsn_tlli, 0);
551 gbproxy_touch_link_info(peer, link_info, now);
552 }
553 } else if (link_info) {
554 gbproxy_touch_link_info(peer, link_info, now);
555 }
556
557 if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
558 gbproxy_assign_imsi(peer, link_info, parse_ctx);
559
560 return link_info;
561}
562
563static struct gbproxy_link_info *gbproxy_get_link_info_dl(
564 struct gbproxy_peer *peer,
565 struct gprs_gb_parse_context *parse_ctx)
566{
567 struct gbproxy_link_info *link_info = NULL;
568
569 /* Which key to use depends on its availability only, if that fails, do
570 * not retry it with another key (e.g. IMSI). */
571 if (parse_ctx->tlli_enc)
572 link_info = gbproxy_link_info_by_sgsn_tlli(peer, parse_ctx->tlli,
573 parse_ctx->peer_nsei);
574
575 /* TODO: Get link_info by (SGSN) P-TMSI if that is available (see
576 * GSM 08.18, 7.2) instead of using the IMSI as key. */
577 else if (parse_ctx->imsi)
578 link_info = gbproxy_link_info_by_imsi(
579 peer, parse_ctx->imsi, parse_ctx->imsi_len);
580
581 if (link_info)
582 link_info->is_deregistered = false;
583
584 return link_info;
585}
586
587struct gbproxy_link_info *gbproxy_update_link_state_dl(
588 struct gbproxy_peer *peer,
589 time_t now,
590 struct gprs_gb_parse_context *parse_ctx)
591{
592 struct gbproxy_link_info *link_info = NULL;
593
594 link_info = gbproxy_get_link_info_dl(peer, parse_ctx);
595
596 if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && link_info) {
597 /* A new P-TMSI has been signalled in the message,
598 * register new TLLI */
599 uint32_t new_sgsn_ptmsi;
600 uint32_t new_bss_ptmsi = GSM_RESERVED_TMSI;
601 gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_sgsn_ptmsi);
602
603 if (link_info->sgsn_tlli.ptmsi == new_sgsn_ptmsi)
604 new_bss_ptmsi = link_info->tlli.ptmsi;
605
606 if (new_bss_ptmsi == GSM_RESERVED_TMSI)
607 new_bss_ptmsi = gbproxy_make_bss_ptmsi(peer, new_sgsn_ptmsi);
608
609 LOGP(DGPRS, LOGL_INFO,
610 "Got new PTMSI %08x from SGSN, using %08x for BSS\n",
611 new_sgsn_ptmsi, new_bss_ptmsi);
612 /* Setup PTMSIs */
613 link_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi;
614 link_info->tlli.ptmsi = new_bss_ptmsi;
615 } else if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && !link_info &&
616 !peer->cfg->patch_ptmsi) {
617 /* A new P-TMSI has been signalled in the message with an unknown
618 * TLLI, create a new link_info */
619 /* TODO: Add a test case for this branch */
620 uint32_t new_ptmsi;
621 gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
622
623 LOGP(DGPRS, LOGL_INFO,
624 "Adding TLLI %08x to list (SGSN, new P-TMSI is %08x)\n",
625 parse_ctx->tlli, new_ptmsi);
626
627 link_info = gbproxy_link_info_alloc(peer);
628 link_info->sgsn_tlli.current = parse_ctx->tlli;
629 link_info->tlli.current = parse_ctx->tlli;
630 link_info->sgsn_tlli.ptmsi = new_ptmsi;
631 link_info->tlli.ptmsi = new_ptmsi;
632 gbproxy_attach_link_info(peer, now, link_info);
633 } else if (parse_ctx->tlli_enc && parse_ctx->llc && !link_info &&
634 !peer->cfg->patch_ptmsi) {
635 /* Unknown SGSN TLLI, create a new link_info */
636 uint32_t new_ptmsi;
637 link_info = gbproxy_link_info_alloc(peer);
638 LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list (SGSN)\n",
639 parse_ctx->tlli);
640
641 gbproxy_attach_link_info(peer, now, link_info);
642
643 /* Setup TLLIs */
644 link_info->sgsn_tlli.current = parse_ctx->tlli;
645 link_info->tlli.current = parse_ctx->tlli;
646
647 if (!parse_ctx->new_ptmsi_enc)
648 return link_info;
649 /* A new P-TMSI has been signalled in the message */
650
651 gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
652 LOGP(DGPRS, LOGL_INFO,
653 "Assigning new P-TMSI %08x\n", new_ptmsi);
654 /* Setup P-TMSIs */
655 link_info->sgsn_tlli.ptmsi = new_ptmsi;
656 link_info->tlli.ptmsi = new_ptmsi;
657 } else if (parse_ctx->tlli_enc && parse_ctx->llc && link_info) {
658 uint32_t bss_tlli = gbproxy_map_tlli(parse_ctx->tlli,
659 link_info, 1);
660 gbproxy_validate_tlli(&link_info->sgsn_tlli, parse_ctx->tlli, 1);
661 gbproxy_validate_tlli(&link_info->tlli, bss_tlli, 1);
662 gbproxy_touch_link_info(peer, link_info, now);
663 } else if (link_info) {
664 gbproxy_touch_link_info(peer, link_info, now);
665 }
666
667 if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
668 gbproxy_assign_imsi(peer, link_info, parse_ctx);
669
670 return link_info;
671}
672
673int gbproxy_update_link_state_after(
674 struct gbproxy_peer *peer,
675 struct gbproxy_link_info *link_info,
676 time_t now,
677 struct gprs_gb_parse_context *parse_ctx)
678{
679 int rc = 0;
680 if (parse_ctx->invalidate_tlli && link_info) {
681 int keep_info =
682 peer->cfg->keep_link_infos == GBPROX_KEEP_ALWAYS ||
683 (peer->cfg->keep_link_infos == GBPROX_KEEP_REATTACH &&
684 parse_ctx->await_reattach) ||
685 (peer->cfg->keep_link_infos == GBPROX_KEEP_IDENTIFIED &&
686 link_info->imsi_len > 0);
687 if (keep_info) {
688 LOGP(DGPRS, LOGL_INFO, "Unregistering TLLI %08x\n",
689 link_info->tlli.current);
690 rc = gbproxy_unregister_link_info(peer, link_info);
691 } else {
692 LOGP(DGPRS, LOGL_INFO, "Removing TLLI %08x from list\n",
693 link_info->tlli.current);
694 gbproxy_delete_link_info(peer, link_info);
695 rc = 1;
696 }
697 } else if (parse_ctx->to_bss && parse_ctx->tlli_enc &&
698 parse_ctx->new_ptmsi_enc && link_info) {
699 /* A new PTMSI has been signaled in the message,
700 * register new TLLI */
701 uint32_t new_sgsn_ptmsi = link_info->sgsn_tlli.ptmsi;
702 uint32_t new_bss_ptmsi = link_info->tlli.ptmsi;
703 uint32_t new_sgsn_tlli;
704 uint32_t new_bss_tlli = 0;
705
706 new_sgsn_tlli = gprs_tmsi2tlli(new_sgsn_ptmsi, TLLI_LOCAL);
707 if (new_bss_ptmsi != GSM_RESERVED_TMSI)
708 new_bss_tlli = gprs_tmsi2tlli(new_bss_ptmsi, TLLI_LOCAL);
709 LOGP(DGPRS, LOGL_INFO,
710 "Assigning new TLLI %08x to SGSN, %08x to BSS\n",
711 new_sgsn_tlli, new_bss_tlli);
712
713 gbproxy_reassign_tlli(&link_info->sgsn_tlli,
714 peer, new_sgsn_tlli);
715 gbproxy_reassign_tlli(&link_info->tlli,
716 peer, new_bss_tlli);
717 gbproxy_remove_matching_link_infos(peer, link_info);
718 }
719
720 gbproxy_remove_stale_link_infos(peer, now);
721
722 return rc;
723}
724
725