blob: bf1c4e0daf30863f18317e92b842489207a7333b [file] [log] [blame]
Harald Welte799e0c92010-04-30 21:49:24 +02001/*
2 * (C) 2010 by Harald Welte <laforge@gnumonks.org>
3 * (C) 2010 by On-Waves
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01007 * 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
Harald Welte799e0c92010-04-30 21:49:24 +02009 * (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
Harald Welte9af6ddf2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Harald Welte799e0c92010-04-30 21:49:24 +020015 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * 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/>.
Harald Welte799e0c92010-04-30 21:49:24 +020018 *
19 */
20
Harald Welte799e0c92010-04-30 21:49:24 +020021#include <sys/socket.h>
22#include <netinet/in.h>
23#include <arpa/inet.h>
Jacob Erlbeck73685282014-05-23 20:48:07 +020024#include <string.h>
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020025#include <time.h>
Pau Espin Pedrol67f1d1e2018-08-16 12:11:46 +020026#include <inttypes.h>
Harald Welte799e0c92010-04-30 21:49:24 +020027
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010028#include <osmocom/core/talloc.h>
Alexander Couzens82182d02020-09-22 13:21:46 +020029#include <osmocom/core/timer.h>
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020030#include <osmocom/core/rate_ctr.h>
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020031#include <osmocom/gsm/gsm48.h>
Harald Welte799e0c92010-04-30 21:49:24 +020032
Alexander Couzens82182d02020-09-22 13:21:46 +020033#include <osmocom/gprs/gprs_ns2.h>
Harald Welte7e82b742017-08-12 13:43:54 +020034#include <osmocom/gsm/apn.h>
Harald Welteea34a4e2012-06-16 14:59:56 +080035
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020036#include <osmocom/sgsn/debug.h>
37#include <osmocom/sgsn/gb_proxy.h>
38#include <osmocom/sgsn/gprs_utils.h>
39#include <osmocom/sgsn/vty.h>
Harald Welte799e0c92010-04-30 21:49:24 +020040
Harald Welte4b037e42010-05-19 19:45:32 +020041#include <osmocom/vty/command.h>
Daniel Willmanne8c8ec92020-12-02 19:33:50 +010042#include <osmocom/vty/logging.h>
Harald Welte4b037e42010-05-19 19:45:32 +020043#include <osmocom/vty/vty.h>
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020044#include <osmocom/vty/misc.h>
Harald Welte799e0c92010-04-30 21:49:24 +020045
Harald Welte799e0c92010-04-30 21:49:24 +020046static struct gbproxy_config *g_cfg = NULL;
47
48/*
Pau Espin Pedrol94998fa2018-06-20 23:55:22 +020049 * vty code for gbproxy below
Harald Welte799e0c92010-04-30 21:49:24 +020050 */
Harald Welteb77c6972010-05-01 11:28:43 +020051static struct cmd_node gbproxy_node = {
Harald Welte799e0c92010-04-30 21:49:24 +020052 GBPROXY_NODE,
Harald Welte570ce242012-08-17 13:16:10 +020053 "%s(config-gbproxy)# ",
Harald Welte799e0c92010-04-30 21:49:24 +020054 1,
55};
56
Jacob Erlbeck7430da62014-09-12 15:09:56 +020057static const struct value_string keep_modes[] = {
58 {GBPROX_KEEP_NEVER, "never"},
59 {GBPROX_KEEP_REATTACH, "re-attach"},
60 {GBPROX_KEEP_IDENTIFIED, "identified"},
61 {GBPROX_KEEP_ALWAYS, "always"},
62 {0, NULL}
63};
64
Jacob Erlbeck6c3fdc12014-09-25 13:39:06 +020065static const struct value_string match_ids[] = {
66 {GBPROX_MATCH_PATCHING, "patching"},
Jacob Erlbeckb36032c2014-09-25 13:21:48 +020067 {GBPROX_MATCH_ROUTING, "routing"},
Jacob Erlbeck6c3fdc12014-09-25 13:39:06 +020068 {0, NULL}
69};
70
Holger Hans Peter Freyther1ddd9e52014-08-04 11:35:32 +020071static void gbprox_vty_print_peer(struct vty *vty, struct gbproxy_peer *peer)
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020072{
73 struct gprs_ra_id raid;
74 gsm48_parse_ra(&raid, peer->ra);
75
76 vty_out(vty, "NSEI %5u, PTP-BVCI %5u, "
Daniel Willmann447ad442020-11-26 18:19:21 +010077 "RAI %s", peer->nse->nsei, peer->bvci, osmo_rai_name(&raid));
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020078 if (peer->blocked)
79 vty_out(vty, " [BVC-BLOCKED]");
80
81 vty_out(vty, "%s", VTY_NEWLINE);
82}
83
Harald Welte799e0c92010-04-30 21:49:24 +020084static int config_write_gbproxy(struct vty *vty)
85{
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +020086 enum gbproxy_match_id match_id;
87
Harald Welte799e0c92010-04-30 21:49:24 +020088 vty_out(vty, "gbproxy%s", VTY_NEWLINE);
89
Harald Welteff3bde82010-05-19 15:09:09 +020090 vty_out(vty, " sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei,
Harald Welte799e0c92010-04-30 21:49:24 +020091 VTY_NEWLINE);
Harald Welte799e0c92010-04-30 21:49:24 +020092
Neels Hofmeyr10719b72018-02-21 00:39:36 +010093 if (g_cfg->core_plmn.mcc > 0)
94 vty_out(vty, " core-mobile-country-code %s%s",
95 osmo_mcc_name(g_cfg->core_plmn.mcc), VTY_NEWLINE);
96 if (g_cfg->core_plmn.mnc > 0)
97 vty_out(vty, " core-mobile-network-code %s%s",
98 osmo_mnc_name(g_cfg->core_plmn.mnc, g_cfg->core_plmn.mnc_3_digits), VTY_NEWLINE);
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +020099
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200100 for (match_id = 0; match_id < ARRAY_SIZE(g_cfg->matches); ++match_id) {
101 struct gbproxy_match *match = &g_cfg->matches[match_id];
102 if (match->re_str)
Jacob Erlbeck6c3fdc12014-09-25 13:39:06 +0200103 vty_out(vty, " match-imsi %s %s%s",
104 get_value_string(match_ids, match_id),
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200105 match->re_str, VTY_NEWLINE);
106 }
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200107
Jacob Erlbeck73685282014-05-23 20:48:07 +0200108 if (g_cfg->core_apn != NULL) {
109 if (g_cfg->core_apn_size > 0) {
110 char str[500] = {0};
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200111 vty_out(vty, " core-access-point-name %s%s",
Harald Welte7e82b742017-08-12 13:43:54 +0200112 osmo_apn_to_str(str, g_cfg->core_apn,
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200113 g_cfg->core_apn_size),
114 VTY_NEWLINE);
Jacob Erlbeck73685282014-05-23 20:48:07 +0200115 } else {
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200116 vty_out(vty, " core-access-point-name none%s",
117 VTY_NEWLINE);
Jacob Erlbeck73685282014-05-23 20:48:07 +0200118 }
119 }
Jacob Erlbeck0d4236b2014-08-18 14:54:37 +0200120
Jacob Erlbeck25f98e62014-08-28 13:47:53 +0200121 if (g_cfg->route_to_sgsn2)
122 vty_out(vty, " secondary-sgsn nsei %u%s", g_cfg->nsip_sgsn2_nsei,
123 VTY_NEWLINE);
124
Pau Espin Pedrol82f13612018-08-17 13:13:27 +0200125 if (g_cfg->clean_stale_timer_freq > 0)
126 vty_out(vty, " link-list clean-stale-timer %u%s",
127 g_cfg->clean_stale_timer_freq, VTY_NEWLINE);
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200128 if (g_cfg->tlli_max_age > 0)
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200129 vty_out(vty, " link-list max-age %d%s",
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200130 g_cfg->tlli_max_age, VTY_NEWLINE);
131 if (g_cfg->tlli_max_len > 0)
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200132 vty_out(vty, " link-list max-length %d%s",
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200133 g_cfg->tlli_max_len, VTY_NEWLINE);
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200134 vty_out(vty, " link-list keep-mode %s%s",
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200135 get_value_string(keep_modes, g_cfg->keep_link_infos),
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200136 VTY_NEWLINE);
Pau Espin Pedrol67f1d1e2018-08-16 12:11:46 +0200137 if (g_cfg->stored_msgs_max_len > 0)
138 vty_out(vty, " link stored-msgs-max-length %"PRIu32"%s",
139 g_cfg->stored_msgs_max_len, VTY_NEWLINE);
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200140
Jacob Erlbeck67a44452014-05-19 10:14:58 +0200141
Harald Welte799e0c92010-04-30 21:49:24 +0200142 return CMD_SUCCESS;
143}
144
Harald Welte799e0c92010-04-30 21:49:24 +0200145DEFUN(cfg_gbproxy,
146 cfg_gbproxy_cmd,
147 "gbproxy",
148 "Configure the Gb proxy")
149{
150 vty->node = GBPROXY_NODE;
151 return CMD_SUCCESS;
152}
153
Harald Welte799e0c92010-04-30 21:49:24 +0200154DEFUN(cfg_nsip_sgsn_nsei,
155 cfg_nsip_sgsn_nsei_cmd,
Harald Welteff3bde82010-05-19 15:09:09 +0200156 "sgsn nsei <0-65534>",
Holger Hans Peter Freyther2eb6e2c2011-11-05 15:14:59 +0100157 "SGSN information\n"
158 "NSEI to be used in the connection with the SGSN\n"
159 "The NSEI\n")
Harald Welte799e0c92010-04-30 21:49:24 +0200160{
Jacob Erlbeckcc8856f2014-10-08 13:37:28 +0200161 unsigned int nsei = atoi(argv[0]);
Harald Welte799e0c92010-04-30 21:49:24 +0200162
Jacob Erlbeckcc8856f2014-10-08 13:37:28 +0200163 if (g_cfg->route_to_sgsn2 && g_cfg->nsip_sgsn2_nsei == nsei) {
164 vty_out(vty, "SGSN NSEI %d conflicts with secondary SGSN NSEI%s",
165 nsei, VTY_NEWLINE);
166 return CMD_WARNING;
167 }
168
169 g_cfg->nsip_sgsn_nsei = nsei;
Harald Welte799e0c92010-04-30 21:49:24 +0200170 return CMD_SUCCESS;
171}
172
Jacob Erlbeck67a44452014-05-19 10:14:58 +0200173#define GBPROXY_CORE_MNC_STR "Use this network code for the core network\n"
174
175DEFUN(cfg_gbproxy_core_mnc,
176 cfg_gbproxy_core_mnc_cmd,
177 "core-mobile-network-code <1-999>",
178 GBPROXY_CORE_MNC_STR "NCC value\n")
179{
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100180 uint16_t mnc;
181 bool mnc_3_digits;
182 if (osmo_mnc_from_str(argv[0], &mnc, &mnc_3_digits)) {
183 vty_out(vty, "%% Invalid MNC: %s%s", argv[0], VTY_NEWLINE);
184 return CMD_WARNING;
185 }
186 g_cfg->core_plmn.mnc = mnc;
187 g_cfg->core_plmn.mnc_3_digits = mnc_3_digits;
Jacob Erlbeck67a44452014-05-19 10:14:58 +0200188 return CMD_SUCCESS;
189}
190
191DEFUN(cfg_gbproxy_no_core_mnc,
192 cfg_gbproxy_no_core_mnc_cmd,
193 "no core-mobile-network-code",
194 NO_STR GBPROXY_CORE_MNC_STR)
195{
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100196 g_cfg->core_plmn.mnc = 0;
197 g_cfg->core_plmn.mnc_3_digits = false;
Jacob Erlbeck67a44452014-05-19 10:14:58 +0200198 return CMD_SUCCESS;
199}
200
201#define GBPROXY_CORE_MCC_STR "Use this country code for the core network\n"
202
203DEFUN(cfg_gbproxy_core_mcc,
204 cfg_gbproxy_core_mcc_cmd,
205 "core-mobile-country-code <1-999>",
206 GBPROXY_CORE_MCC_STR "MCC value\n")
207{
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100208 g_cfg->core_plmn.mcc = atoi(argv[0]);
Jacob Erlbeck67a44452014-05-19 10:14:58 +0200209 return CMD_SUCCESS;
210}
211
212DEFUN(cfg_gbproxy_no_core_mcc,
213 cfg_gbproxy_no_core_mcc_cmd,
214 "no core-mobile-country-code",
215 NO_STR GBPROXY_CORE_MCC_STR)
216{
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100217 g_cfg->core_plmn.mcc = 0;
Jacob Erlbeck67a44452014-05-19 10:14:58 +0200218 return CMD_SUCCESS;
219}
220
Jacob Erlbeck6c3fdc12014-09-25 13:39:06 +0200221#define GBPROXY_MATCH_IMSI_STR "Restrict actions to certain IMSIs\n"
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200222
223DEFUN(cfg_gbproxy_match_imsi,
224 cfg_gbproxy_match_imsi_cmd,
Jacob Erlbeckb36032c2014-09-25 13:21:48 +0200225 "match-imsi (patching|routing) .REGEXP",
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200226 GBPROXY_MATCH_IMSI_STR
Jacob Erlbeckb36032c2014-09-25 13:21:48 +0200227 "Patch MS related information elements on match only\n"
228 "Route to the secondary SGSN on match only\n"
Jacob Erlbeck6c3fdc12014-09-25 13:39:06 +0200229 "Regular expression for the IMSI match\n")
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200230{
Jacob Erlbeckb36032c2014-09-25 13:21:48 +0200231 const char *filter = argv[1];
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200232 const char *err_msg = NULL;
Jacob Erlbeck6c3fdc12014-09-25 13:39:06 +0200233 struct gbproxy_match *match;
Jacob Erlbeckb36032c2014-09-25 13:21:48 +0200234 enum gbproxy_match_id match_id = get_string_value(match_ids, argv[0]);
Jacob Erlbeck6c3fdc12014-09-25 13:39:06 +0200235
236 OSMO_ASSERT(match_id >= GBPROX_MATCH_PATCHING &&
237 match_id < GBPROX_MATCH_LAST);
238 match = &g_cfg->matches[match_id];
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200239
Jacob Erlbeck9a83d7a2014-09-25 11:17:31 +0200240 if (gbproxy_set_patch_filter(match, filter, &err_msg) != 0) {
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200241 vty_out(vty, "Match expression invalid: %s%s",
242 err_msg, VTY_NEWLINE);
243 return CMD_WARNING;
244 }
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200245
Harald Welteaed46ec2019-03-22 09:44:42 +0100246 g_cfg->acquire_imsi = true;
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200247
248 return CMD_SUCCESS;
249}
250
251DEFUN(cfg_gbproxy_no_match_imsi,
252 cfg_gbproxy_no_match_imsi_cmd,
253 "no match-imsi",
254 NO_STR GBPROXY_MATCH_IMSI_STR)
255{
Jacob Erlbeck6c3fdc12014-09-25 13:39:06 +0200256 enum gbproxy_match_id match_id;
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200257
Jacob Erlbeck6c3fdc12014-09-25 13:39:06 +0200258 for (match_id = 0; match_id < ARRAY_SIZE(g_cfg->matches); ++match_id)
259 gbproxy_clear_patch_filter(&g_cfg->matches[match_id]);
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200260
Harald Welteaed46ec2019-03-22 09:44:42 +0100261 g_cfg->acquire_imsi = false;
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200262
263 return CMD_SUCCESS;
264}
265
Jacob Erlbeck73685282014-05-23 20:48:07 +0200266#define GBPROXY_CORE_APN_STR "Use this access point name (APN) for the backbone\n"
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200267#define GBPROXY_CORE_APN_ARG_STR "Replace APN by this string\n" "Remove APN\n"
Jacob Erlbeck73685282014-05-23 20:48:07 +0200268
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200269static int set_core_apn(struct vty *vty, const char *apn)
Jacob Erlbeck73685282014-05-23 20:48:07 +0200270{
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200271 int apn_len;
Jacob Erlbeck73685282014-05-23 20:48:07 +0200272
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200273 if (!apn) {
274 talloc_free(g_cfg->core_apn);
275 g_cfg->core_apn = NULL;
276 g_cfg->core_apn_size = 0;
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200277 return CMD_SUCCESS;
278 }
Jacob Erlbeck73685282014-05-23 20:48:07 +0200279
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200280 apn_len = strlen(apn);
281
282 if (apn_len >= 100) {
Jacob Erlbeck73685282014-05-23 20:48:07 +0200283 vty_out(vty, "APN string too long (max 99 chars)%s",
284 VTY_NEWLINE);
285 return CMD_WARNING;
286 }
287
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200288 if (apn_len == 0) {
289 talloc_free(g_cfg->core_apn);
290 /* TODO: replace NULL */
291 g_cfg->core_apn = talloc_zero_size(NULL, 2);
292 g_cfg->core_apn_size = 0;
293 } else {
294 /* TODO: replace NULL */
295 g_cfg->core_apn =
296 talloc_realloc_size(NULL, g_cfg->core_apn, apn_len + 1);
297 g_cfg->core_apn_size =
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +0200298 gprs_str_to_apn(g_cfg->core_apn, apn_len + 1, apn);
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200299 }
Jacob Erlbeck73685282014-05-23 20:48:07 +0200300
301 return CMD_SUCCESS;
302}
303
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200304DEFUN(cfg_gbproxy_core_apn,
305 cfg_gbproxy_core_apn_cmd,
306 "core-access-point-name (APN|none)",
307 GBPROXY_CORE_APN_STR GBPROXY_CORE_APN_ARG_STR)
308{
309 if (strcmp(argv[0], "none") == 0)
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200310 return set_core_apn(vty, "");
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200311 else
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200312 return set_core_apn(vty, argv[0]);
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200313}
314
Jacob Erlbeck73685282014-05-23 20:48:07 +0200315DEFUN(cfg_gbproxy_no_core_apn,
316 cfg_gbproxy_no_core_apn_cmd,
317 "no core-access-point-name",
318 NO_STR GBPROXY_CORE_APN_STR)
319{
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200320 return set_core_apn(vty, NULL);
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200321}
322
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200323/* TODO: Remove the patch-ptmsi command, since P-TMSI patching is enabled
324 * automatically when needed. This command is only left for manual testing
325 * (e.g. doing P-TMSI patching without using a secondary SGSN)
326 */
Jacob Erlbeck0d4236b2014-08-18 14:54:37 +0200327#define GBPROXY_PATCH_PTMSI_STR "Patch P-TMSI/TLLI\n"
328
329DEFUN(cfg_gbproxy_patch_ptmsi,
330 cfg_gbproxy_patch_ptmsi_cmd,
331 "patch-ptmsi",
332 GBPROXY_PATCH_PTMSI_STR)
333{
Harald Welteaed46ec2019-03-22 09:44:42 +0100334 g_cfg->patch_ptmsi = true;
Jacob Erlbeck0d4236b2014-08-18 14:54:37 +0200335
336 return CMD_SUCCESS;
337}
338
339DEFUN(cfg_gbproxy_no_patch_ptmsi,
340 cfg_gbproxy_no_patch_ptmsi_cmd,
341 "no patch-ptmsi",
342 NO_STR GBPROXY_PATCH_PTMSI_STR)
343{
Harald Welteaed46ec2019-03-22 09:44:42 +0100344 g_cfg->patch_ptmsi = false;
Jacob Erlbeck0d4236b2014-08-18 14:54:37 +0200345
346 return CMD_SUCCESS;
347}
348
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200349/* TODO: Remove the acquire-imsi command, since that feature is enabled
350 * automatically when IMSI matching is enabled. This command is only left for
351 * manual testing (e.g. doing IMSI acquisition without IMSI based patching)
352 */
Jacob Erlbeck5f4ef322014-08-22 17:10:01 +0200353#define GBPROXY_ACQUIRE_IMSI_STR "Acquire the IMSI before establishing a LLC connection (Experimental)\n"
354
355DEFUN(cfg_gbproxy_acquire_imsi,
356 cfg_gbproxy_acquire_imsi_cmd,
357 "acquire-imsi",
358 GBPROXY_ACQUIRE_IMSI_STR)
359{
Harald Welteaed46ec2019-03-22 09:44:42 +0100360 g_cfg->acquire_imsi = true;
Jacob Erlbeck5f4ef322014-08-22 17:10:01 +0200361
362 return CMD_SUCCESS;
363}
364
365DEFUN(cfg_gbproxy_no_acquire_imsi,
366 cfg_gbproxy_no_acquire_imsi_cmd,
367 "no acquire-imsi",
368 NO_STR GBPROXY_ACQUIRE_IMSI_STR)
369{
Harald Welteaed46ec2019-03-22 09:44:42 +0100370 g_cfg->acquire_imsi = false;
Jacob Erlbeck5f4ef322014-08-22 17:10:01 +0200371
372 return CMD_SUCCESS;
373}
374
Jacob Erlbeckf4d60c82014-08-26 14:47:15 +0200375#define GBPROXY_SECOND_SGSN_STR "Route matching LLC connections to a second SGSN (Experimental)\n"
376
377DEFUN(cfg_gbproxy_secondary_sgsn,
378 cfg_gbproxy_secondary_sgsn_cmd,
379 "secondary-sgsn nsei <0-65534>",
380 GBPROXY_SECOND_SGSN_STR
381 "NSEI to be used in the connection with the SGSN\n"
382 "The NSEI\n")
383{
Jacob Erlbeckcc8856f2014-10-08 13:37:28 +0200384 unsigned int nsei = atoi(argv[0]);
385
386 if (g_cfg->nsip_sgsn_nsei == nsei) {
387 vty_out(vty, "Secondary SGSN NSEI %d conflicts with primary SGSN NSEI%s",
388 nsei, VTY_NEWLINE);
389 return CMD_WARNING;
390 }
391
Harald Welteaed46ec2019-03-22 09:44:42 +0100392 g_cfg->route_to_sgsn2 = true;
Jacob Erlbeckcc8856f2014-10-08 13:37:28 +0200393 g_cfg->nsip_sgsn2_nsei = nsei;
Jacob Erlbeckf4d60c82014-08-26 14:47:15 +0200394
Harald Welteaed46ec2019-03-22 09:44:42 +0100395 g_cfg->patch_ptmsi = true;
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200396
Jacob Erlbeckf4d60c82014-08-26 14:47:15 +0200397 return CMD_SUCCESS;
398}
399
400DEFUN(cfg_gbproxy_no_secondary_sgsn,
401 cfg_gbproxy_no_secondary_sgsn_cmd,
402 "no secondary-sgsn",
403 NO_STR GBPROXY_SECOND_SGSN_STR)
404{
Harald Welteaed46ec2019-03-22 09:44:42 +0100405 g_cfg->route_to_sgsn2 = false;
Jacob Erlbeckf4d60c82014-08-26 14:47:15 +0200406 g_cfg->nsip_sgsn2_nsei = 0xFFFF;
407
Harald Welteaed46ec2019-03-22 09:44:42 +0100408 g_cfg->patch_ptmsi = false;
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200409
Jacob Erlbeckf4d60c82014-08-26 14:47:15 +0200410 return CMD_SUCCESS;
411}
412
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200413#define GBPROXY_LINK_LIST_STR "Set TLLI list parameters\n"
Pau Espin Pedrol67f1d1e2018-08-16 12:11:46 +0200414#define GBPROXY_LINK_STR "Set TLLI parameters\n"
Pau Espin Pedrol82f13612018-08-17 13:13:27 +0200415
416#define GBPROXY_CLEAN_STALE_TIMER_STR "Periodic timer to clean stale links\n"
417
418DEFUN(cfg_gbproxy_link_list_clean_stale_timer,
419 cfg_gbproxy_link_list_clean_stale_timer_cmd,
420 "link-list clean-stale-timer <1-999999>",
421 GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR
422 "Frequency at which the periodic timer is fired (in seconds)\n")
423{
Daniel Willmann447ad442020-11-26 18:19:21 +0100424 struct gbproxy_nse *nse;
Pau Espin Pedrol82f13612018-08-17 13:13:27 +0200425 g_cfg->clean_stale_timer_freq = (unsigned int) atoi(argv[0]);
426
427 /* Re-schedule running timers soon in case prev frequency was really big
428 and new frequency is desired to be lower. After initial run, periodic
429 time is used. Use random() to avoid firing timers for all peers at
430 the same time */
Daniel Willmann447ad442020-11-26 18:19:21 +0100431 llist_for_each_entry(nse, &g_cfg->nse_peers, list) {
432 struct gbproxy_peer *peer;
433 llist_for_each_entry(peer, &nse->bts_peers, list)
434 osmo_timer_schedule(&peer->clean_stale_timer,
435 random() % 5, random() % 1000000);
436 }
Pau Espin Pedrol82f13612018-08-17 13:13:27 +0200437
438 return CMD_SUCCESS;
439}
440
441DEFUN(cfg_gbproxy_link_list_no_clean_stale_timer,
442 cfg_gbproxy_link_list_no_clean_stale_timer_cmd,
443 "no link-list clean-stale-timer",
444 NO_STR GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR)
445
446{
Daniel Willmann447ad442020-11-26 18:19:21 +0100447 struct gbproxy_nse *nse;
Pau Espin Pedrol82f13612018-08-17 13:13:27 +0200448 g_cfg->clean_stale_timer_freq = 0;
449
Daniel Willmann447ad442020-11-26 18:19:21 +0100450 llist_for_each_entry(nse, &g_cfg->nse_peers, list) {
451 struct gbproxy_peer *peer;
452 llist_for_each_entry(peer, &nse->bts_peers, list)
453 osmo_timer_del(&peer->clean_stale_timer);
454 }
Pau Espin Pedrol82f13612018-08-17 13:13:27 +0200455
456 return CMD_SUCCESS;
457}
458
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200459#define GBPROXY_MAX_AGE_STR "Limit maximum age\n"
460
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200461DEFUN(cfg_gbproxy_link_list_max_age,
462 cfg_gbproxy_link_list_max_age_cmd,
463 "link-list max-age <1-999999>",
464 GBPROXY_LINK_LIST_STR GBPROXY_MAX_AGE_STR
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200465 "Maximum age in seconds\n")
466{
467 g_cfg->tlli_max_age = atoi(argv[0]);
468
Jacob Erlbeck73685282014-05-23 20:48:07 +0200469 return CMD_SUCCESS;
470}
471
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200472DEFUN(cfg_gbproxy_link_list_no_max_age,
473 cfg_gbproxy_link_list_no_max_age_cmd,
474 "no link-list max-age",
475 NO_STR GBPROXY_LINK_LIST_STR GBPROXY_MAX_AGE_STR)
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200476{
477 g_cfg->tlli_max_age = 0;
478
479 return CMD_SUCCESS;
480}
481
482#define GBPROXY_MAX_LEN_STR "Limit list length\n"
483
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200484DEFUN(cfg_gbproxy_link_list_max_len,
485 cfg_gbproxy_link_list_max_len_cmd,
486 "link-list max-length <1-99999>",
487 GBPROXY_LINK_LIST_STR GBPROXY_MAX_LEN_STR
488 "Maximum number of logical links in the list\n")
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200489{
490 g_cfg->tlli_max_len = atoi(argv[0]);
491
492 return CMD_SUCCESS;
493}
494
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200495DEFUN(cfg_gbproxy_link_list_no_max_len,
496 cfg_gbproxy_link_list_no_max_len_cmd,
497 "no link-list max-length",
498 NO_STR GBPROXY_LINK_LIST_STR GBPROXY_MAX_LEN_STR)
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200499{
500 g_cfg->tlli_max_len = 0;
501
502 return CMD_SUCCESS;
503}
504
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200505DEFUN(cfg_gbproxy_link_list_keep_mode,
506 cfg_gbproxy_link_list_keep_mode_cmd,
507 "link-list keep-mode (never|re-attach|identified|always)",
508 GBPROXY_LINK_LIST_STR "How to keep entries for detached logical links\n"
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200509 "Discard entry immediately after detachment\n"
510 "Keep entry if a re-attachment has be requested\n"
511 "Keep entry if it associated with an IMSI\n"
512 "Don't discard entries after detachment\n")
513{
514 int val = get_string_value(keep_modes, argv[0]);
515 OSMO_ASSERT(val >= GBPROX_KEEP_NEVER && val <= GBPROX_KEEP_ALWAYS);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200516 g_cfg->keep_link_infos = val;
Jacob Erlbeck7430da62014-09-12 15:09:56 +0200517
518 return CMD_SUCCESS;
519}
520
Pau Espin Pedrol67f1d1e2018-08-16 12:11:46 +0200521DEFUN(cfg_gbproxy_link_stored_msgs_max_len,
522 cfg_gbproxy_link_stored_msgs_max_len_cmd,
523 "link stored-msgs-max-length <1-99999>",
524 GBPROXY_LINK_STR GBPROXY_MAX_LEN_STR
525 "Maximum number of msgb stored in the logical link waiting to acquire its IMSI\n")
526{
527 g_cfg->stored_msgs_max_len = (uint32_t) atoi(argv[0]);
528
529 return CMD_SUCCESS;
530}
531
532DEFUN(cfg_gbproxy_link_no_stored_msgs_max_len,
533 cfg_gbproxy_link_no_stored_msgs_max_len_cmd,
534 "no link stored-msgs-max-length",
535 NO_STR GBPROXY_LINK_STR GBPROXY_MAX_LEN_STR)
536{
537 g_cfg->stored_msgs_max_len = 0;
538
539 return CMD_SUCCESS;
540}
541
Daniel Willmanne8c8ec92020-12-02 19:33:50 +0100542static void log_set_bvc_filter(struct log_target *target,
543 const uint16_t *bvci)
544{
545 if (bvci) {
546 uintptr_t bvci_filter = *bvci | BVC_LOG_CTX_FLAG;
547 target->filter_map |= (1 << LOG_FLT_GB_BVC);
548 target->filter_data[LOG_FLT_GB_BVC] = (void *)bvci_filter;
549 } else if (target->filter_data[LOG_FLT_GB_BVC]) {
550 target->filter_map = ~(1 << LOG_FLT_GB_BVC);
551 target->filter_data[LOG_FLT_GB_BVC] = NULL;
552 }
553}
554
555DEFUN(logging_fltr_bvc,
556 logging_fltr_bvc_cmd,
557 "logging filter bvc bvci <0-65535>",
558 LOGGING_STR FILTER_STR
559 "Filter based on BSSGP VC\n"
560 "Identify BVC by BVCI\n"
561 "Numeric identifier\n")
562{
563 struct log_target *tgt;
564 uint16_t id = atoi(argv[0]);
565
566 log_tgt_mutex_lock();
567 tgt = osmo_log_vty2tgt(vty);
568 if (!tgt) {
569 log_tgt_mutex_unlock();
570 return CMD_WARNING;
571 }
572
573 log_set_bvc_filter(tgt, &id);
574 log_tgt_mutex_unlock();
575 return CMD_SUCCESS;
576}
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200577
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200578DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy [stats]",
579 SHOW_STR "Display information about the Gb proxy\n" "Show statistics\n")
580{
Daniel Willmann447ad442020-11-26 18:19:21 +0100581 struct gbproxy_nse *nse;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200582 int show_stats = argc >= 1;
Jacob Erlbeck91fb6802014-05-28 10:59:10 +0200583
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200584 if (show_stats)
Holger Hans Peter Freythereece6272014-08-04 15:42:36 +0200585 vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200586
Daniel Willmann447ad442020-11-26 18:19:21 +0100587 llist_for_each_entry(nse, &g_cfg->nse_peers, list) {
588 struct gbproxy_peer *peer;
589 llist_for_each_entry(peer, &nse->bts_peers, list) {
590 gbprox_vty_print_peer(vty, peer);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200591
Daniel Willmann447ad442020-11-26 18:19:21 +0100592 if (show_stats)
593 vty_out_rate_ctr_group(vty, " ", peer->ctrg);
594 }
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200595 }
596 return CMD_SUCCESS;
597}
598
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200599DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
600 SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200601{
Daniel Willmann447ad442020-11-26 18:19:21 +0100602 struct gbproxy_nse *nse;
Jacob Erlbeckc6807c42014-09-19 16:34:01 +0200603 time_t now;
604 struct timespec ts = {0,};
605
Pau Espin Pedrol36abead2018-08-17 13:27:20 +0200606 osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
Jacob Erlbeckc6807c42014-09-19 16:34:01 +0200607 now = ts.tv_sec;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200608
Daniel Willmann447ad442020-11-26 18:19:21 +0100609 llist_for_each_entry(nse, &g_cfg->nse_peers, list) {
610 struct gbproxy_peer *peer;
611 llist_for_each_entry(peer, &nse->bts_peers, list) {
612 struct gbproxy_link_info *link_info;
613 struct gbproxy_patch_state *state = &peer->patch_state;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200614
Daniel Willmann447ad442020-11-26 18:19:21 +0100615 gbprox_vty_print_peer(vty, peer);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200616
Daniel Willmann447ad442020-11-26 18:19:21 +0100617 llist_for_each_entry(link_info, &state->logical_links, list) {
618 time_t age = now - link_info->timestamp;
619 struct osmo_mobile_identity mi;
620 const char *imsi_str;
Jacob Erlbeck146e3072014-09-02 14:09:01 +0200621
Daniel Willmann447ad442020-11-26 18:19:21 +0100622 if (link_info->imsi > 0) {
623 if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)
624 || mi.type != GSM_MI_TYPE_IMSI)
625 imsi_str = "(invalid)";
626 else
627 imsi_str = mi.imsi;
628 } else {
629 imsi_str = "(none)";
630 }
631 vty_out(vty, " TLLI %08x, IMSI %s, AGE %d",
632 link_info->tlli.current, imsi_str, (int)age);
633
634 if (link_info->stored_msgs_len)
635 vty_out(vty, ", STORED %"PRIu32"/%"PRIu32,
636 link_info->stored_msgs_len,
637 g_cfg->stored_msgs_max_len);
638
639 if (g_cfg->route_to_sgsn2)
640 vty_out(vty, ", SGSN NSEI %d",
641 link_info->sgsn_nsei);
642
643 if (link_info->is_deregistered)
644 vty_out(vty, ", DE-REGISTERED");
645
646 vty_out(vty, "%s", VTY_NEWLINE);
Jacob Erlbeck89d3d342014-08-06 18:55:15 +0200647 }
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200648 }
649 }
650 return CMD_SUCCESS;
651}
652
653DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
654 "delete-gbproxy-peer <0-65534> bvci <2-65534>",
655 "Delete a GBProxy peer by NSEI and optionally BVCI\n"
656 "NSEI number\n"
657 "Only delete peer with a matching BVCI\n"
658 "BVCI number\n")
659{
660 const uint16_t nsei = atoi(argv[0]);
661 const uint16_t bvci = atoi(argv[1]);
662 int counter;
663
Jacob Erlbeck5f1faa32014-08-21 10:01:30 +0200664 counter = gbproxy_cleanup_peers(g_cfg, nsei, bvci);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200665
666 if (counter == 0) {
667 vty_out(vty, "BVC not found%s", VTY_NEWLINE);
668 return CMD_WARNING;
669 }
670
671 return CMD_SUCCESS;
672}
673
674DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
675 "delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
676 "Delete a GBProxy peer by NSEI and optionally BVCI\n"
677 "NSEI number\n"
678 "Only delete BSSGP connections (BVC)\n"
679 "Only delete dynamic NS connections (NS-VC)\n"
680 "Delete BVC and dynamic NS connections\n"
681 "Show what would be deleted instead of actually deleting\n"
682 )
683{
684 const uint16_t nsei = atoi(argv[0]);
685 const char *mode = argv[1];
686 int dry_run = argc > 2;
687 int delete_bvc = 0;
688 int delete_nsvc = 0;
689 int counter;
690
691 if (strcmp(mode, "only-bvc") == 0)
692 delete_bvc = 1;
693 else if (strcmp(mode, "only-nsvc") == 0)
694 delete_nsvc = 1;
695 else
696 delete_bvc = delete_nsvc = 1;
697
698 if (delete_bvc) {
Daniel Willmann9a2fc902020-12-04 17:43:27 +0100699 if (!dry_run) {
700 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei);
Jacob Erlbeck5f1faa32014-08-21 10:01:30 +0200701 counter = gbproxy_cleanup_peers(g_cfg, nsei, 0);
Daniel Willmann9a2fc902020-12-04 17:43:27 +0100702 gbproxy_nse_free(nse);
703 } else {
Daniel Willmann447ad442020-11-26 18:19:21 +0100704 struct gbproxy_nse *nse;
Holger Hans Peter Freyther1ddd9e52014-08-04 11:35:32 +0200705 struct gbproxy_peer *peer;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200706 counter = 0;
Daniel Willmann447ad442020-11-26 18:19:21 +0100707 llist_for_each_entry(nse, &g_cfg->nse_peers, list) {
708 if (nse->nsei != nsei)
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200709 continue;
Daniel Willmann447ad442020-11-26 18:19:21 +0100710 llist_for_each_entry(peer, &nse->bts_peers, list) {
711 vty_out(vty, "BVC: ");
712 gbprox_vty_print_peer(vty, peer);
713 counter += 1;
714 }
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200715 }
716 }
717 vty_out(vty, "%sDeleted %d BVC%s",
718 dry_run ? "Not " : "", counter, VTY_NEWLINE);
719 }
720
721 if (delete_nsvc) {
Alexander Couzens82182d02020-09-22 13:21:46 +0200722 struct gprs_ns2_inst *nsi = g_cfg->nsi;
723 struct gprs_ns2_nse *nse;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200724
Alexander Couzens82182d02020-09-22 13:21:46 +0200725 nse = gprs_ns2_nse_by_nsei(nsi, nsei);
726 if (!nse) {
727 vty_out(vty, "NSEI not found%s", VTY_NEWLINE);
728 return CMD_WARNING;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200729 }
Alexander Couzens82182d02020-09-22 13:21:46 +0200730
731 /* TODO: We should NOT delete a persistent NSEI/NSVC as soon as we can check for these */
732 if (!dry_run)
733 gprs_ns2_free_nse(nse);
734
735 vty_out(vty, "%sDeleted NS-VCs for NSEI %d%s",
736 dry_run ? "Not " : "", nsei, VTY_NEWLINE);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200737 }
738
739 return CMD_SUCCESS;
740}
741
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200742#define GBPROXY_DELETE_LINK_STR \
743 "Delete a GBProxy logical link entry by NSEI and identification\nNSEI number\n"
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200744
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200745DEFUN(delete_gb_link_by_id, delete_gb_link_by_id_cmd,
746 "delete-gbproxy-link <0-65534> (tlli|imsi|sgsn-nsei) IDENT",
747 GBPROXY_DELETE_LINK_STR
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200748 "Delete entries with a matching TLLI (hex)\n"
749 "Delete entries with a matching IMSI\n"
Jacob Erlbeckde74e722014-10-28 11:29:43 +0100750 "Delete entries with a matching SGSN NSEI\n"
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200751 "Identification to match\n")
752{
753 const uint16_t nsei = atoi(argv[0]);
Jacob Erlbeck91a0e862014-09-17 10:56:38 +0200754 enum {MATCH_TLLI = 't', MATCH_IMSI = 'i', MATCH_SGSN = 's'} match;
755 uint32_t ident = 0;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200756 const char *imsi = NULL;
Holger Hans Peter Freyther1ddd9e52014-08-04 11:35:32 +0200757 struct gbproxy_peer *peer = 0;
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200758 struct gbproxy_link_info *link_info, *nxt;
Holger Hans Peter Freyther1ddd9e52014-08-04 11:35:32 +0200759 struct gbproxy_patch_state *state;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200760 int found = 0;
761
762 match = argv[1][0];
763
Jacob Erlbeck91a0e862014-09-17 10:56:38 +0200764 switch (match) {
765 case MATCH_TLLI: ident = strtoll(argv[2], NULL, 16); break;
766 case MATCH_IMSI: imsi = argv[2]; break;
767 case MATCH_SGSN: ident = strtoll(argv[2], NULL, 0); break;
768 };
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200769
770 peer = gbproxy_peer_by_nsei(g_cfg, nsei);
771 if (!peer) {
772 vty_out(vty, "Didn't find peer with NSEI %d%s",
773 nsei, VTY_NEWLINE);
774 return CMD_WARNING;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200775 }
776
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200777 state = &peer->patch_state;
778
Jacob Erlbeckf8562e32014-09-19 16:03:07 +0200779 llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list) {
Neels Hofmeyrb26a5a82020-05-29 16:53:23 +0200780 struct osmo_mobile_identity mi;
781
Jacob Erlbeck91a0e862014-09-17 10:56:38 +0200782 switch (match) {
783 case MATCH_TLLI:
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200784 if (link_info->tlli.current != ident)
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200785 continue;
Jacob Erlbeck91a0e862014-09-17 10:56:38 +0200786 break;
787 case MATCH_SGSN:
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200788 if (link_info->sgsn_nsei != ident)
Jacob Erlbeck91a0e862014-09-17 10:56:38 +0200789 continue;
790 break;
791 case MATCH_IMSI:
Jacob Erlbeck6a1d4282014-10-20 17:22:36 +0200792 if (!link_info->imsi)
793 continue;
Neels Hofmeyrb26a5a82020-05-29 16:53:23 +0200794 if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)
795 || mi.type != GSM_MI_TYPE_IMSI)
796 continue;
797 if (strcmp(mi.imsi, imsi) != 0)
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200798 continue;
Jacob Erlbeck91a0e862014-09-17 10:56:38 +0200799 break;
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200800 }
801
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200802 vty_out(vty, "Deleting link with TLLI %08x%s", link_info->tlli.current,
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200803 VTY_NEWLINE);
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200804 gbproxy_delete_link_info(peer, link_info);
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200805 found += 1;
806 }
807
808 if (!found && argc >= 2) {
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200809 vty_out(vty, "Didn't find link entry with %s %s%s",
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200810 argv[1], argv[2], VTY_NEWLINE);
811 }
812
813 return CMD_SUCCESS;
814}
815
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200816DEFUN(delete_gb_link, delete_gb_link_cmd,
817 "delete-gbproxy-link <0-65534> (stale|de-registered)",
818 GBPROXY_DELETE_LINK_STR
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200819 "Delete stale entries\n"
820 "Delete de-registered entries\n")
821{
822 const uint16_t nsei = atoi(argv[0]);
823 enum {MATCH_STALE = 's', MATCH_DEREGISTERED = 'd'} match;
824 struct gbproxy_peer *peer = 0;
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200825 struct gbproxy_link_info *link_info, *nxt;
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200826 struct gbproxy_patch_state *state;
Jacob Erlbeckc6807c42014-09-19 16:34:01 +0200827 time_t now;
828 struct timespec ts = {0,};
829
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200830 int found = 0;
831
832 match = argv[1][0];
833
Jacob Erlbeck5f1faa32014-08-21 10:01:30 +0200834 peer = gbproxy_peer_by_nsei(g_cfg, nsei);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200835 if (!peer) {
836 vty_out(vty, "Didn't find peer with NSEI %d%s",
837 nsei, VTY_NEWLINE);
838 return CMD_WARNING;
839 }
840
841 state = &peer->patch_state;
842
Pau Espin Pedrol36abead2018-08-17 13:27:20 +0200843 osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
Jacob Erlbeckc6807c42014-09-19 16:34:01 +0200844 now = ts.tv_sec;
845
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200846 if (match == MATCH_STALE) {
Jacob Erlbeckc6807c42014-09-19 16:34:01 +0200847 found = gbproxy_remove_stale_link_infos(peer, now);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200848 if (found)
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200849 vty_out(vty, "Deleted %d stale logical link%s%s",
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200850 found, found == 1 ? "" : "s", VTY_NEWLINE);
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200851 } else {
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200852 llist_for_each_entry_safe(link_info, nxt,
Jacob Erlbeckf8562e32014-09-19 16:03:07 +0200853 &state->logical_links, list) {
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200854 if (!link_info->is_deregistered)
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200855 continue;
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200856
Jacob Erlbeck91d2f8a2014-09-19 15:07:27 +0200857 gbproxy_delete_link_info(peer, link_info);
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200858 found += 1;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200859 }
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200860 }
861
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200862 if (found)
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200863 vty_out(vty, "Deleted %d %s logical link%s%s",
Jacob Erlbeckcdd37832014-09-16 08:56:26 +0200864 found, argv[1], found == 1 ? "" : "s", VTY_NEWLINE);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200865
866 return CMD_SUCCESS;
867}
Jacob Erlbeck67a44452014-05-19 10:14:58 +0200868
Holger Hans Peter Freyther925504b2015-09-24 10:21:40 +0200869/*
870 * legacy commands to provide an upgrade path from "broken" releases
871 * or pre-releases
872 */
873DEFUN_DEPRECATED(cfg_gbproxy_broken_apn_match,
874 cfg_gbproxy_broken_apn_match_cmd,
875 "core-access-point-name none match-imsi .REGEXP",
876 GBPROXY_CORE_APN_STR GBPROXY_MATCH_IMSI_STR "Remove APN\n"
877 "Patch MS related information elements on match only\n"
878 "Route to the secondary SGSN on match only\n"
879 "Regular expression for the IMSI match\n")
880{
881 const char *filter = argv[0];
882 const char *err_msg = NULL;
883 struct gbproxy_match *match;
884 enum gbproxy_match_id match_id = get_string_value(match_ids, "patching");
885
886 /* apply APN none */
887 set_core_apn(vty, "");
888
889 /* do the matching... with copy and paste */
890 OSMO_ASSERT(match_id >= GBPROX_MATCH_PATCHING &&
891 match_id < GBPROX_MATCH_LAST);
892 match = &g_cfg->matches[match_id];
893
894 if (gbproxy_set_patch_filter(match, filter, &err_msg) != 0) {
895 vty_out(vty, "Match expression invalid: %s%s",
896 err_msg, VTY_NEWLINE);
897 return CMD_WARNING;
898 }
899
Harald Welteaed46ec2019-03-22 09:44:42 +0100900 g_cfg->acquire_imsi = true;
Holger Hans Peter Freyther925504b2015-09-24 10:21:40 +0200901
902 return CMD_SUCCESS;
903}
904
905#define GBPROXY_TLLI_LIST_STR "Set TLLI list parameters\n"
906#define GBPROXY_MAX_LEN_STR "Limit list length\n"
907DEFUN_DEPRECATED(cfg_gbproxy_depr_tlli_list_max_len,
908 cfg_gbproxy_depr_tlli_list_max_len_cmd,
909 "tlli-list max-length <1-99999>",
910 GBPROXY_TLLI_LIST_STR GBPROXY_MAX_LEN_STR
911 "Maximum number of TLLIs in the list\n")
912{
913 g_cfg->tlli_max_len = atoi(argv[0]);
914
915 return CMD_SUCCESS;
916}
917
Harald Welte799e0c92010-04-30 21:49:24 +0200918int gbproxy_vty_init(void)
919{
Harald Welte995a2d32010-05-12 16:50:52 +0000920 install_element_ve(&show_gbproxy_cmd);
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200921 install_element_ve(&show_gbproxy_links_cmd);
Daniel Willmanne8c8ec92020-12-02 19:33:50 +0100922 install_element_ve(&logging_fltr_bvc_cmd);
Harald Welte799e0c92010-04-30 21:49:24 +0200923
Jacob Erlbeck4211d792013-10-24 12:48:23 +0200924 install_element(ENABLE_NODE, &delete_gb_bvci_cmd);
925 install_element(ENABLE_NODE, &delete_gb_nsei_cmd);
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200926 install_element(ENABLE_NODE, &delete_gb_link_by_id_cmd);
927 install_element(ENABLE_NODE, &delete_gb_link_cmd);
Holger Hans Peter Freyther90267a92013-10-23 11:24:17 +0200928
Harald Welte799e0c92010-04-30 21:49:24 +0200929 install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
930 install_node(&gbproxy_node, config_write_gbproxy);
Harald Welte799e0c92010-04-30 21:49:24 +0200931 install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd);
Jacob Erlbeck67a44452014-05-19 10:14:58 +0200932 install_element(GBPROXY_NODE, &cfg_gbproxy_core_mcc_cmd);
933 install_element(GBPROXY_NODE, &cfg_gbproxy_core_mnc_cmd);
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200934 install_element(GBPROXY_NODE, &cfg_gbproxy_match_imsi_cmd);
Jacob Erlbeck73685282014-05-23 20:48:07 +0200935 install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_cmd);
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200936 install_element(GBPROXY_NODE, &cfg_gbproxy_secondary_sgsn_cmd);
Jacob Erlbeck0d4236b2014-08-18 14:54:37 +0200937 install_element(GBPROXY_NODE, &cfg_gbproxy_patch_ptmsi_cmd);
Jacob Erlbeck5f4ef322014-08-22 17:10:01 +0200938 install_element(GBPROXY_NODE, &cfg_gbproxy_acquire_imsi_cmd);
Pau Espin Pedrol82f13612018-08-17 13:13:27 +0200939 install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_clean_stale_timer_cmd);
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200940 install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_max_age_cmd);
941 install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_max_len_cmd);
942 install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_keep_mode_cmd);
Pau Espin Pedrol67f1d1e2018-08-16 12:11:46 +0200943 install_element(GBPROXY_NODE, &cfg_gbproxy_link_stored_msgs_max_len_cmd);
Jacob Erlbeck67a44452014-05-19 10:14:58 +0200944 install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mcc_cmd);
945 install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mnc_cmd);
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200946 install_element(GBPROXY_NODE, &cfg_gbproxy_no_match_imsi_cmd);
Jacob Erlbeck73685282014-05-23 20:48:07 +0200947 install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_apn_cmd);
Jacob Erlbeckcd9e1c92014-09-02 13:57:19 +0200948 install_element(GBPROXY_NODE, &cfg_gbproxy_no_secondary_sgsn_cmd);
Jacob Erlbeck0d4236b2014-08-18 14:54:37 +0200949 install_element(GBPROXY_NODE, &cfg_gbproxy_no_patch_ptmsi_cmd);
Jacob Erlbeck5f4ef322014-08-22 17:10:01 +0200950 install_element(GBPROXY_NODE, &cfg_gbproxy_no_acquire_imsi_cmd);
Pau Espin Pedrol82f13612018-08-17 13:13:27 +0200951 install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_clean_stale_timer_cmd);
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200952 install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_max_age_cmd);
953 install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_max_len_cmd);
Pau Espin Pedrol67f1d1e2018-08-16 12:11:46 +0200954 install_element(GBPROXY_NODE, &cfg_gbproxy_link_no_stored_msgs_max_len_cmd);
Harald Welte799e0c92010-04-30 21:49:24 +0200955
Holger Hans Peter Freyther925504b2015-09-24 10:21:40 +0200956 /* broken or deprecated to allow an upgrade path */
957 install_element(GBPROXY_NODE, &cfg_gbproxy_broken_apn_match_cmd);
958 install_element(GBPROXY_NODE, &cfg_gbproxy_depr_tlli_list_max_len_cmd);
959
Harald Welte799e0c92010-04-30 21:49:24 +0200960 return 0;
961}
962
963int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg)
964{
965 int rc;
966
967 g_cfg = cfg;
Harald Weltedcccb182010-05-16 20:52:23 +0200968 rc = vty_read_config_file(config_file, NULL);
Harald Welte799e0c92010-04-30 21:49:24 +0200969 if (rc < 0) {
970 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
971 return rc;
972 }
973
974 return 0;
975}