blob: 14ce7d86b077850b73776cf2ca5e4a5ddf626115 [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
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020035struct gbproxy_link_info *gbproxy_link_info_by_tlli(struct gbproxy_peer *peer,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020036 uint32_t tlli)
37{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020038 struct gbproxy_link_info *link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020039 struct gbproxy_patch_state *state = &peer->patch_state;
40
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020041 llist_for_each_entry(link_info, &state->enabled_tllis, list)
42 if (link_info->tlli.current == tlli ||
43 link_info->tlli.assigned == tlli)
44 return link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020045
46 return NULL;
47}
48
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020049struct gbproxy_link_info *gbproxy_link_info_by_ptmsi(
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020050 struct gbproxy_peer *peer,
51 uint32_t ptmsi)
52{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020053 struct gbproxy_link_info *link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020054 struct gbproxy_patch_state *state = &peer->patch_state;
55
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020056 llist_for_each_entry(link_info, &state->enabled_tllis, list)
57 if (link_info->tlli.ptmsi == ptmsi)
58 return link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020059
60 return NULL;
61}
62
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020063struct gbproxy_link_info *gbproxy_link_info_by_any_sgsn_tlli(
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020064 struct gbproxy_peer *peer,
65 uint32_t tlli)
66{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020067 struct gbproxy_link_info *link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020068 struct gbproxy_patch_state *state = &peer->patch_state;
69
Jacob Erlbeck91a0e862014-09-17 10:56:38 +020070 /* Don't care about the NSEI */
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020071 llist_for_each_entry(link_info, &state->enabled_tllis, list)
72 if (link_info->sgsn_tlli.current == tlli ||
73 link_info->sgsn_tlli.assigned == tlli)
74 return link_info;
Jacob Erlbeck91a0e862014-09-17 10:56:38 +020075
76 return NULL;
77}
78
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020079struct gbproxy_link_info *gbproxy_link_info_by_sgsn_tlli(
Jacob Erlbeck91a0e862014-09-17 10:56:38 +020080 struct gbproxy_peer *peer,
81 uint32_t tlli, uint32_t sgsn_nsei)
82{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020083 struct gbproxy_link_info *link_info;
Jacob Erlbeck91a0e862014-09-17 10:56:38 +020084 struct gbproxy_patch_state *state = &peer->patch_state;
85
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020086 llist_for_each_entry(link_info, &state->enabled_tllis, list)
87 if ((link_info->sgsn_tlli.current == tlli ||
88 link_info->sgsn_tlli.assigned == tlli) &&
89 link_info->sgsn_nsei == sgsn_nsei)
90 return link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020091
92 return NULL;
93}
94
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +020095struct gbproxy_link_info *gbproxy_link_info_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{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200100 struct gbproxy_link_info *link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200101 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
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200106 llist_for_each_entry(link_info, &state->enabled_tllis, list) {
107 if (link_info->imsi_len != imsi_len)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200108 continue;
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200109 if (memcmp(link_info->imsi, imsi, imsi_len) != 0)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200110 continue;
111
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200112 return link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200113 }
114
115 return NULL;
116}
117
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200118void gbproxy_link_info_discard_messages(struct gbproxy_link_info *link_info)
Jacob Erlbeck31591142014-09-03 11:59:48 +0200119{
120 struct msgb *msg, *nxt;
121
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200122 llist_for_each_entry_safe(msg, nxt, &link_info->stored_msgs, list) {
Jacob Erlbeck31591142014-09-03 11:59:48 +0200123 llist_del(&msg->list);
124 msgb_free(msg);
125 }
126}
127
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200128void gbproxy_delete_link_info(struct gbproxy_peer *peer,
129 struct gbproxy_link_info *link_info)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200130{
131 struct gbproxy_patch_state *state = &peer->patch_state;
132
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200133 gbproxy_link_info_discard_messages(link_info);
Jacob Erlbeck31591142014-09-03 11:59:48 +0200134
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200135 llist_del(&link_info->list);
136 talloc_free(link_info);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200137 state->enabled_tllis_count -= 1;
138
139 peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
140 state->enabled_tllis_count;
141}
142
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200143void gbproxy_delete_link_infos(struct gbproxy_peer *peer)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200144{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200145 struct gbproxy_link_info *link_info, *nxt;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200146 struct gbproxy_patch_state *state = &peer->patch_state;
147
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200148 llist_for_each_entry_safe(link_info, nxt, &state->enabled_tllis, list)
149 gbproxy_delete_link_info(peer, link_info);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200150
151 OSMO_ASSERT(state->enabled_tllis_count == 0);
152 OSMO_ASSERT(llist_empty(&state->enabled_tllis));
153}
154
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200155void gbproxy_attach_link_info(struct gbproxy_peer *peer, time_t now,
156 struct gbproxy_link_info *link_info)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200157{
158 struct gbproxy_patch_state *state = &peer->patch_state;
159
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200160 link_info->timestamp = now;
161 llist_add(&link_info->list, &state->enabled_tllis);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200162 state->enabled_tllis_count += 1;
163
164 peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
165 state->enabled_tllis_count;
166}
167
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200168int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200169{
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--) {
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200182 struct gbproxy_link_info *link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200183 OSMO_ASSERT(!llist_empty(&state->enabled_tllis));
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200184 link_info = llist_entry(state->enabled_tllis.prev,
185 struct gbproxy_link_info,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200186 list);
187 LOGP(DGPRS, LOGL_INFO,
188 "Removing TLLI %08x from list "
189 "(stale, length %d, max_len exceeded)\n",
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200190 link_info->tlli.current, state->enabled_tllis_count);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200191
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200192 gbproxy_delete_link_info(peer, link_info);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200193 deleted_count += 1;
194 }
195
196 while (check_for_age && !llist_empty(&state->enabled_tllis)) {
197 time_t age;
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200198 struct gbproxy_link_info *link_info;
199 link_info = llist_entry(state->enabled_tllis.prev,
200 struct gbproxy_link_info,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200201 list);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200202 age = now - link_info->timestamp;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200203 /* 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",
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200212 link_info->tlli.current, (int)age);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200213
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200214 gbproxy_delete_link_info(peer, link_info);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200215 deleted_count += 1;
216 }
217
218 return deleted_count;
219}
220
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200221struct gbproxy_link_info *gbproxy_link_info_alloc( struct gbproxy_peer *peer)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200222{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200223 struct gbproxy_link_info *link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200224
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200225 link_info = talloc_zero(peer, struct gbproxy_link_info);
226 link_info->tlli.ptmsi = GSM_RESERVED_TMSI;
227 link_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200228
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200229 INIT_LLIST_HEAD(&link_info->stored_msgs);
Jacob Erlbeck5f4ef322014-08-22 17:10:01 +0200230
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200231 return link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200232}
233
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200234void gbproxy_detach_link_info(
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200235 struct gbproxy_peer *peer,
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200236 struct gbproxy_link_info *link_info)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200237{
238 struct gbproxy_patch_state *state = &peer->patch_state;
239
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200240 llist_del(&link_info->list);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200241 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 Erlbeck91d2f8a2014-09-19 15:07:27 +0200248void gbproxy_update_link_info(struct gbproxy_link_info *link_info,
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200249 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 Erlbeck91d2f8a2014-09-19 15:07:27 +0200254 link_info->imsi_len = imsi_len;
255 link_info->imsi =
256 talloc_realloc_size(link_info, link_info->imsi, imsi_len);
257 OSMO_ASSERT(link_info->imsi != NULL);
258 memcpy(link_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,
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200278 struct gbproxy_link_info *link_info, int to_bss)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200279{
280 uint32_t tlli = 0;
281 struct gbproxy_tlli_state *src, *dst;
282 if (to_bss) {
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200283 src = &link_info->sgsn_tlli;
284 dst = &link_info->tlli;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200285 } else {
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200286 src = &link_info->tlli;
287 dst = &link_info->sgsn_tlli;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200288 }
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
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200329static void gbproxy_touch_link_info(struct gbproxy_peer *peer,
330 struct gbproxy_link_info *link_info,
Jacob Erlbeck9a7b0d52014-09-19 13:30:14 +0200331 time_t now)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200332{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200333 gbproxy_detach_link_info(peer, link_info);
334 gbproxy_attach_link_info(peer, now, link_info);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200335}
336
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200337static void gbproxy_unregister_link_info(struct gbproxy_peer *peer,
338 struct gbproxy_link_info *link_info)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200339{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200340 if (!link_info)
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200341 return;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200342
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200343 if (link_info->tlli.ptmsi == GSM_RESERVED_TMSI && !link_info->imsi_len) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200344 LOGP(DGPRS, LOGL_INFO,
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200345 "Removing TLLI %08x from list (P-TMSI or IMSI are not set)\n",
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200346 link_info->tlli.current);
347 gbproxy_delete_link_info(peer, link_info);
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200348 return;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200349 }
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200350
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200351 link_info->tlli.current = 0;
352 link_info->tlli.assigned = 0;
353 link_info->sgsn_tlli.current = 0;
354 link_info->sgsn_tlli.assigned = 0;
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200355
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200356 link_info->is_deregistered = 1;
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200357
358 return;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200359}
360
Jacob Erlbeck8992f302014-09-19 13:17:55 +0200361int gbproxy_imsi_matches(struct gbproxy_peer *peer,
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200362 struct gbproxy_link_info *link_info)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200363{
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200364 if (!peer->cfg->check_imsi)
365 return 1;
366
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200367 return link_info != NULL && link_info->imsi_matches;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200368}
369
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200370void gbproxy_assign_imsi(struct gbproxy_peer *peer,
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200371 struct gbproxy_link_info *link_info,
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200372 struct gprs_gb_parse_context *parse_ctx)
373{
Jacob Erlbeck8992f302014-09-19 13:17:55 +0200374 int imsi_matches;
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200375 struct gbproxy_link_info *other_link_info;
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200376
377 /* Make sure that there is a second entry with the same IMSI */
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200378 other_link_info = gbproxy_link_info_by_imsi(
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200379 peer, parse_ctx->imsi, parse_ctx->imsi_len);
380
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200381 if (other_link_info && other_link_info != link_info) {
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200382 char mi_buf[200];
383 mi_buf[0] = '\0';
384 gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
385 parse_ctx->imsi, parse_ctx->imsi_len);
386 LOGP(DGPRS, LOGL_INFO,
387 "Removing TLLI %08x from list (IMSI %s re-used)\n",
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200388 other_link_info->tlli.current, mi_buf);
389 gbproxy_delete_link_info(peer, other_link_info);
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200390 }
391
392 /* Update the IMSI field */
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200393 gbproxy_update_link_info(link_info,
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200394 parse_ctx->imsi, parse_ctx->imsi_len);
395
396 /* Check, whether the IMSI matches */
Jacob Erlbeck8992f302014-09-19 13:17:55 +0200397 imsi_matches = gbproxy_check_imsi(peer, parse_ctx->imsi,
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200398 parse_ctx->imsi_len);
Jacob Erlbeck8992f302014-09-19 13:17:55 +0200399 if (imsi_matches >= 0)
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200400 link_info->imsi_matches = imsi_matches;
Jacob Erlbeck16a3cd32014-09-15 11:46:42 +0200401}
402
Jacob Erlbeck1a024422014-09-16 14:10:27 +0200403static int gbproxy_tlli_match(const struct gbproxy_tlli_state *a,
404 const struct gbproxy_tlli_state *b)
405{
406 if (a->current && a->current == b->current)
407 return 1;
408
409 if (a->assigned && a->assigned == b->assigned)
410 return 1;
411
412 if (a->ptmsi != GSM_RESERVED_TMSI && a->ptmsi == b->ptmsi)
413 return 1;
414
415 return 0;
416}
417
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200418static void gbproxy_remove_matching_link_infos(
419 struct gbproxy_peer *peer, struct gbproxy_link_info *link_info)
Jacob Erlbeck1a024422014-09-16 14:10:27 +0200420{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200421 struct gbproxy_link_info *info, *nxt;
Jacob Erlbeck1a024422014-09-16 14:10:27 +0200422 struct gbproxy_patch_state *state = &peer->patch_state;
423
424 /* Make sure that there is no second entry with the same P-TMSI or TLLI */
425 llist_for_each_entry_safe(info, nxt, &state->enabled_tllis, list) {
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200426 if (info == link_info)
Jacob Erlbeck1a024422014-09-16 14:10:27 +0200427 continue;
428
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200429 if (!gbproxy_tlli_match(&link_info->tlli, &info->tlli) &&
430 (link_info->sgsn_nsei != info->sgsn_nsei ||
431 !gbproxy_tlli_match(&link_info->sgsn_tlli, &info->sgsn_tlli)))
Jacob Erlbeck1a024422014-09-16 14:10:27 +0200432 continue;
433
434 LOGP(DGPRS, LOGL_INFO,
435 "Removing TLLI %08x from list (P-TMSI/TLLI re-used)\n",
436 info->tlli.current);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200437 gbproxy_delete_link_info(peer, info);
Jacob Erlbeck1a024422014-09-16 14:10:27 +0200438 }
439}
440
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200441struct gbproxy_link_info *gbproxy_get_link_info_ul(
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200442 struct gbproxy_peer *peer,
443 struct gprs_gb_parse_context *parse_ctx)
444{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200445 struct gbproxy_link_info *link_info = NULL;
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200446
447 if (parse_ctx->tlli_enc)
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200448 link_info = gbproxy_link_info_by_tlli(peer, parse_ctx->tlli);
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200449
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200450 if (!link_info && parse_ctx->imsi)
451 link_info = gbproxy_link_info_by_imsi(
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200452 peer, parse_ctx->imsi, parse_ctx->imsi_len);
453
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200454 if (!link_info && parse_ctx->ptmsi_enc && !parse_ctx->old_raid_is_foreign) {
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200455 uint32_t bss_ptmsi;
456 if (!gprs_parse_mi_tmsi(parse_ctx->ptmsi_enc, GSM48_TMSI_LEN,
457 &bss_ptmsi))
458 LOGP(DGPRS, LOGL_ERROR,
459 "Failed to parse P-TMSI (TLLI is %08x)\n",
460 parse_ctx->tlli);
461 else
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200462 link_info = gbproxy_link_info_by_ptmsi(peer, bss_ptmsi);
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200463 }
464
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200465 if (link_info)
466 link_info->is_deregistered = 0;
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200467
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200468 return link_info;
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200469}
470
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200471struct gbproxy_link_info *gbproxy_update_link_state_ul(
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200472 struct gbproxy_peer *peer,
473 time_t now,
474 struct gprs_gb_parse_context *parse_ctx)
475{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200476 struct gbproxy_link_info *link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200477
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200478 link_info = gbproxy_get_link_info_ul(peer, parse_ctx);
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200479
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200480 if (parse_ctx->tlli_enc && parse_ctx->llc) {
481 uint32_t sgsn_tlli;
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200482 if (!link_info) {
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200483 LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n",
484 parse_ctx->tlli);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200485 link_info = gbproxy_link_info_alloc(peer);
486 gbproxy_attach_link_info(peer, now, link_info);
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200487
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200488 /* Setup TLLIs */
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200489 sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200490 parse_ctx->tlli);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200491 link_info->sgsn_tlli.current = sgsn_tlli;
492 link_info->tlli.current = parse_ctx->tlli;;
493 } else if (!link_info->tlli.current) {
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200494 /* New TLLI (info found by IMSI or P-TMSI) */
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200495 link_info->tlli.current = parse_ctx->tlli;
496 link_info->sgsn_tlli.current =
497 gbproxy_make_sgsn_tlli(peer, link_info,
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200498 parse_ctx->tlli);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200499 gbproxy_touch_link_info(peer, link_info, now);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200500 } else {
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200501 sgsn_tlli = gbproxy_map_tlli(parse_ctx->tlli, link_info, 0);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200502 if (!sgsn_tlli)
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200503 sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200504 parse_ctx->tlli);
505
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200506 gbproxy_validate_tlli(&link_info->tlli,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200507 parse_ctx->tlli, 0);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200508 gbproxy_validate_tlli(&link_info->sgsn_tlli,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200509 sgsn_tlli, 0);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200510 gbproxy_touch_link_info(peer, link_info, now);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200511 }
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200512 } else if (link_info) {
513 gbproxy_touch_link_info(peer, link_info, now);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200514 }
515
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200516 if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
517 gbproxy_assign_imsi(peer, link_info, parse_ctx);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200518
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200519 return link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200520}
521
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200522struct gbproxy_link_info *gbproxy_update_link_state_dl(
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200523 struct gbproxy_peer *peer,
524 time_t now,
525 struct gprs_gb_parse_context *parse_ctx)
526{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200527 struct gbproxy_link_info *link_info = NULL;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200528
529 if (parse_ctx->tlli_enc)
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200530 link_info = gbproxy_link_info_by_sgsn_tlli(
Jacob Erlbeck91a0e862014-09-17 10:56:38 +0200531 peer, parse_ctx->tlli, parse_ctx->peer_nsei);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200532
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200533 if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && link_info) {
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200534 /* A new P-TMSI has been signalled in the message,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200535 * register new TLLI */
536 uint32_t new_sgsn_ptmsi;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200537 uint32_t new_bss_ptmsi;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200538 if (!gprs_parse_mi_tmsi(parse_ctx->new_ptmsi_enc, GSM48_TMSI_LEN,
539 &new_sgsn_ptmsi)) {
540 LOGP(DGPRS, LOGL_ERROR,
541 "Failed to parse new TLLI/PTMSI (current is %08x)\n",
542 parse_ctx->tlli);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200543 return link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200544 }
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200545 new_bss_ptmsi = gbproxy_make_bss_ptmsi(peer, new_sgsn_ptmsi);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200546
Jacob Erlbeckb1ee5cd2014-09-04 14:53:30 +0200547 LOGP(DGPRS, LOGL_INFO,
548 "Got new PTMSI %08x from SGSN, using %08x for BSS\n",
549 new_sgsn_ptmsi, new_bss_ptmsi);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200550 /* Setup PTMSIs */
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200551 link_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi;
552 link_info->tlli.ptmsi = new_bss_ptmsi;
553 } else if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && !link_info &&
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200554 !peer->cfg->patch_ptmsi) {
555 /* A new P-TMSI has been signalled in the message with an unknown
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200556 * TLLI, create a new link_info */
Jacob Erlbecka42fe9f2014-09-12 14:15:02 +0200557 /* TODO: Add a test case for this branch */
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200558 uint32_t new_ptmsi;
559 if (!gprs_parse_mi_tmsi(parse_ctx->new_ptmsi_enc, GSM48_TMSI_LEN,
560 &new_ptmsi)) {
561 LOGP(DGPRS, LOGL_ERROR,
562 "Failed to parse new PTMSI (TLLI is %08x)\n",
563 parse_ctx->tlli);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200564 return link_info;
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200565 }
566
567 LOGP(DGPRS, LOGL_INFO,
568 "Adding TLLI %08x to list (SGSN, new P-TMSI is %08x)\n",
569 parse_ctx->tlli, new_ptmsi);
570
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200571 link_info = gbproxy_link_info_alloc(peer);
572 link_info->sgsn_tlli.current = parse_ctx->tlli;;
573 link_info->tlli.current = parse_ctx->tlli;;
574 link_info->sgsn_tlli.ptmsi = new_ptmsi;
575 link_info->tlli.ptmsi = new_ptmsi;
576 gbproxy_attach_link_info(peer, now, link_info);
577 } else if (parse_ctx->tlli_enc && parse_ctx->llc && !link_info &&
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200578 !peer->cfg->patch_ptmsi) {
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200579 /* Unknown SGSN TLLI, create a new link_info */
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200580 uint32_t new_ptmsi;
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200581 link_info = gbproxy_link_info_alloc(peer);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200582 LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list (SGSN)\n",
583 parse_ctx->tlli);
584
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200585 gbproxy_attach_link_info(peer, now, link_info);
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200586
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200587 /* Setup TLLIs */
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200588 link_info->sgsn_tlli.current = parse_ctx->tlli;
589 link_info->tlli.current = parse_ctx->tlli;
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200590
591 if (!parse_ctx->new_ptmsi_enc)
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200592 return link_info;
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200593 /* A new P-TMSI has been signalled in the message */
594
595 if (!gprs_parse_mi_tmsi(parse_ctx->new_ptmsi_enc,
596 GSM48_TMSI_LEN, &new_ptmsi)) {
597 LOGP(DGPRS, LOGL_ERROR,
598 "Failed to parse new PTMSI (TLLI is %08x)\n",
599 parse_ctx->tlli);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200600 return link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200601 }
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200602 LOGP(DGPRS, LOGL_INFO,
603 "Assigning new P-TMSI %08x\n", new_ptmsi);
604 /* Setup P-TMSIs */
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200605 link_info->sgsn_tlli.ptmsi = new_ptmsi;
606 link_info->tlli.ptmsi = new_ptmsi;
607 } else if (parse_ctx->tlli_enc && parse_ctx->llc && link_info) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200608 uint32_t bss_tlli = gbproxy_map_tlli(parse_ctx->tlli,
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200609 link_info, 1);
610 gbproxy_validate_tlli(&link_info->sgsn_tlli, parse_ctx->tlli, 1);
611 gbproxy_validate_tlli(&link_info->tlli, bss_tlli, 1);
612 gbproxy_touch_link_info(peer, link_info, now);
613 } else if (link_info) {
614 gbproxy_touch_link_info(peer, link_info, now);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200615 }
616
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200617 if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
618 gbproxy_assign_imsi(peer, link_info, parse_ctx);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200619
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200620 return link_info;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200621}
622
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200623void gbproxy_update_link_state_after(
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200624 struct gbproxy_peer *peer,
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200625 struct gbproxy_link_info *link_info,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200626 time_t now,
627 struct gprs_gb_parse_context *parse_ctx)
628{
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200629 if (parse_ctx->invalidate_tlli && link_info) {
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200630 int keep_info =
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200631 peer->cfg->keep_link_infos == GBPROX_KEEP_ALWAYS ||
632 (peer->cfg->keep_link_infos == GBPROX_KEEP_REATTACH &&
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200633 parse_ctx->await_reattach) ||
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200634 (peer->cfg->keep_link_infos == GBPROX_KEEP_IDENTIFIED &&
635 link_info->imsi_len > 0);
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200636 if (keep_info) {
637 LOGP(DGPRS, LOGL_INFO, "Unregistering TLLI %08x\n",
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200638 link_info->tlli.current);
639 gbproxy_unregister_link_info(peer, link_info);
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200640 } else {
641 LOGP(DGPRS, LOGL_INFO, "Removing TLLI %08x from list\n",
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200642 link_info->tlli.current);
643 gbproxy_delete_link_info(peer, link_info);
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200644 }
Jacob Erlbeckb1ee5cd2014-09-04 14:53:30 +0200645 } else if (parse_ctx->to_bss && parse_ctx->tlli_enc &&
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200646 parse_ctx->new_ptmsi_enc && link_info) {
Jacob Erlbeckb1ee5cd2014-09-04 14:53:30 +0200647 /* A new PTMSI has been signaled in the message,
648 * register new TLLI */
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200649 uint32_t new_sgsn_ptmsi = link_info->sgsn_tlli.ptmsi;
650 uint32_t new_bss_ptmsi = link_info->tlli.ptmsi;
Jacob Erlbeckb1ee5cd2014-09-04 14:53:30 +0200651 uint32_t new_sgsn_tlli;
652 uint32_t new_bss_tlli = 0;
653
654 new_sgsn_tlli = gprs_tmsi2tlli(new_sgsn_ptmsi, TLLI_LOCAL);
655 if (new_bss_ptmsi != GSM_RESERVED_TMSI)
656 new_bss_tlli = gprs_tmsi2tlli(new_bss_ptmsi, TLLI_LOCAL);
657 LOGP(DGPRS, LOGL_INFO,
658 "Assigning new TLLI %08x to SGSN, %08x to BSS\n",
659 new_sgsn_tlli, new_bss_tlli);
660
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200661 gbproxy_reassign_tlli(&link_info->sgsn_tlli,
Jacob Erlbeckb1ee5cd2014-09-04 14:53:30 +0200662 peer, new_sgsn_tlli);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200663 gbproxy_reassign_tlli(&link_info->tlli,
Jacob Erlbeckb1ee5cd2014-09-04 14:53:30 +0200664 peer, new_bss_tlli);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200665 gbproxy_remove_matching_link_infos(peer, link_info);
Jacob Erlbeckb1ee5cd2014-09-04 14:53:30 +0200666 }
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200667
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200668 gbproxy_remove_stale_link_infos(peer, now);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200669}
670
671