blob: 496f605dd8d81682723ec7df5dbb7b8500884ba6 [file] [log] [blame]
Jacob Erlbeck9114bee2014-08-19 12:21:01 +02001/* Gb-proxy message patching */
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
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020021#include <osmocom/sgsn/gb_proxy.h>
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020022
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020023#include <osmocom/sgsn/gprs_utils.h>
24#include <osmocom/sgsn/gprs_gb_parse.h>
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020025
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020026#include <osmocom/sgsn/debug.h>
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020027
28#include <osmocom/gprs/protocol/gsm_08_18.h>
29#include <osmocom/core/rate_ctr.h>
Harald Welte7e82b742017-08-12 13:43:54 +020030#include <osmocom/gsm/apn.h>
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020031
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020032extern void *tall_bsc_ctx;
33
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020034/* patch RA identifier in place */
Max25c65c32018-01-08 14:43:53 +010035static void gbproxy_patch_raid(struct gsm48_ra_id *raid_enc, struct gbproxy_peer *peer,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020036 int to_bss, const char *log_text)
37{
38 struct gbproxy_patch_state *state = &peer->patch_state;
Neels Hofmeyr10719b72018-02-21 00:39:36 +010039 struct osmo_plmn_id old_plmn;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020040 struct gprs_ra_id raid;
Jacob Erlbeckcba4c0c2014-09-15 14:38:37 +020041 enum gbproxy_peer_ctr counter =
42 to_bss ?
43 GBPROX_PEER_CTR_RAID_PATCHED_SGSN :
44 GBPROX_PEER_CTR_RAID_PATCHED_BSS;
45
Neels Hofmeyr10719b72018-02-21 00:39:36 +010046 if (!state->local_plmn.mcc || !state->local_plmn.mnc)
Jacob Erlbeckcba4c0c2014-09-15 14:38:37 +020047 return;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020048
Max25c65c32018-01-08 14:43:53 +010049 gsm48_parse_ra(&raid, (uint8_t *)raid_enc);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020050
Neels Hofmeyr10719b72018-02-21 00:39:36 +010051 old_plmn = (struct osmo_plmn_id){
52 .mcc = raid.mcc,
53 .mnc = raid.mnc,
54 .mnc_3_digits = raid.mnc_3_digits,
55 };
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020056
57 if (!to_bss) {
58 /* BSS -> SGSN */
Neels Hofmeyr10719b72018-02-21 00:39:36 +010059 if (state->local_plmn.mcc)
60 raid.mcc = peer->cfg->core_plmn.mcc;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020061
Neels Hofmeyr10719b72018-02-21 00:39:36 +010062 if (state->local_plmn.mnc) {
63 raid.mnc = peer->cfg->core_plmn.mnc;
64 raid.mnc_3_digits = peer->cfg->core_plmn.mnc_3_digits;
65 }
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020066 } else {
67 /* SGSN -> BSS */
Neels Hofmeyr10719b72018-02-21 00:39:36 +010068 if (state->local_plmn.mcc)
69 raid.mcc = state->local_plmn.mcc;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020070
Neels Hofmeyr10719b72018-02-21 00:39:36 +010071 if (state->local_plmn.mnc) {
72 raid.mnc = state->local_plmn.mnc;
73 raid.mnc_3_digits = state->local_plmn.mnc_3_digits;
74 }
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020075 }
76
Jacob Erlbeckcba4c0c2014-09-15 14:38:37 +020077 LOGP(DGPRS, LOGL_DEBUG,
78 "Patching %s to %s: "
Neels Hofmeyr10719b72018-02-21 00:39:36 +010079 "%s-%d-%d -> %s\n",
Jacob Erlbeckcba4c0c2014-09-15 14:38:37 +020080 log_text,
81 to_bss ? "BSS" : "SGSN",
Neels Hofmeyr10719b72018-02-21 00:39:36 +010082 osmo_plmn_name(&old_plmn), raid.lac, raid.rac,
83 osmo_rai_name(&raid));
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020084
Max25c65c32018-01-08 14:43:53 +010085 gsm48_encode_ra(raid_enc, &raid);
Jacob Erlbeckcba4c0c2014-09-15 14:38:37 +020086 rate_ctr_inc(&peer->ctrg->ctr[counter]);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020087}
88
89static void gbproxy_patch_apn_ie(struct msgb *msg,
90 uint8_t *apn_ie, size_t apn_ie_len,
91 struct gbproxy_peer *peer,
92 size_t *new_apn_ie_len, const char *log_text)
93{
94 struct apn_ie_hdr {
95 uint8_t iei;
96 uint8_t apn_len;
97 uint8_t apn[0];
98 } *hdr = (void *)apn_ie;
99
100 size_t apn_len = hdr->apn_len;
101 uint8_t *apn = hdr->apn;
102
103 OSMO_ASSERT(apn_ie_len == apn_len + sizeof(struct apn_ie_hdr));
104 OSMO_ASSERT(apn_ie_len > 2 && apn_ie_len <= 102);
105
106 if (peer->cfg->core_apn_size == 0) {
107 char str1[110];
108 /* Remove the IE */
109 LOGP(DGPRS, LOGL_DEBUG,
110 "Patching %s to SGSN: Removing APN '%s'\n",
111 log_text,
Harald Welte7e82b742017-08-12 13:43:54 +0200112 osmo_apn_to_str(str1, apn, apn_len));
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200113
114 *new_apn_ie_len = 0;
115 gprs_msgb_resize_area(msg, apn_ie, apn_ie_len, 0);
116 } else {
117 /* Resize the IE */
118 char str1[110];
119 char str2[110];
120
121 OSMO_ASSERT(peer->cfg->core_apn_size <= 100);
122
123 LOGP(DGPRS, LOGL_DEBUG,
124 "Patching %s to SGSN: "
125 "Replacing APN '%s' -> '%s'\n",
126 log_text,
Harald Welte7e82b742017-08-12 13:43:54 +0200127 osmo_apn_to_str(str1, apn, apn_len),
128 osmo_apn_to_str(str2, peer->cfg->core_apn,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200129 peer->cfg->core_apn_size));
130
131 *new_apn_ie_len = peer->cfg->core_apn_size + 2;
132 gprs_msgb_resize_area(msg, apn, apn_len, peer->cfg->core_apn_size);
133 memcpy(apn, peer->cfg->core_apn, peer->cfg->core_apn_size);
134 hdr->apn_len = peer->cfg->core_apn_size;
135 }
136
137 rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]);
138}
139
140static int gbproxy_patch_tlli(uint8_t *tlli_enc,
141 struct gbproxy_peer *peer,
142 uint32_t new_tlli,
143 int to_bss, const char *log_text)
144{
145 uint32_t tlli_be;
146 uint32_t tlli;
147 enum gbproxy_peer_ctr counter =
148 to_bss ?
149 GBPROX_PEER_CTR_TLLI_PATCHED_SGSN :
150 GBPROX_PEER_CTR_TLLI_PATCHED_BSS;
151
152 memcpy(&tlli_be, tlli_enc, sizeof(tlli_be));
153 tlli = ntohl(tlli_be);
154
155 if (tlli == new_tlli)
156 return 0;
157
158 LOGP(DGPRS, LOGL_DEBUG,
159 "Patching %ss: "
160 "Replacing %08x -> %08x\n",
161 log_text, tlli, new_tlli);
162
163 tlli_be = htonl(new_tlli);
164 memcpy(tlli_enc, &tlli_be, sizeof(tlli_be));
165
166 rate_ctr_inc(&peer->ctrg->ctr[counter]);
167
168 return 1;
169}
170
171static int gbproxy_patch_ptmsi(uint8_t *ptmsi_enc,
172 struct gbproxy_peer *peer,
173 uint32_t new_ptmsi,
174 int to_bss, const char *log_text)
175{
176 uint32_t ptmsi_be;
177 uint32_t ptmsi;
178 enum gbproxy_peer_ctr counter =
179 to_bss ?
180 GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN :
181 GBPROX_PEER_CTR_PTMSI_PATCHED_BSS;
Jacob Erlbeck49389172014-10-02 16:14:47 +0200182 memcpy(&ptmsi_be, ptmsi_enc, sizeof(ptmsi_be));
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200183 ptmsi = ntohl(ptmsi_be);
184
185 if (ptmsi == new_ptmsi)
186 return 0;
187
188 LOGP(DGPRS, LOGL_DEBUG,
189 "Patching %ss: "
190 "Replacing %08x -> %08x\n",
191 log_text, ptmsi, new_ptmsi);
192
193 ptmsi_be = htonl(new_ptmsi);
Jacob Erlbeck49389172014-10-02 16:14:47 +0200194 memcpy(ptmsi_enc, &ptmsi_be, sizeof(ptmsi_be));
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200195
196 rate_ctr_inc(&peer->ctrg->ctr[counter]);
197
198 return 1;
199}
200
201int gbproxy_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
202 struct gbproxy_peer *peer,
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200203 struct gbproxy_link_info *link_info, int *len_change,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200204 struct gprs_gb_parse_context *parse_ctx)
205{
206 struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
207 int have_patched = 0;
208 int fcs;
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200209 struct gbproxy_config *cfg = peer->cfg;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200210
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200211 if (parse_ctx->ptmsi_enc && link_info &&
Jacob Erlbeckcba4c0c2014-09-15 14:38:37 +0200212 !parse_ctx->old_raid_is_foreign && peer->cfg->patch_ptmsi) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200213 uint32_t ptmsi;
214 if (parse_ctx->to_bss)
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200215 ptmsi = link_info->tlli.ptmsi;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200216 else
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200217 ptmsi = link_info->sgsn_tlli.ptmsi;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200218
219 if (ptmsi != GSM_RESERVED_TMSI) {
220 if (gbproxy_patch_ptmsi(parse_ctx->ptmsi_enc, peer,
221 ptmsi, parse_ctx->to_bss, "P-TMSI"))
222 have_patched = 1;
223 } else {
224 /* TODO: invalidate old RAI if present (see below) */
225 }
226 }
227
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200228 if (parse_ctx->new_ptmsi_enc && link_info && cfg->patch_ptmsi) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200229 uint32_t ptmsi;
230 if (parse_ctx->to_bss)
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200231 ptmsi = link_info->tlli.ptmsi;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200232 else
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200233 ptmsi = link_info->sgsn_tlli.ptmsi;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200234
235 OSMO_ASSERT(ptmsi);
236 if (gbproxy_patch_ptmsi(parse_ctx->new_ptmsi_enc, peer,
237 ptmsi, parse_ctx->to_bss, "new P-TMSI"))
238 have_patched = 1;
239 }
240
241 if (parse_ctx->raid_enc) {
Max25c65c32018-01-08 14:43:53 +0100242 gbproxy_patch_raid((struct gsm48_ra_id *)parse_ctx->raid_enc, peer, parse_ctx->to_bss,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200243 parse_ctx->llc_msg_name);
244 have_patched = 1;
245 }
246
Jacob Erlbeck948c07f2014-09-11 15:22:18 +0200247 if (parse_ctx->old_raid_enc && !parse_ctx->old_raid_is_foreign) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200248 /* TODO: Patch to invalid if P-TMSI unknown. */
Max25c65c32018-01-08 14:43:53 +0100249 gbproxy_patch_raid((struct gsm48_ra_id *)parse_ctx->old_raid_enc, peer, parse_ctx->to_bss,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200250 parse_ctx->llc_msg_name);
251 have_patched = 1;
252 }
253
254 if (parse_ctx->apn_ie &&
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200255 cfg->core_apn &&
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200256 !parse_ctx->to_bss &&
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200257 gbproxy_imsi_matches(cfg, GBPROX_MATCH_PATCHING, link_info) &&
258 cfg->core_apn) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200259 size_t new_len;
260 gbproxy_patch_apn_ie(msg,
261 parse_ctx->apn_ie, parse_ctx->apn_ie_len,
262 peer, &new_len, parse_ctx->llc_msg_name);
263 *len_change += (int)new_len - (int)parse_ctx->apn_ie_len;
264
265 have_patched = 1;
266 }
267
268 if (have_patched) {
269 llc_len += *len_change;
270 ghp->crc_length += *len_change;
271
272 /* Fix FCS */
273 fcs = gprs_llc_fcs(llc, ghp->crc_length);
274 LOGP(DLLC, LOGL_DEBUG, "Updated LLC message, CRC: %06x -> %06x\n",
275 ghp->fcs, fcs);
276
277 llc[llc_len - 3] = fcs & 0xff;
278 llc[llc_len - 2] = (fcs >> 8) & 0xff;
279 llc[llc_len - 1] = (fcs >> 16) & 0xff;
280 }
281
282 return have_patched;
283}
284
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100285/* patch BSSGP message to use core_plmn.mcc/mnc on the SGSN side */
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200286void gbproxy_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
287 struct gbproxy_peer *peer,
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200288 struct gbproxy_link_info *link_info, int *len_change,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200289 struct gprs_gb_parse_context *parse_ctx)
290{
291 const char *err_info = NULL;
292 int err_ctr = -1;
293
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200294 if (parse_ctx->bssgp_raid_enc)
Max25c65c32018-01-08 14:43:53 +0100295 gbproxy_patch_raid((struct gsm48_ra_id *)parse_ctx->bssgp_raid_enc, peer,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200296 parse_ctx->to_bss, "BSSGP");
297
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200298 if (parse_ctx->need_decryption &&
Jacob Erlbeck1abfdc22014-09-04 11:42:08 +0200299 (peer->cfg->patch_ptmsi || peer->cfg->core_apn)) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200300 /* Patching LLC messages has been requested
301 * explicitly, but the message (including the
302 * type) is encrypted, so we possibly fail to
303 * patch the LLC part of the message. */
304 err_ctr = GBPROX_PEER_CTR_PATCH_CRYPT_ERR;
305 err_info = "GMM message is encrypted";
306 goto patch_error;
307 }
308
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200309 if (!link_info && parse_ctx->tlli_enc && parse_ctx->to_bss) {
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200310 /* Happens with unknown (not cached) TLLI coming from
311 * the SGSN */
312 /* TODO: What shall be done with the message in this case? */
313 err_ctr = GBPROX_PEER_CTR_TLLI_UNKNOWN;
314 err_info = "TLLI sent by the SGSN is unknown";
315 goto patch_error;
316 }
317
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200318 if (!link_info)
Jacob Erlbeckecbd56c2014-08-26 10:01:57 +0200319 return;
320
Jacob Erlbeckcba4c0c2014-09-15 14:38:37 +0200321 if (parse_ctx->tlli_enc && peer->cfg->patch_ptmsi) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200322 uint32_t tlli = gbproxy_map_tlli(parse_ctx->tlli,
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200323 link_info, parse_ctx->to_bss);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200324
325 if (tlli) {
326 gbproxy_patch_tlli(parse_ctx->tlli_enc, peer, tlli,
327 parse_ctx->to_bss, "TLLI");
328 parse_ctx->tlli = tlli;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200329 } else {
330 /* Internal error */
331 err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
332 err_info = "Replacement TLLI is 0";
333 goto patch_error;
334 }
335 }
336
Jacob Erlbeckc37ef6c2014-09-30 13:49:43 +0200337 if (parse_ctx->bssgp_ptmsi_enc && peer->cfg->patch_ptmsi) {
338 uint32_t ptmsi;
339 if (parse_ctx->to_bss)
340 ptmsi = link_info->tlli.ptmsi;
341 else
342 ptmsi = link_info->sgsn_tlli.ptmsi;
343
344 if (ptmsi != GSM_RESERVED_TMSI)
345 gbproxy_patch_ptmsi(
346 parse_ctx->bssgp_ptmsi_enc, peer,
347 ptmsi, parse_ctx->to_bss, "BSSGP P-TMSI");
348 }
349
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200350 if (parse_ctx->llc) {
351 uint8_t *llc = parse_ctx->llc;
352 size_t llc_len = parse_ctx->llc_len;
353 int llc_len_change = 0;
354
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200355 gbproxy_patch_llc(msg, llc, llc_len, peer, link_info,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200356 &llc_len_change, parse_ctx);
357 /* Note that the APN might have been resized here, but no
358 * pointer int the parse_ctx will refer to an adress after the
359 * APN. So it's possible to patch first and do the TLLI
360 * handling afterwards. */
361
362 if (llc_len_change) {
363 llc_len += llc_len_change;
364
365 /* Fix LLC IE len */
366 /* TODO: This is a kludge, but the a pointer to the
367 * start of the IE is not available here */
368 if (llc[-2] == BSSGP_IE_LLC_PDU && llc[-1] & 0x80) {
369 /* most probably a one byte length */
370 if (llc_len > 127) {
371 err_info = "Cannot increase size";
372 err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
373 goto patch_error;
374 }
375 llc[-1] = llc_len | 0x80;
376 } else {
377 llc[-2] = (llc_len >> 8) & 0x7f;
378 llc[-1] = llc_len & 0xff;
379 }
380 *len_change += llc_len_change;
381 }
382 /* Note that the tp struct might contain invalid pointers here
383 * if the LLC field has changed its size */
384 parse_ctx->llc_len = llc_len;
385 }
386 return;
387
388patch_error:
389 OSMO_ASSERT(err_ctr >= 0);
390 rate_ctr_inc(&peer->ctrg->ctr[err_ctr]);
391 LOGP(DGPRS, LOGL_ERROR,
392 "NSEI=%u(%s) failed to patch BSSGP message as requested: %s.\n",
393 msgb_nsei(msg), parse_ctx->to_bss ? "SGSN" : "BSS",
394 err_info);
395}
396
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200397void gbproxy_clear_patch_filter(struct gbproxy_match *match)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200398{
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200399 if (match->enable) {
400 regfree(&match->re_comp);
401 match->enable = 0;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200402 }
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200403 talloc_free(match->re_str);
404 match->re_str = NULL;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200405}
406
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200407int gbproxy_set_patch_filter(struct gbproxy_match *match, const char *filter,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200408 const char **err_msg)
409{
410 static char err_buf[300];
411 int rc;
412
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200413 gbproxy_clear_patch_filter(match);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200414
415 if (!filter)
416 return 0;
417
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200418 rc = regcomp(&match->re_comp, filter,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200419 REG_EXTENDED | REG_NOSUB | REG_ICASE);
420
421 if (rc == 0) {
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200422 match->enable = 1;
423 match->re_str = talloc_strdup(tall_bsc_ctx, filter);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200424 return 0;
425 }
426
427 if (err_msg) {
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200428 regerror(rc, &match->re_comp,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200429 err_buf, sizeof(err_buf));
430 *err_msg = err_buf;
431 }
432
433 return -1;
434}
435
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200436int gbproxy_check_imsi(struct gbproxy_match *match,
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200437 const uint8_t *imsi, size_t imsi_len)
438{
439 char mi_buf[200];
440 int rc;
441
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200442 if (!match->enable)
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200443 return 1;
444
445 rc = gprs_is_mi_imsi(imsi, imsi_len);
446 if (rc > 0)
447 rc = gsm48_mi_to_string(mi_buf, sizeof(mi_buf), imsi, imsi_len);
448 if (rc <= 0) {
449 LOGP(DGPRS, LOGL_NOTICE, "Invalid IMSI %s\n",
450 osmo_hexdump(imsi, imsi_len));
451 return -1;
452 }
453
454 LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi_buf, rc);
455
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200456 rc = regexec(&match->re_comp, mi_buf, 0, NULL, 0);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200457 if (rc == REG_NOMATCH) {
458 LOGP(DGPRS, LOGL_INFO,
459 "IMSI '%s' doesn't match pattern '%s'\n",
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200460 mi_buf, match->re_str);
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200461 return 0;
462 }
463
464 return 1;
465}
466