blob: 8aadd2f4498ec0f97ed6520a4538ea1bdb95ffc8 [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
Jacob Erlbeck91a0e862014-09-17 10:56:38 +020063struct gbproxy_tlli_info *gbproxy_find_tlli_by_any_sgsn_tlli(
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020064 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
Jacob Erlbeck91a0e862014-09-17 10:56:38 +020070 /* Don't care about the NSEI */
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020071 llist_for_each_entry(tlli_info, &state->enabled_tllis, list)
72 if (tlli_info->sgsn_tlli.current == tlli ||
Jacob Erlbeck91a0e862014-09-17 10:56:38 +020073 tlli_info->sgsn_tlli.assigned == tlli)
74 return tlli_info;
75
76 return NULL;
77}
78
79struct gbproxy_tlli_info *gbproxy_find_tlli_by_sgsn_tlli(
80 struct gbproxy_peer *peer,
81 uint32_t tlli, uint32_t sgsn_nsei)
82{
83 struct gbproxy_tlli_info *tlli_info;
84 struct gbproxy_patch_state *state = &peer->patch_state;
85
86 llist_for_each_entry(tlli_info, &state->enabled_tllis, list)
87 if ((tlli_info->sgsn_tlli.current == tlli ||
88 tlli_info->sgsn_tlli.assigned == tlli) &&
89 tlli_info->sgsn_nsei == sgsn_nsei)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020090 return tlli_info;
91
92 return NULL;
93}
94
Jacob Erlbeck2fd1ba42014-09-11 14:57:03 +020095struct gbproxy_tlli_info *gbproxy_find_tlli_by_imsi(
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020096 struct gbproxy_peer *peer,
Jacob Erlbeck2fd1ba42014-09-11 14:57:03 +020097 const uint8_t *imsi,
98 size_t imsi_len)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020099{
100 struct gbproxy_tlli_info *tlli_info;
101 struct gbproxy_patch_state *state = &peer->patch_state;
102
Jacob Erlbeck2fd1ba42014-09-11 14:57:03 +0200103 if (!gprs_is_mi_imsi(imsi, imsi_len))
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200104 return NULL;
105
106 llist_for_each_entry(tlli_info, &state->enabled_tllis, list) {
Jacob Erlbeck2fd1ba42014-09-11 14:57:03 +0200107 if (tlli_info->imsi_len != imsi_len)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200108 continue;
Jacob Erlbeck2fd1ba42014-09-11 14:57:03 +0200109 if (memcmp(tlli_info->imsi, imsi, imsi_len) != 0)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200110 continue;
111
112 return tlli_info;
113 }
114
115 return NULL;
116}
117
Jacob Erlbeck31591142014-09-03 11:59:48 +0200118void gbproxy_tlli_info_discard_messages(struct gbproxy_tlli_info *tlli_info)
119{
120 struct msgb *msg, *nxt;
121
122 llist_for_each_entry_safe(msg, nxt, &tlli_info->stored_msgs, list) {
123 llist_del(&msg->list);
124 msgb_free(msg);
125 }
126}
127
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200128void gbproxy_delete_tlli(struct gbproxy_peer *peer,
129 struct gbproxy_tlli_info *tlli_info)
130{
131 struct gbproxy_patch_state *state = &peer->patch_state;
132
Jacob Erlbeck31591142014-09-03 11:59:48 +0200133 gbproxy_tlli_info_discard_messages(tlli_info);
134
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200135 llist_del(&tlli_info->list);
136 talloc_free(tlli_info);
137 state->enabled_tllis_count -= 1;
138
139 peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
140 state->enabled_tllis_count;
141}
142
143void gbproxy_delete_tllis(struct gbproxy_peer *peer)
144{
145 struct gbproxy_tlli_info *tlli_info, *nxt;
146 struct gbproxy_patch_state *state = &peer->patch_state;
147
148 llist_for_each_entry_safe(tlli_info, nxt, &state->enabled_tllis, list)
149 gbproxy_delete_tlli(peer, tlli_info);
150
151 OSMO_ASSERT(state->enabled_tllis_count == 0);
152 OSMO_ASSERT(llist_empty(&state->enabled_tllis));
153}
154
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200155void gbproxy_attach_tlli_info(struct gbproxy_peer *peer, time_t now,
156 struct gbproxy_tlli_info *tlli_info)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200157{
158 struct gbproxy_patch_state *state = &peer->patch_state;
159
160 tlli_info->timestamp = now;
161 llist_add(&tlli_info->list, &state->enabled_tllis);
162 state->enabled_tllis_count += 1;
163
164 peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
165 state->enabled_tllis_count;
166}
167
168int gbproxy_remove_stale_tllis(struct gbproxy_peer *peer, time_t now)
169{
170 struct gbproxy_patch_state *state = &peer->patch_state;
171 int exceeded_max_len = 0;
172 int deleted_count = 0;
173 int check_for_age;
174
175 if (peer->cfg->tlli_max_len > 0)
176 exceeded_max_len =
177 state->enabled_tllis_count - peer->cfg->tlli_max_len;
178
179 check_for_age = peer->cfg->tlli_max_age > 0;
180
181 for (; exceeded_max_len > 0; exceeded_max_len--) {
182 struct gbproxy_tlli_info *tlli_info;
183 OSMO_ASSERT(!llist_empty(&state->enabled_tllis));
184 tlli_info = llist_entry(state->enabled_tllis.prev,
185 struct gbproxy_tlli_info,
186 list);
187 LOGP(DGPRS, LOGL_INFO,
188 "Removing TLLI %08x from list "
189 "(stale, length %d, max_len exceeded)\n",
190 tlli_info->tlli.current, state->enabled_tllis_count);
191
192 gbproxy_delete_tlli(peer, tlli_info);
193 deleted_count += 1;
194 }
195
196 while (check_for_age && !llist_empty(&state->enabled_tllis)) {
197 time_t age;
198 struct gbproxy_tlli_info *tlli_info;
199 tlli_info = llist_entry(state->enabled_tllis.prev,
200 struct gbproxy_tlli_info,
201 list);
202 age = now - tlli_info->timestamp;
203 /* age < 0 only happens after system time jumps, discard entry */
204 if (age <= peer->cfg->tlli_max_age && age >= 0) {
205 check_for_age = 0;
206 continue;
207 }
208
209 LOGP(DGPRS, LOGL_INFO,
210 "Removing TLLI %08x from list "
211 "(stale, age %d, max_age exceeded)\n",
212 tlli_info->tlli.current, (int)age);
213
214 gbproxy_delete_tlli(peer, tlli_info);
215 deleted_count += 1;
216 }
217
218 return deleted_count;
219}
220
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200221struct gbproxy_tlli_info *gbproxy_tlli_info_alloc( struct gbproxy_peer *peer)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200222{
223 struct gbproxy_tlli_info *tlli_info;
224
225 tlli_info = talloc_zero(peer, struct gbproxy_tlli_info);
226 tlli_info->tlli.ptmsi = GSM_RESERVED_TMSI;
227 tlli_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI;
228
Jacob Erlbeck5f4ef322014-08-22 17:10:01 +0200229 INIT_LLIST_HEAD(&tlli_info->stored_msgs);
230
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200231 return tlli_info;
232}
233
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200234void gbproxy_detach_tlli_info(
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200235 struct gbproxy_peer *peer,
236 struct gbproxy_tlli_info *tlli_info)
237{
238 struct gbproxy_patch_state *state = &peer->patch_state;
239
240 llist_del(&tlli_info->list);
241 OSMO_ASSERT(state->enabled_tllis_count > 0);
242 state->enabled_tllis_count -= 1;
243
244 peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
245 state->enabled_tllis_count;
246}
247
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200248void gbproxy_update_tlli_info(struct gbproxy_tlli_info *tlli_info,
249 const uint8_t *imsi, size_t imsi_len)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200250{
251 if (!gprs_is_mi_imsi(imsi, imsi_len))
252 return;
253
Jacob Erlbeck2fd1ba42014-09-11 14:57:03 +0200254 tlli_info->imsi_len = imsi_len;
255 tlli_info->imsi =
256 talloc_realloc_size(tlli_info, tlli_info->imsi, imsi_len);
257 OSMO_ASSERT(tlli_info->imsi != NULL);
258 memcpy(tlli_info->imsi, imsi, imsi_len);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200259}
260
261void gbproxy_reassign_tlli(struct gbproxy_tlli_state *tlli_state,
262 struct gbproxy_peer *peer, uint32_t new_tlli)
263{
264 if (new_tlli == tlli_state->current)
265 return;
266
267 LOGP(DGPRS, LOGL_INFO,
268 "The TLLI has been reassigned from %08x to %08x\n",
269 tlli_state->current, new_tlli);
270
271 /* Remember assigned TLLI */
272 tlli_state->assigned = new_tlli;
273 tlli_state->bss_validated = 0;
274 tlli_state->net_validated = 0;
275}
276
277uint32_t gbproxy_map_tlli(uint32_t other_tlli,
278 struct gbproxy_tlli_info *tlli_info, int to_bss)
279{
280 uint32_t tlli = 0;
281 struct gbproxy_tlli_state *src, *dst;
282 if (to_bss) {
283 src = &tlli_info->sgsn_tlli;
284 dst = &tlli_info->tlli;
285 } else {
286 src = &tlli_info->tlli;
287 dst = &tlli_info->sgsn_tlli;
288 }
289 if (src->current == other_tlli)
290 tlli = dst->current;
291 else if (src->assigned == other_tlli)
292 tlli = dst->assigned;
293
294 return tlli;
295}
296
297static void gbproxy_validate_tlli(struct gbproxy_tlli_state *tlli_state,
298 uint32_t tlli, int to_bss)
299{
300 LOGP(DGPRS, LOGL_DEBUG,
301 "%s({current = %08x, assigned = %08x, net_vld = %d, bss_vld = %d}, %08x)\n",
302 __func__, tlli_state->current, tlli_state->assigned,
303 tlli_state->net_validated, tlli_state->bss_validated, tlli);
304
305 if (!tlli_state->assigned || tlli_state->assigned != tlli)
306 return;
307
308 /* TODO: Is this ok? Check spec */
309 if (gprs_tlli_type(tlli) != TLLI_LOCAL)
310 return;
311
312 /* See GSM 04.08, 4.7.1.5 */
313 if (to_bss)
314 tlli_state->net_validated = 1;
315 else
316 tlli_state->bss_validated = 1;
317
318 if (!tlli_state->bss_validated || !tlli_state->net_validated)
319 return;
320
321 LOGP(DGPRS, LOGL_INFO,
322 "The TLLI %08x has been validated (was %08x)\n",
323 tlli_state->assigned, tlli_state->current);
324
325 tlli_state->current = tlli;
326 tlli_state->assigned = 0;
327}
328
329void gbproxy_touch_tlli(struct gbproxy_peer *peer,
330 struct gbproxy_tlli_info *tlli_info, time_t now)
331{
332 gbproxy_detach_tlli_info(peer, tlli_info);
333 gbproxy_attach_tlli_info(peer, now, tlli_info);
334}
335
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200336static void gbproxy_unregister_tlli(struct gbproxy_peer *peer,
337 struct gbproxy_tlli_info *tlli_info)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200338{
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200339 if (!tlli_info)
340 return;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200341
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200342 if (tlli_info->tlli.ptmsi == GSM_RESERVED_TMSI && !tlli_info->imsi_len) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200343 LOGP(DGPRS, LOGL_INFO,
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200344 "Removing TLLI %08x from list (P-TMSI or IMSI are not set)\n",
345 tlli_info->tlli.current);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200346 gbproxy_delete_tlli(peer, tlli_info);
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200347 return;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200348 }
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200349
350 tlli_info->tlli.current = 0;
351 tlli_info->tlli.assigned = 0;
352 tlli_info->sgsn_tlli.current = 0;
353 tlli_info->sgsn_tlli.assigned = 0;
354
355 tlli_info->is_deregistered = 1;
356
357 return;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200358}
359
Jacob Erlbeck18a37872014-09-08 09:59:16 +0200360int gbproxy_check_tlli(struct gbproxy_peer *peer,
361 struct gbproxy_tlli_info *tlli_info)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200362{
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200363 if (!peer->cfg->check_imsi)
364 return 1;
365
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200366 return tlli_info != NULL && tlli_info->enable_patching;
367}
368
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200369void gbproxy_assign_imsi(struct gbproxy_peer *peer,
370 struct gbproxy_tlli_info *tlli_info,
371 struct gprs_gb_parse_context *parse_ctx)
372{
373 int enable_patching;
374 struct gbproxy_tlli_info *other_tlli_info;
375
376 /* Make sure that there is a second entry with the same IMSI */
377 other_tlli_info = gbproxy_find_tlli_by_imsi(
378 peer, parse_ctx->imsi, parse_ctx->imsi_len);
379
380 if (other_tlli_info && other_tlli_info != tlli_info) {
381 char mi_buf[200];
382 mi_buf[0] = '\0';
383 gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
384 parse_ctx->imsi, parse_ctx->imsi_len);
385 LOGP(DGPRS, LOGL_INFO,
386 "Removing TLLI %08x from list (IMSI %s re-used)\n",
387 other_tlli_info->tlli.current, mi_buf);
388 gbproxy_delete_tlli(peer, other_tlli_info);
389 }
390
391 /* Update the IMSI field */
392 gbproxy_update_tlli_info(tlli_info,
393 parse_ctx->imsi, parse_ctx->imsi_len);
394
395 /* Check, whether the IMSI matches */
396 enable_patching = gbproxy_check_imsi(peer, parse_ctx->imsi,
397 parse_ctx->imsi_len);
398 if (enable_patching >= 0)
399 tlli_info->enable_patching = enable_patching;
400}
401
Jacob Erlbeck1a024422014-09-16 14:10:27 +0200402static int gbproxy_tlli_match(const struct gbproxy_tlli_state *a,
403 const struct gbproxy_tlli_state *b)
404{
405 if (a->current && a->current == b->current)
406 return 1;
407
408 if (a->assigned && a->assigned == b->assigned)
409 return 1;
410
411 if (a->ptmsi != GSM_RESERVED_TMSI && a->ptmsi == b->ptmsi)
412 return 1;
413
414 return 0;
415}
416
417static void gbproxy_remove_matching_tllis(struct gbproxy_peer *peer,
418 struct gbproxy_tlli_info *tlli_info)
419{
420 struct gbproxy_tlli_info *info, *nxt;
421 struct gbproxy_patch_state *state = &peer->patch_state;
422
423 /* Make sure that there is no second entry with the same P-TMSI or TLLI */
424 llist_for_each_entry_safe(info, nxt, &state->enabled_tllis, list) {
425 if (info == tlli_info)
426 continue;
427
428 if (!gbproxy_tlli_match(&tlli_info->tlli, &info->tlli) &&
Jacob Erlbeck91a0e862014-09-17 10:56:38 +0200429 (tlli_info->sgsn_nsei != info->sgsn_nsei ||
430 !gbproxy_tlli_match(&tlli_info->sgsn_tlli, &info->sgsn_tlli)))
Jacob Erlbeck1a024422014-09-16 14:10:27 +0200431 continue;
432
433 LOGP(DGPRS, LOGL_INFO,
434 "Removing TLLI %08x from list (P-TMSI/TLLI re-used)\n",
435 info->tlli.current);
436 gbproxy_delete_tlli(peer, info);
437 }
438}
439
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200440struct gbproxy_tlli_info *gbproxy_get_tlli_info_ul(
441 struct gbproxy_peer *peer,
442 struct gprs_gb_parse_context *parse_ctx)
443{
444 struct gbproxy_tlli_info *tlli_info = NULL;
445
446 if (parse_ctx->tlli_enc)
447 tlli_info = gbproxy_find_tlli(peer, parse_ctx->tlli);
448
449 if (!tlli_info && parse_ctx->imsi)
450 tlli_info = gbproxy_find_tlli_by_imsi(
451 peer, parse_ctx->imsi, parse_ctx->imsi_len);
452
453 if (!tlli_info && parse_ctx->ptmsi_enc && !parse_ctx->old_raid_is_foreign) {
454 uint32_t bss_ptmsi;
455 if (!gprs_parse_mi_tmsi(parse_ctx->ptmsi_enc, GSM48_TMSI_LEN,
456 &bss_ptmsi))
457 LOGP(DGPRS, LOGL_ERROR,
458 "Failed to parse P-TMSI (TLLI is %08x)\n",
459 parse_ctx->tlli);
460 else
461 tlli_info = gbproxy_find_tlli_by_ptmsi(peer, bss_ptmsi);
462 }
463
464 if (tlli_info)
465 tlli_info->is_deregistered = 0;
466
467 return tlli_info;
468}
469
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200470struct gbproxy_tlli_info *gbproxy_update_tlli_state_ul(
471 struct gbproxy_peer *peer,
472 time_t now,
473 struct gprs_gb_parse_context *parse_ctx)
474{
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200475 struct gbproxy_tlli_info *tlli_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200476
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200477 tlli_info = gbproxy_get_tlli_info_ul(peer, parse_ctx);
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200478
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200479 if (parse_ctx->tlli_enc && parse_ctx->llc) {
480 uint32_t sgsn_tlli;
481 if (!tlli_info) {
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200482 LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n",
483 parse_ctx->tlli);
484 tlli_info = gbproxy_tlli_info_alloc(peer);
485 gbproxy_attach_tlli_info(peer, now, tlli_info);
486
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200487 /* Setup TLLIs */
488 sgsn_tlli = gbproxy_make_sgsn_tlli(peer, tlli_info,
489 parse_ctx->tlli);
490 tlli_info->sgsn_tlli.current = sgsn_tlli;
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200491 tlli_info->tlli.current = parse_ctx->tlli;;
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200492 } else if (!tlli_info->tlli.current) {
493 /* New TLLI (info found by IMSI or P-TMSI) */
494 tlli_info->tlli.current = parse_ctx->tlli;
495 tlli_info->sgsn_tlli.current =
496 gbproxy_make_sgsn_tlli(peer, tlli_info,
497 parse_ctx->tlli);
498 gbproxy_touch_tlli(peer, tlli_info, now);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200499 } else {
500 sgsn_tlli = gbproxy_map_tlli(parse_ctx->tlli, tlli_info, 0);
501 if (!sgsn_tlli)
502 sgsn_tlli = gbproxy_make_sgsn_tlli(peer, tlli_info,
503 parse_ctx->tlli);
504
505 gbproxy_validate_tlli(&tlli_info->tlli,
506 parse_ctx->tlli, 0);
507 gbproxy_validate_tlli(&tlli_info->sgsn_tlli,
508 sgsn_tlli, 0);
509 gbproxy_touch_tlli(peer, tlli_info, now);
510 }
511 } else if (tlli_info) {
512 gbproxy_touch_tlli(peer, tlli_info, now);
513 }
514
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200515 if (parse_ctx->imsi && tlli_info && tlli_info->imsi_len == 0)
516 gbproxy_assign_imsi(peer, tlli_info, parse_ctx);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200517
518 return tlli_info;
519}
520
521struct gbproxy_tlli_info *gbproxy_update_tlli_state_dl(
522 struct gbproxy_peer *peer,
523 time_t now,
524 struct gprs_gb_parse_context *parse_ctx)
525{
526 struct gbproxy_tlli_info *tlli_info = NULL;
527
528 if (parse_ctx->tlli_enc)
Jacob Erlbeck91a0e862014-09-17 10:56:38 +0200529 tlli_info = gbproxy_find_tlli_by_sgsn_tlli(
530 peer, parse_ctx->tlli, parse_ctx->peer_nsei);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200531
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200532 if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && tlli_info) {
533 /* A new P-TMSI has been signalled in the message,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200534 * register new TLLI */
535 uint32_t new_sgsn_ptmsi;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200536 uint32_t new_bss_ptmsi;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200537 if (!gprs_parse_mi_tmsi(parse_ctx->new_ptmsi_enc, GSM48_TMSI_LEN,
538 &new_sgsn_ptmsi)) {
539 LOGP(DGPRS, LOGL_ERROR,
540 "Failed to parse new TLLI/PTMSI (current is %08x)\n",
541 parse_ctx->tlli);
542 return tlli_info;
543 }
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200544 new_bss_ptmsi = gbproxy_make_bss_ptmsi(peer, new_sgsn_ptmsi);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200545
Jacob Erlbeckb1ee5cd2014-09-04 14:53:30 +0200546 LOGP(DGPRS, LOGL_INFO,
547 "Got new PTMSI %08x from SGSN, using %08x for BSS\n",
548 new_sgsn_ptmsi, new_bss_ptmsi);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200549 /* Setup PTMSIs */
550 tlli_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi;
551 tlli_info->tlli.ptmsi = new_bss_ptmsi;
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200552 } else if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && !tlli_info &&
553 !peer->cfg->patch_ptmsi) {
554 /* A new P-TMSI has been signalled in the message with an unknown
555 * TLLI, create a new tlli_info */
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200556 /* TODO: Add a test case for this branch */
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200557 uint32_t new_ptmsi;
558 if (!gprs_parse_mi_tmsi(parse_ctx->new_ptmsi_enc, GSM48_TMSI_LEN,
559 &new_ptmsi)) {
560 LOGP(DGPRS, LOGL_ERROR,
561 "Failed to parse new PTMSI (TLLI is %08x)\n",
562 parse_ctx->tlli);
563 return tlli_info;
564 }
565
566 LOGP(DGPRS, LOGL_INFO,
567 "Adding TLLI %08x to list (SGSN, new P-TMSI is %08x)\n",
568 parse_ctx->tlli, new_ptmsi);
569
570 tlli_info = gbproxy_tlli_info_alloc(peer);
571 tlli_info->sgsn_tlli.current = parse_ctx->tlli;;
572 tlli_info->tlli.current = parse_ctx->tlli;;
573 tlli_info->sgsn_tlli.ptmsi = new_ptmsi;
574 tlli_info->tlli.ptmsi = new_ptmsi;
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200575 gbproxy_attach_tlli_info(peer, now, tlli_info);
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200576 } else if (parse_ctx->tlli_enc && parse_ctx->llc && !tlli_info &&
577 !peer->cfg->patch_ptmsi) {
578 /* Unknown SGSN TLLI, create a new tlli_info */
579 uint32_t new_ptmsi;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200580 tlli_info = gbproxy_tlli_info_alloc(peer);
581 LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list (SGSN)\n",
582 parse_ctx->tlli);
583
584 gbproxy_attach_tlli_info(peer, now, tlli_info);
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200585
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200586 /* Setup TLLIs */
587 tlli_info->sgsn_tlli.current = parse_ctx->tlli;
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200588 tlli_info->tlli.current = parse_ctx->tlli;
589
590 if (!parse_ctx->new_ptmsi_enc)
591 return tlli_info;
592 /* A new P-TMSI has been signalled in the message */
593
594 if (!gprs_parse_mi_tmsi(parse_ctx->new_ptmsi_enc,
595 GSM48_TMSI_LEN, &new_ptmsi)) {
596 LOGP(DGPRS, LOGL_ERROR,
597 "Failed to parse new PTMSI (TLLI is %08x)\n",
598 parse_ctx->tlli);
599 return tlli_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200600 }
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200601 LOGP(DGPRS, LOGL_INFO,
602 "Assigning new P-TMSI %08x\n", new_ptmsi);
603 /* Setup P-TMSIs */
604 tlli_info->sgsn_tlli.ptmsi = new_ptmsi;
605 tlli_info->tlli.ptmsi = new_ptmsi;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200606 } else if (parse_ctx->tlli_enc && parse_ctx->llc && tlli_info) {
607 uint32_t bss_tlli = gbproxy_map_tlli(parse_ctx->tlli,
608 tlli_info, 1);
609 gbproxy_validate_tlli(&tlli_info->sgsn_tlli, parse_ctx->tlli, 1);
610 gbproxy_validate_tlli(&tlli_info->tlli, bss_tlli, 1);
611 gbproxy_touch_tlli(peer, tlli_info, now);
612 } else if (tlli_info) {
613 gbproxy_touch_tlli(peer, tlli_info, now);
614 }
615
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200616 if (parse_ctx->imsi && tlli_info && tlli_info->imsi_len == 0)
617 gbproxy_assign_imsi(peer, tlli_info, parse_ctx);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200618
619 return tlli_info;
620}
621
622void gbproxy_update_tlli_state_after(
623 struct gbproxy_peer *peer,
624 struct gbproxy_tlli_info *tlli_info,
625 time_t now,
626 struct gprs_gb_parse_context *parse_ctx)
627{
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200628 if (parse_ctx->invalidate_tlli && tlli_info) {
629 int keep_info =
630 peer->cfg->keep_tlli_infos == GBPROX_KEEP_ALWAYS ||
631 (peer->cfg->keep_tlli_infos == GBPROX_KEEP_REATTACH &&
632 parse_ctx->await_reattach) ||
633 (peer->cfg->keep_tlli_infos == GBPROX_KEEP_IDENTIFIED &&
634 tlli_info->imsi_len > 0);
635 if (keep_info) {
636 LOGP(DGPRS, LOGL_INFO, "Unregistering TLLI %08x\n",
637 tlli_info->tlli.current);
638 gbproxy_unregister_tlli(peer, tlli_info);
639 } else {
640 LOGP(DGPRS, LOGL_INFO, "Removing TLLI %08x from list\n",
641 tlli_info->tlli.current);
642 gbproxy_delete_tlli(peer, tlli_info);
643 }
Jacob Erlbeckb1ee5cd2014-09-04 14:53:30 +0200644 } else if (parse_ctx->to_bss && parse_ctx->tlli_enc &&
645 parse_ctx->new_ptmsi_enc && tlli_info) {
646 /* A new PTMSI has been signaled in the message,
647 * register new TLLI */
648 uint32_t new_sgsn_ptmsi = tlli_info->sgsn_tlli.ptmsi;
649 uint32_t new_bss_ptmsi = tlli_info->tlli.ptmsi;
650 uint32_t new_sgsn_tlli;
651 uint32_t new_bss_tlli = 0;
652
653 new_sgsn_tlli = gprs_tmsi2tlli(new_sgsn_ptmsi, TLLI_LOCAL);
654 if (new_bss_ptmsi != GSM_RESERVED_TMSI)
655 new_bss_tlli = gprs_tmsi2tlli(new_bss_ptmsi, TLLI_LOCAL);
656 LOGP(DGPRS, LOGL_INFO,
657 "Assigning new TLLI %08x to SGSN, %08x to BSS\n",
658 new_sgsn_tlli, new_bss_tlli);
659
660 gbproxy_reassign_tlli(&tlli_info->sgsn_tlli,
661 peer, new_sgsn_tlli);
662 gbproxy_reassign_tlli(&tlli_info->tlli,
663 peer, new_bss_tlli);
Jacob Erlbeck1a024422014-09-16 14:10:27 +0200664 gbproxy_remove_matching_tllis(peer, tlli_info);
Jacob Erlbeckb1ee5cd2014-09-04 14:53:30 +0200665 }
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200666
667 gbproxy_remove_stale_tllis(peer, now);
668}
669
670