blob: 6327d1a3d2ddd468da5c21c81ce8c09c46c9ab54 [file] [log] [blame]
Harald Welte288be162010-05-01 16:48:27 +02001/*
Harald Welte89837d42016-05-06 23:28:11 +02002 * (C) 2010-2016 by Harald Welte <laforge@gnumonks.org>
Harald Welte288be162010-05-01 16:48:27 +02003 * (C) 2010 by On-Waves
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02004 * (C) 2015 by Holger Hans Peter Freyther
Harald Welte288be162010-05-01 16:48:27 +02005 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01008 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
Harald Welte288be162010-05-01 16:48:27 +020010 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010015 * GNU Affero General Public License for more details.
Harald Welte288be162010-05-01 16:48:27 +020016 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte288be162010-05-01 16:48:27 +020019 *
20 */
21
Harald Welte288be162010-05-01 16:48:27 +020022#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +010025#include <time.h>
Pau Espin Pedrolfa120102018-07-09 20:37:47 +020026#include <inttypes.h>
Harald Welte288be162010-05-01 16:48:27 +020027
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010028#include <osmocom/core/talloc.h>
29#include <osmocom/core/utils.h>
30#include <osmocom/core/rate_ctr.h>
Pau Espin Pedrola299d652019-08-14 19:11:10 +020031#include <osmocom/core/tdef.h>
Harald Welte53373bc2016-04-20 17:11:43 +020032#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
Harald Welte7e82b742017-08-12 13:43:54 +020033#include <osmocom/gsm/apn.h>
Harald Welte288be162010-05-01 16:48:27 +020034
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020035#include <osmocom/sgsn/debug.h>
36#include <osmocom/sgsn/sgsn.h>
Alexander Couzensf23e2db2020-07-27 22:39:58 +020037#include <osmocom/gprs/gprs_ns2.h>
Oliver Smithab39b622021-07-05 15:41:05 +020038#include <osmocom/sgsn/gprs_gb.h>
Alexander Couzensc503f0a2018-08-07 17:50:04 +020039#include <osmocom/sgsn/gprs_gmm.h>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020040#include <osmocom/sgsn/gprs_sgsn.h>
Pau Espin Pedrole5c89982021-05-03 18:16:42 +020041#include <osmocom/sgsn/gtp_mme.h>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020042#include <osmocom/sgsn/vty.h>
Harald Weltef4b2c4c2018-09-16 07:53:41 +020043#include <osmocom/gsupclient/gsup_client.h>
Harald Welte288be162010-05-01 16:48:27 +020044
Pau Espin Pedrola299d652019-08-14 19:11:10 +020045#include <osmocom/vty/tdef_vty.h>
Harald Welte4b037e42010-05-19 19:45:32 +020046#include <osmocom/vty/command.h>
47#include <osmocom/vty/vty.h>
Pablo Neira Ayuso6110a3f2011-03-28 19:35:00 +020048#include <osmocom/vty/misc.h>
Max93408ae2016-06-28 14:10:16 +020049#include <osmocom/crypt/gprs_cipher.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010050#include <osmocom/abis/ipa.h>
51
Alexander Couzensc503f0a2018-08-07 17:50:04 +020052#include <osmocom/gprs/gprs_bssgp.h>
53
Harald Welted193cb32010-05-17 22:58:03 +020054#include <pdp.h>
Maxbaabc682017-10-20 13:39:57 +020055#include <gtp.h>
Harald Welted193cb32010-05-17 22:58:03 +020056
Neels Hofmeyr2188a772016-05-20 21:59:55 +020057#include "../../bscconfig.h"
58
59#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +020060#include <osmocom/ranap/iu_client.h>
Neels Hofmeyr2188a772016-05-20 21:59:55 +020061#endif
62
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +010063extern void *tall_sgsn_ctx;
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020064
Harald Welte288be162010-05-01 16:48:27 +020065static struct sgsn_config *g_cfg = NULL;
66
Jacob Erlbeck106f5472014-11-04 10:08:37 +010067const struct value_string sgsn_auth_pol_strs[] = {
68 { SGSN_AUTH_POLICY_OPEN, "accept-all" },
69 { SGSN_AUTH_POLICY_CLOSED, "closed" },
70 { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" },
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +010071 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeck106f5472014-11-04 10:08:37 +010072 { 0, NULL }
73};
74
Harald Welte94508822015-08-15 19:08:21 +020075/* Section 11.2.2 / Table 11.3a GPRS Mobility management timers – MS side */
76#define GSM0408_T3312_SECS (10*60) /* periodic RAU interval, default 54min */
77
78/* Section 11.2.2 / Table 11.4 MM timers netwokr side */
79#define GSM0408_T3322_SECS 6 /* DETACH_REQ -> DETACH_ACC */
80#define GSM0408_T3350_SECS 6 /* waiting for ATT/RAU/TMSI COMPL */
81#define GSM0408_T3360_SECS 6 /* waiting for AUTH/CIPH RESP */
82#define GSM0408_T3370_SECS 6 /* waiting for ID RESP */
83
Alexander Couzens5ba6fb32017-01-31 18:04:27 +010084/* Section 11.2.2 / Table 11.4a MM timers network side */
Harald Welte94508822015-08-15 19:08:21 +020085#define GSM0408_T3313_SECS 30 /* waiting for paging response */
86#define GSM0408_T3314_SECS 44 /* force to STBY on expiry, Ready timer */
87#define GSM0408_T3316_SECS 44
88
89/* Section 11.3 / Table 11.2d Timers of Session Management - network side */
90#define GSM0408_T3385_SECS 8 /* wait for ACT PDP CTX REQ */
91#define GSM0408_T3386_SECS 8 /* wait for MODIFY PDP CTX ACK */
92#define GSM0408_T3395_SECS 8 /* wait for DEACT PDP CTX ACK */
93#define GSM0408_T3397_SECS 8 /* wait for DEACT AA PDP CTX ACK */
94
Alexander Couzensafadd102019-10-08 14:30:59 +020095/* Non spec timer */
96#define NONSPEC_X1001_SECS 5 /* wait for a RANAP Release Complete */
97
Pau Espin Pedrola299d652019-08-14 19:11:10 +020098
99static struct osmo_tdef sgsn_T_defs[] = {
100 { .T=3312, .default_val=GSM0408_T3312_SECS, .desc="Periodic RA Update timer (s)" },
101 { .T=3313, .default_val=GSM0408_T3313_SECS, .desc="Waiting for paging response timer (s)" },
Alexander Couzens39cbecd2017-02-03 22:16:05 +0100102 { .T=3314, .default_val=GSM0408_T3314_SECS, .desc="READY timer. Force to STANDBY on expiry timer (s)" },
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200103 { .T=3316, .default_val=GSM0408_T3316_SECS, .desc="AA-Ready timer (s)" },
104 { .T=3322, .default_val=GSM0408_T3322_SECS, .desc="Detach request -> accept timer (s)" },
105 { .T=3350, .default_val=GSM0408_T3350_SECS, .desc="Waiting for ATT/RAU/TMSI_COMPL timer (s)" },
106 { .T=3360, .default_val=GSM0408_T3360_SECS, .desc="Waiting for AUTH/CIPH response timer (s)" },
107 { .T=3370, .default_val=GSM0408_T3370_SECS, .desc="Waiting for IDENTITY response timer (s)" },
108 { .T=3385, .default_val=GSM0408_T3385_SECS, .desc="Wait for ACT PDP CTX REQ timer (s)" },
109 { .T=3386, .default_val=GSM0408_T3386_SECS, .desc="Wait for MODIFY PDP CTX ACK timer (s)" },
110 { .T=3395, .default_val=GSM0408_T3395_SECS, .desc="Wait for DEACT PDP CTX ACK timer (s)" },
111 { .T=3397, .default_val=GSM0408_T3397_SECS, .desc="Wait for DEACT AA PDP CTX ACK timer (s)" },
Alexander Couzens3bad31b2019-09-11 02:17:31 +0200112 /* non spec timers */
Alexander Couzensafadd102019-10-08 14:30:59 +0200113 { .T=-1001, .default_val=NONSPEC_X1001_SECS, .desc="RANAP Release timeout. Wait for RANAP Release Complete."
114 "On expiry release Iu connection (s)" },
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200115 {}
116};
117
118DEFUN(show_timer, show_timer_cmd,
119 "show timer " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
120 SHOW_STR "Show timers\n"
121 OSMO_TDEF_VTY_DOC_T)
122{
123 const char *T_arg = argc > 0 ? argv[0] : NULL;
124 return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs, T_arg, NULL);
Harald Welte94508822015-08-15 19:08:21 +0200125}
126
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200127DEFUN(cfg_sgsn_timer, cfg_sgsn_timer_cmd,
128 "timer " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
129 "Configure or show timers\n"
130 OSMO_TDEF_VTY_DOC_SET)
131{
132 /* If any arguments are missing, redirect to 'show' */
133 if (argc < 2)
134 return show_timer(self, vty, argc, argv);
135 return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs, argv);
136}
Harald Welte94508822015-08-15 19:08:21 +0200137
Keith6cee1a12021-09-29 21:00:04 +0200138char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6)
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200139{
140 static char str[INET6_ADDRSTRLEN + 10];
141
142 if (!pdpa || len < 2)
143 return "none";
144
145 switch (pdpa[0] & 0x0f) {
146 case PDP_TYPE_ORG_IETF:
147 switch (pdpa[1]) {
148 case PDP_TYPE_N_IETF_IPv4:
149 if (len < 2 + 4)
150 break;
Keith6cee1a12021-09-29 21:00:04 +0200151 osmo_strlcpy(str, "IPv4 ", sizeof(str));
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200152 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
153 return str;
154 case PDP_TYPE_N_IETF_IPv6:
155 if (len < 2 + 8)
156 break;
Keith6cee1a12021-09-29 21:00:04 +0200157 osmo_strlcpy(str, "IPv6 ", sizeof(str));
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200158 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
159 return str;
Keith6cee1a12021-09-29 21:00:04 +0200160 case PDP_TYPE_N_IETF_IPv4v6:
161 if (len < 2 + 20)
162 break;
163 if (return_ipv6) {
164 /* The IPv6 token, (rightmost four fields) is a duplicate of
165 * the site prefix + subnetID (leftmost fields) in pdpa here */
166 osmo_strlcpy(str, "IPv6 ", sizeof(str));
167 inet_ntop(AF_INET6, pdpa+6, str+5, sizeof(str)-5);
168 return str;
169 }
170 osmo_strlcpy(str, "IPv4 ", sizeof(str));
171 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
172 return str;
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200173 default:
174 break;
175 }
176 break;
177 case PDP_TYPE_ORG_ETSI:
178 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
179 return "PPP";
180 break;
181 default:
182 break;
183 }
184
185 return "invalid";
186}
187
Harald Welte288be162010-05-01 16:48:27 +0200188static struct cmd_node sgsn_node = {
189 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200190 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200191 1,
192};
193
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200194static struct cmd_node mme_node = {
195 MME_NODE,
196 "%s(config-sgsn-mme)# ",
197 1,
198};
199
200static void config_write_mme(struct vty *vty, const struct sgsn_mme_ctx *mme, const char *prefix)
201{
202 struct mme_rim_route *rt;
203
204 vty_out(vty, "%smme %s%s", prefix, mme->name, VTY_NEWLINE);
205
206 vty_out(vty, "%s gtp remote-ip %s%s", prefix, inet_ntoa(mme->remote_addr), VTY_NEWLINE);
207 if (mme->default_route)
208 vty_out(vty, "%s gtp ran-info-relay default%s", prefix, VTY_NEWLINE);
209 llist_for_each_entry(rt, &mme->routes, list) {
210 vty_out(vty, "%s gtp ran-info-relay %s %s %u%s", prefix,
211 osmo_mcc_name(rt->tai.mcc), osmo_mnc_name(rt->tai.mnc, rt->tai.mnc_3_digits),
212 rt->tai.tac, VTY_NEWLINE);
213 }
214}
215
Harald Welte288be162010-05-01 16:48:27 +0200216static int config_write_sgsn(struct vty *vty)
217{
Harald Welte77289c22010-05-18 14:32:29 +0200218 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100219 struct imsi_acl_entry *acl;
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100220 struct apn_ctx *actx;
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800221 struct ares_addr_node *server;
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200222 struct sgsn_mme_ctx *mme;
Eric2f898262021-05-19 18:57:50 +0200223 int i;
Harald Welte288be162010-05-01 16:48:27 +0200224
225 vty_out(vty, "sgsn%s", VTY_NEWLINE);
226
Keithc70e8382020-10-19 22:24:48 +0200227 vty_out(vty, " gtp state-dir %s%s",
228 g_cfg->gtp_statedir, VTY_NEWLINE);
Harald Weltee300d002010-06-02 12:41:34 +0200229 vty_out(vty, " gtp local-ip %s%s",
230 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
231
Harald Welted193cb32010-05-17 22:58:03 +0200232 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800233 if (gctx->id == UINT32_MAX)
234 continue;
235
Harald Welteff3bde82010-05-19 15:09:09 +0200236 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200237 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200238 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200239 gctx->gtp_version, VTY_NEWLINE);
Pau Espin Pedrolaa89f5d2019-08-28 16:08:45 +0200240 if (gctx->echo_interval)
241 vty_out(vty, " ggsn %u echo-interval %u%s",
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200242 gctx->id, gctx->echo_interval, VTY_NEWLINE);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200243 else
244 vty_out(vty, " ggsn %u no echo-interval%s",
245 gctx->id, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200246 }
247
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800248 if (sgsn->cfg.dynamic_lookup)
249 vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE);
250
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800251 for (server = sgsn->ares_servers; server; server = server->next)
252 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
253
Eric2f898262021-05-19 18:57:50 +0200254 if (g_cfg->cipher_support_mask != 0) {
255 vty_out(vty, " encryption gea");
256
257 for (i = 0; i < _GPRS_ALGO_NUM; i++)
258 if (g_cfg->cipher_support_mask >> i & 1)
259 vty_out(vty, " %u", i);
260
261 vty_out(vty, "%s", VTY_NEWLINE);
262 }
Stefan Sperling88220092018-12-11 14:42:00 +0100263 if (g_cfg->sgsn_ipa_name)
264 vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100265 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
266 vty_out(vty, " gsup remote-ip %s%s",
267 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
268 if (g_cfg->gsup_server_port)
269 vty_out(vty, " gsup remote-port %d%s",
270 g_cfg->gsup_server_port, VTY_NEWLINE);
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200271 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE && !g_cfg->require_authentication)
272 vty_out(vty, " authentication optional%s", VTY_NEWLINE);
Max176b62a2016-07-04 11:09:07 +0200273 vty_out(vty, " auth-policy %s%s",
274 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
275 VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200276
277 vty_out(vty, " gsup oap-id %d%s",
278 (int)g_cfg->oap.client_id, VTY_NEWLINE);
279 if (g_cfg->oap.secret_k_present != 0)
280 vty_out(vty, " gsup oap-k %s%s",
281 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
282 VTY_NEWLINE);
283 if (g_cfg->oap.secret_opc_present != 0)
284 vty_out(vty, " gsup oap-opc %s%s",
285 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
286 VTY_NEWLINE);
287
Harald Welte7f6da482013-03-19 11:00:13 +0100288 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
289 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
290
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100291 if (llist_empty(&sgsn_apn_ctxts))
292 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
293 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
294 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200295 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100296 actx->name, actx->imsi_prefix, actx->ggsn->id,
297 VTY_NEWLINE);
298 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200299 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100300 actx->ggsn->id, VTY_NEWLINE);
301 }
302
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200303 if (g_cfg->cdr.filename)
304 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
305 else
306 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +0100307 if (g_cfg->cdr.trap)
308 vty_out(vty, " cdr trap%s", VTY_NEWLINE);
309 else
310 vty_out(vty, " no cdr trap%s", VTY_NEWLINE);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200311 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
312
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200313 osmo_tdef_vty_write(vty, g_cfg->T_defs, " timer ");
Harald Welte94508822015-08-15 19:08:21 +0200314
Philippf1f34362016-08-26 17:00:21 +0200315 if (g_cfg->pcomp_rfc1144.active) {
316 vty_out(vty, " compression rfc1144 active slots %d%s",
317 g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE);
318 } else if (g_cfg->pcomp_rfc1144.passive) {
319 vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE);
320 } else
321 vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE);
322
Philipp73f83d52016-09-02 13:38:01 +0200323 if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) {
324 vty_out(vty,
325 " compression v42bis active direction sgsn codewords %d strlen %d%s",
326 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
327 VTY_NEWLINE);
328 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) {
329 vty_out(vty,
330 " compression v42bis active direction ms codewords %d strlen %d%s",
331 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
332 VTY_NEWLINE);
333 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) {
334 vty_out(vty,
335 " compression v42bis active direction both codewords %d strlen %d%s",
336 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
337 VTY_NEWLINE);
338 } else if (g_cfg->dcomp_v42bis.passive) {
339 vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE);
340 } else
341 vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
342
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200343 llist_for_each_entry(mme, &sgsn->mme_list, list) {
344 config_write_mme(vty, mme, " ");
345 }
346
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200347#ifdef BUILD_IU
Pau Espin Pedrol2c908992019-08-19 19:06:06 +0200348 vty_out(vty, " cs7-instance-iu %u%s", g_cfg->iu.cs7_instance,
349 VTY_NEWLINE);
Neels Hofmeyra7a39472017-07-05 15:19:52 +0200350 ranap_iu_vty_config_write(vty, " ");
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200351#endif
352
Harald Welte288be162010-05-01 16:48:27 +0200353 return CMD_SUCCESS;
354}
355
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100356#define SGSN_STR "Configure the SGSN\n"
357#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200358
359DEFUN(cfg_sgsn, cfg_sgsn_cmd,
360 "sgsn",
361 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200362{
363 vty->node = SGSN_NODE;
364 return CMD_SUCCESS;
365}
366
Keithc70e8382020-10-19 22:24:48 +0200367DEFUN(cfg_sgsn_state_dir, cfg_sgsn_state_dir_cmd,
368 "gtp state-dir PATH",
369 "GTP Parameters\n"
370 "Set the directory for the GTP State file\n"
371 "Local Directory\n")
372{
373 osmo_talloc_replace_string(sgsn, &sgsn->cfg.gtp_statedir, argv[0]);
374
375 return CMD_SUCCESS;
376}
377
Harald Weltee300d002010-06-02 12:41:34 +0200378DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
379 "gtp local-ip A.B.C.D",
380 "GTP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100381 "Set the IP address for the local GTP bind for the Gp interface (towards the GGSNs)."
382 " Note: in case you would like to run the GGSN on the same machine as the SGSN, you can not run"
383 " both on the same IP address, since both sides are specified to use the same GTP port numbers"
384 " (" OSMO_STRINGIFY_VAL(GTP1C_PORT) " and " OSMO_STRINGIFY_VAL(GTP1U_PORT) ")."
385 " For example, you could use 127.0.0.1 for the SGSN and 127.0.0.2 for the GGSN in such"
386 " situations.\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100387 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200388{
389 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
390
391 return CMD_SUCCESS;
392}
393
Harald Welted193cb32010-05-17 22:58:03 +0200394DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
395 "ggsn <0-255> remote-ip A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100396 GGSN_STR "GGSN Number\n"
397 "Configure this static GGSN to use the specified remote IP address.\n"
398 "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200399{
400 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200401 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200402
Harald Welted193cb32010-05-17 22:58:03 +0200403 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200404
Harald Welted193cb32010-05-17 22:58:03 +0200405 return CMD_SUCCESS;
406}
407
408#if 0
409DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
410 "ggsn <0-255> remote-port <0-65535>",
411 "")
412{
413 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200414 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200415 uint16_t port = atoi(argv[1]);
416
417}
418#endif
419
420DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
421 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100422 GGSN_STR "GGSN Number\n" "GTP Version\n"
423 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200424{
425 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200426 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200427
428 if (atoi(argv[1]))
429 ggc->gtp_version = 1;
430 else
431 ggc->gtp_version = 0;
432
433 return CMD_SUCCESS;
434}
435
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200436/* Seee 3GPP TS 29.060 section 7.2.1 */
437DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
438 "ggsn <0-255> echo-interval <1-36000>",
439 GGSN_STR "GGSN Number\n"
440 "Send an echo request to this static GGSN every interval.\n"
441 "Interval between echo requests in seconds.\n")
442{
443 uint32_t id = atoi(argv[0]);
444 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
445
446 ggc->echo_interval = atoi(argv[1]);
447
448 if (ggc->echo_interval < 60)
Pau Espin Pedrolba2e5002019-05-27 17:35:32 +0200449 vty_out(vty, "%% 3GPP TS 29.060 section 7.2.1 states interval should " \
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200450 "not be lower than 60 seconds, use this value for " \
451 "testing purposes only!%s", VTY_NEWLINE);
452
Alexander Couzens176a4d22018-09-18 20:07:37 +0200453 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200454 return CMD_SUCCESS;
455}
456
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200457DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
458 "ggsn <0-255> no echo-interval",
459 GGSN_STR "GGSN Number\n"
460 NO_STR "Send an echo request to this static GGSN every interval.\n")
461{
462 uint32_t id = atoi(argv[0]);
463 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
464
Pau Espin Pedrolaa89f5d2019-08-28 16:08:45 +0200465 ggc->echo_interval = 0;
Alexander Couzens176a4d22018-09-18 20:07:37 +0200466 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200467
468 return CMD_SUCCESS;
469}
470
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800471DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
472 "ggsn dynamic",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100473 GGSN_STR
474 "Enable dynamic resolving of GGSNs based on DNS resolving the APN name like in a GRX-style setup."
475 " Changing this setting requires a restart.\n")
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800476{
477 sgsn->cfg.dynamic_lookup = 1;
478 return CMD_SUCCESS;
479}
480
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800481DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
482 "grx-dns-add A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100483 "Use the specified IP address for DNS-resolving the AP names to GGSN IP addresses\n"
484 "IPv4 address\n")
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800485{
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +0100486 struct ares_addr_node *node = talloc_zero(tall_sgsn_ctx, struct ares_addr_node);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800487 node->family = AF_INET;
488 inet_aton(argv[0], &node->addr.addr4);
489
490 node->next = sgsn->ares_servers;
491 sgsn->ares_servers = node;
492 return CMD_SUCCESS;
493}
494
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100495#define APN_STR "Configure the information per APN\n"
496#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
497
498static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
499 const char *imsi_prefix, int ggsn_id)
500{
501 struct apn_ctx *actx;
502 struct sgsn_ggsn_ctx *ggsn;
503
504 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
505 if (ggsn == NULL) {
506 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
507 ggsn_id, VTY_NEWLINE);
508 return CMD_WARNING;
509 }
510
511 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
512 if (!actx) {
513 vty_out(vty, "%% unable to create APN context for %s/%s%s",
514 apn_str, imsi_prefix, VTY_NEWLINE);
515 return CMD_WARNING;
516 }
517
518 actx->ggsn = ggsn;
519
520 return CMD_SUCCESS;
521}
522
Harald Welted193cb32010-05-17 22:58:03 +0200523DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
524 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100525 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100526 "Select the GGSN to use for the given APN gateway prefix\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100527 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200528{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100529
530 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200531}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100532
533DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
534 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
535 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100536 "Select the GGSN to use for the given APN gateway prefix if and only if the IMSI matches the"
537 " given prefix.\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100538 "An IMSI prefix\n"
539 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
540 "The GGSN id")
541{
542
543 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
544}
Harald Welted193cb32010-05-17 22:58:03 +0200545
Maxc005db72017-10-27 18:43:29 +0200546char *sgsn_gtp_ntoa(struct ul16_t *ul)
Harald Welte471ac7d2016-12-15 19:48:58 +0100547{
Max8492c202017-12-05 17:28:15 +0100548 struct in_addr ia;
549
550 if (gsna2in_addr(&ia, ul) != 0)
Harald Welte471ac7d2016-12-15 19:48:58 +0100551 return "UNKNOWN";
Max8492c202017-12-05 17:28:15 +0100552
553 return inet_ntoa(ia);
Harald Welte471ac7d2016-12-15 19:48:58 +0100554}
555
Harald Welted193cb32010-05-17 22:58:03 +0200556static void vty_dump_pdp(struct vty *vty, const char *pfx,
557 struct sgsn_pdp_ctx *pdp)
558{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200559 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welte471ac7d2016-12-15 19:48:58 +0100560 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s",
561 pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200562 if (pdp->lib) {
Max7933d962017-10-19 16:52:30 +0200563 char apnbuf[APN_MAXLEN + 1];
Harald Weltedfbd2c82017-08-13 00:56:45 +0200564 vty_out(vty, "%s APN: %s%s", pfx,
Max7933d962017-10-19 16:52:30 +0200565 osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200566 VTY_NEWLINE);
567 vty_out(vty, "%s PDP Address: %s%s", pfx,
Keith6cee1a12021-09-29 21:00:04 +0200568 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, false),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200569 VTY_NEWLINE);
Keith6cee1a12021-09-29 21:00:04 +0200570 if (pdp->lib->eua.v[1] == PDP_TYPE_N_IETF_IPv4v6) {
571 vty_out(vty, "%s PDP Address: %s%s", pfx,
572 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, true),
573 VTY_NEWLINE);
574 }
Maxb24af2b2017-12-05 17:54:42 +0100575 vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200576 sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200577 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200578 sgsn_gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100579 vty_out(vty, "%s GTPv%d Remote Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200580 sgsn_gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200581 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200582 sgsn_gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200583 }
Harald Welte471ac7d2016-12-15 19:48:58 +0100584
Harald Welteefbdee92010-06-10 00:20:12 +0200585 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200586}
587
588static void vty_dump_mmctx(struct vty *vty, const char *pfx,
589 struct sgsn_mm_ctx *mm, int pdp)
590{
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200591 uint32_t id = 0;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200592 const char *mm_state_name = NULL;
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200593
594 switch(mm->ran_type) {
595 case MM_CTX_T_UTRAN_Iu:
596#if BUILD_IU
597 id = mm->iu.ue_ctx->conn_id;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200598 mm_state_name = osmo_fsm_inst_state_name(mm->iu.mm_state_fsm);
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200599#endif
600 break;
601 case MM_CTX_T_GERAN_Gb:
602 id = mm->gb.tlli;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200603 mm_state_name = osmo_fsm_inst_state_name(mm->gb.mm_state_fsm);
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200604 break;
605 }
606
Harald Welted193cb32010-05-17 22:58:03 +0200607 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
608 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200609 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200610 pfx, mm->msisdn, id, mm->hlr, VTY_NEWLINE);
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200611 vty_out(vty, "%s GMM State: %s, Routeing Area: %s, Cell ID: %u%s",
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200612 pfx, osmo_fsm_inst_state_name(mm->gmm_fsm),
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100613 osmo_rai_name(&mm->ra), mm->gb.cell_id, VTY_NEWLINE);
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200614 vty_out(vty, "%s MM State: %s, RAN Type: %s%s", pfx, mm_state_name,
615 get_value_string(sgsn_ran_type_names, mm->ran_type), VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200616
Pau Espin Pedrol3b848bd2019-08-30 18:06:35 +0200617 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
Harald Welte8acd88f2010-05-18 10:57:45 +0200618
Harald Welted193cb32010-05-17 22:58:03 +0200619 if (pdp) {
620 struct sgsn_pdp_ctx *pdp;
621
622 llist_for_each_entry(pdp, &mm->pdp_list, list)
623 vty_dump_pdp(vty, " ", pdp);
624 }
625}
626
627DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
628 SHOW_STR "Display information about the SGSN")
629{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100630 if (sgsn->gsup_client) {
631 struct ipa_client_conn *link = sgsn->gsup_client->link;
632 vty_out(vty,
633 " Remote authorization: %sconnected to %s:%d via GSUP%s",
634 sgsn->gsup_client->is_connected ? "" : "not ",
635 link->addr, link->port,
636 VTY_NEWLINE);
637 }
Maxbaabc682017-10-20 13:39:57 +0200638 if (sgsn->gsn)
639 vty_out(vty, " GSN: signalling %s, user traffic %s%s",
640 inet_ntoa(sgsn->gsn->gsnc), inet_ntoa(sgsn->gsn->gsnu), VTY_NEWLINE);
641
Harald Welted193cb32010-05-17 22:58:03 +0200642 /* FIXME: statistics */
643 return CMD_SUCCESS;
644}
645
646#define MMCTX_STR "MM Context\n"
647#define INCLUDE_PDP_STR "Include PDP Context Information\n"
648
649#if 0
650DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
651 "show mm-context tlli HEX [pdp]",
652 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
653{
654 uint32_t tlli;
655 struct sgsn_mm_ctx *mm;
656
657 tlli = strtoul(argv[0], NULL, 16);
658 mm = sgsn_mm_ctx_by_tlli(tlli);
659 if (!mm) {
660 vty_out(vty, "No MM context for TLLI %08x%s",
661 tlli, VTY_NEWLINE);
662 return CMD_WARNING;
663 }
664 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
665 return CMD_SUCCESS;
666}
667#endif
668
669DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
670 "show mm-context imsi IMSI [pdp]",
671 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
672 INCLUDE_PDP_STR)
673{
674 struct sgsn_mm_ctx *mm;
675
676 mm = sgsn_mm_ctx_by_imsi(argv[0]);
677 if (!mm) {
678 vty_out(vty, "No MM context for IMSI %s%s",
679 argv[0], VTY_NEWLINE);
680 return CMD_WARNING;
681 }
Keithc12c1a62021-05-20 04:41:01 +0200682 vty_dump_mmctx(vty, "", mm, (argc > 1) ? 1 : 0);
Harald Welted193cb32010-05-17 22:58:03 +0200683 return CMD_SUCCESS;
684}
685
686DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
687 "show mm-context all [pdp]",
688 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
689{
690 struct sgsn_mm_ctx *mm;
Harald Welted193cb32010-05-17 22:58:03 +0200691 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
Keithc12c1a62021-05-20 04:41:01 +0200692 vty_dump_mmctx(vty, "", mm, (argc > 0) ? 1 : 0);
Harald Welted193cb32010-05-17 22:58:03 +0200693
694 return CMD_SUCCESS;
695}
696
Harald Welted193cb32010-05-17 22:58:03 +0200697DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
698 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100699 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200700{
701 struct sgsn_pdp_ctx *pdp;
702
703 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
704 vty_dump_pdp(vty, "", pdp);
705
706 return CMD_SUCCESS;
707}
Harald Welte288be162010-05-01 16:48:27 +0200708
Harald Welte7f6da482013-03-19 11:00:13 +0100709
710DEFUN(imsi_acl, cfg_imsi_acl_cmd,
711 "imsi-acl (add|del) IMSI",
712 "Access Control List of foreign IMSIs\n"
713 "Add IMSI to ACL\n"
714 "Remove IMSI from ACL\n"
715 "IMSI of subscriber\n")
716{
Maxef38b4c2018-11-20 10:25:53 +0100717 char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS + 1];
Harald Welte7f6da482013-03-19 11:00:13 +0100718 const char *op = argv[0];
Philipp Maier6ee49d82017-02-28 16:53:07 +0100719 const char *imsi = imsi_sanitized;
Maxf4fa6952018-01-15 12:12:51 +0100720 size_t len = strnlen(argv[1], GSM23003_IMSI_MAX_DIGITS + 1);
Harald Welte7f6da482013-03-19 11:00:13 +0100721 int rc;
722
Maxef38b4c2018-11-20 10:25:53 +0100723 memset(imsi_sanitized, '0', GSM23003_IMSI_MAX_DIGITS);
724 imsi_sanitized[GSM23003_IMSI_MAX_DIGITS] = '\0';
725
Philipp Maier6ee49d82017-02-28 16:53:07 +0100726 /* Sanitize IMSI */
Maxf4fa6952018-01-15 12:12:51 +0100727 if (len > GSM23003_IMSI_MAX_DIGITS) {
728 vty_out(vty, "%% IMSI (%s) too long (max %u digits) -- ignored!%s",
729 argv[1], GSM23003_IMSI_MAX_DIGITS, VTY_NEWLINE);
Philipp Maier6ee49d82017-02-28 16:53:07 +0100730 return CMD_WARNING;
731 }
Maxf4fa6952018-01-15 12:12:51 +0100732
733 osmo_strlcpy(imsi_sanitized + GSM23003_IMSI_MAX_DIGITS - len, argv[1],
734 sizeof(imsi_sanitized) - (GSM23003_IMSI_MAX_DIGITS - len));
Philipp Maier6ee49d82017-02-28 16:53:07 +0100735
Harald Welte7f6da482013-03-19 11:00:13 +0100736 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200737 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100738 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200739 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100740
741 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100742 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100743 return CMD_WARNING;
744 }
745
746 return CMD_SUCCESS;
747}
748
Eric2f898262021-05-19 18:57:50 +0200749DEFUN_DEPRECATED(cfg_encrypt, cfg_encrypt_cmd,
Max93408ae2016-06-28 14:10:16 +0200750 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
751 "Set encryption algorithm for SGSN\n"
752 "Use GEA0 (no encryption)\n"
753 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
754{
Max93408ae2016-06-28 14:10:16 +0200755 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
Eric2f898262021-05-19 18:57:50 +0200756
757 if (strcmp(argv[0], "gea") == 0)
758 return CMD_SUCCESS;
759
Max086067f2017-05-02 13:03:28 +0200760 if (c != GPRS_ALGO_GEA0) {
Eric2f898262021-05-19 18:57:50 +0200761 if (gprs_cipher_supported(c) <= 0) {
Max086067f2017-05-02 13:03:28 +0200762 vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
763 return CMD_WARNING;
764 }
765
766 if (!g_cfg->require_authentication) {
767 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
768 argv[0], VTY_NEWLINE);
769 return CMD_WARNING;
770 }
Max93408ae2016-06-28 14:10:16 +0200771 }
772
Eric2f898262021-05-19 18:57:50 +0200773 g_cfg->cipher_support_mask |= (1 << c);
774
775 return CMD_SUCCESS;
776}
777
778DEFUN(cfg_encrypt2, cfg_encrypt2_cmd,
779 "encryption gea <0-4> [<0-4>] [<0-4>] [<0-4>] [<0-4>]",
780 "Set encryption algorithms for SGSN\n"
781 "GPRS Encryption Algorithm\n"
782 "GEAn Algorithm Number\n"
783 "GEAn Algorithm Number\n"
784 "GEAn Algorithm Number\n"
785 "GEAn Algorithm Number\n"
786 "GEAn Algorithm Number\n")
787{
788 int i = 0;
789
790 g_cfg->cipher_support_mask = 0;
791 for (i = 0; i < argc; i++)
792 g_cfg->cipher_support_mask |= (1 << atoi(argv[i]));
793
794 for (i = 0; i < _GPRS_ALGO_NUM; i++) {
795 if (g_cfg->cipher_support_mask >> i & 1) {
796
797 if (i == GPRS_ALGO_GEA0)
798 continue;
799
800 if (gprs_cipher_supported(i) <= 0) {
801 vty_out(vty, "%% cipher %d is unsupported in current version%s", i, VTY_NEWLINE);
802 return CMD_ERR_INCOMPLETE;
803 }
804
805 if (!g_cfg->require_authentication) {
806 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
807 argv[i], VTY_NEWLINE);
808 return CMD_ERR_INCOMPLETE;
809 }
810
811 }
812 }
Max93408ae2016-06-28 14:10:16 +0200813
814 return CMD_SUCCESS;
815}
816
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700817DEFUN(cfg_authentication, cfg_authentication_cmd,
818 "authentication (optional|required)",
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200819 "Whether to enforce MS authentication in GERAN (only with auth-policy remote)\n"
820 "Allow MS to attach via GERAN without authentication (default and only possible value for non-remote auth-policy)\n"
821 "Always require authentication (only available for auth-policy remote, default with that auth-policy)\n")
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700822{
823 int required = (argv[0][0] == 'r');
824
825 if (vty->type != VTY_FILE) {
826 if (g_cfg->auth_policy != SGSN_AUTH_POLICY_REMOTE && required) {
827 vty_out(vty, "%% Authentication is not possible without HLR, "
828 "consider setting 'auth-policy' to 'remote'%s",
829 VTY_NEWLINE);
830 return CMD_WARNING;
831 }
832 }
833
834 g_cfg->require_authentication = required;
835 return CMD_SUCCESS;
836}
837
Harald Welte3dfb5492013-03-19 11:48:54 +0100838DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100839 "auth-policy (accept-all|closed|acl-only|remote)",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100840 "Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
841 " permitted to register to the network.\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100842 "Accept all IMSIs (DANGEROUS)\n"
843 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100844 "Accept only subscribers in the ACL\n"
845 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100846{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100847 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100848 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100849 g_cfg->auth_policy = val;
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100850 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100851
852 return CMD_SUCCESS;
853}
854
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100855/* Subscriber */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +0200856#include <osmocom/sgsn/gprs_subscriber.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100857
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100858static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100859{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100860#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100861 char expire_time[200];
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100862#endif
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100863 struct gsm_auth_tuple *at;
864 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100865 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100866
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100867 vty_out(vty, " Authorized: %d%s",
868 gsub->authorized, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100869 vty_out(vty, " LAC: %d/0x%x%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100870 gsub->lac, gsub->lac, VTY_NEWLINE);
871 vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
872 if (gsub->tmsi != GSM_RESERVED_TMSI)
873 vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100874 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100875 if (gsub->sgsn_data->msisdn_len > 0)
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400876 vty_out(vty, " MSISDN (BCD): %s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100877 osmo_hexdump(gsub->sgsn_data->msisdn,
878 gsub->sgsn_data->msisdn_len),
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400879 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100880
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100881 if (strlen(gsub->imei) > 0)
882 vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100883
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100884 for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100885 at_idx++) {
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100886 at = &gsub->sgsn_data->auth_triplets[at_idx];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100887 if (at->key_seq == GSM_KEY_SEQ_INVAL)
888 continue;
889
890 vty_out(vty, " A3A8 tuple (used %d times): ",
891 at->use_count);
Harald Welte89837d42016-05-06 23:28:11 +0200892 vty_out(vty, " CKSN: %d, ",
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100893 at->key_seq);
Harald Welte89837d42016-05-06 23:28:11 +0200894 if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
895 vty_out(vty, "RAND: %s, ",
Max34604c22019-02-13 14:11:29 +0100896 osmo_hexdump_nospc(at->vec.rand,
Harald Welte89837d42016-05-06 23:28:11 +0200897 sizeof(at->vec.rand)));
898 vty_out(vty, "SRES: %s, ",
Max34604c22019-02-13 14:11:29 +0100899 osmo_hexdump_nospc(at->vec.sres,
Harald Welte89837d42016-05-06 23:28:11 +0200900 sizeof(at->vec.sres)));
901 vty_out(vty, "Kc: %s%s",
Max34604c22019-02-13 14:11:29 +0100902 osmo_hexdump_nospc(at->vec.kc,
Harald Welte89837d42016-05-06 23:28:11 +0200903 sizeof(at->vec.kc)), VTY_NEWLINE);
904 }
905 if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
906 vty_out(vty, " AUTN: %s, ",
907 osmo_hexdump(at->vec.autn,
908 sizeof(at->vec.autn)));
909 vty_out(vty, "RES: %s, ",
Max34604c22019-02-13 14:11:29 +0100910 osmo_hexdump_nospc(at->vec.res, at->vec.res_len));
Harald Welte89837d42016-05-06 23:28:11 +0200911 vty_out(vty, "IK: %s, ",
Max34604c22019-02-13 14:11:29 +0100912 osmo_hexdump_nospc(at->vec.ik, sizeof(at->vec.ik)));
Harald Welte89837d42016-05-06 23:28:11 +0200913 vty_out(vty, "CK: %s, ",
Max34604c22019-02-13 14:11:29 +0100914 osmo_hexdump_nospc(at->vec.ck, sizeof(at->vec.ck)));
Harald Welte89837d42016-05-06 23:28:11 +0200915 }
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100916 }
917
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100918 llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
Max34604c22019-02-13 14:11:29 +0100919 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'",
920 pdp->context_id, pdp->pdp_type, pdp->apn_str);
921
922 if (pdp->qos_subscribed_len)
923 vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len));
924
925 vty_out(vty, "%s", VTY_NEWLINE);
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100926 }
927
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100928#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100929 /* print the expiration time of a subscriber */
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100930 if (gsub->expire_lu) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100931 strftime(expire_time, sizeof(expire_time),
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100932 "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100933 expire_time[sizeof(expire_time) - 1] = '\0';
934 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
935 }
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100936#endif
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100937
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100938 if (gsub->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100939 vty_out(vty, " Flags: %s%s%s%s%s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100940 gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100941 "FIRST_CONTACT " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100942 gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100943 "CANCELLED " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100944 gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100945 "UPDATE_LOCATION_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100946 gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100947 "AUTH_INFO_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100948 gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100949 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100950 VTY_NEWLINE);
951
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100952 vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100953}
954
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200955#define RESET_SGSN_STATE_STR \
956 "Remove all known subscribers, MM contexts and flush BSSGP queues." \
957 " Useful only when running tests against the SGSN\n"
958
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200959DEFUN_HIDDEN(reset_sgsn_state,
960 reset_sgsn_state_cmd,
961 "reset sgsn state",
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200962 RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR)
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200963{
964 struct gprs_subscr *subscr, *tmp_subscr;
965 struct sgsn_mm_ctx *mm, *tmp_mm;
966
967 llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
968 {
969 gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
970 }
971 vty_out(vty, "Cancelled MM Ctx. %s", VTY_NEWLINE);
972
973 llist_for_each_entry_safe(subscr, tmp_subscr, gprs_subscribers, entry) {
974 gprs_subscr_get(subscr);
975 gprs_subscr_cancel(subscr);
976 gprs_subscr_put(subscr);
977 }
978 vty_out(vty, "Removed all gprs subscribers.%s", VTY_NEWLINE);
979
980 bssgp_flush_all_queues();
981 vty_out(vty, "Flushed all BSSGPs queues.%s", VTY_NEWLINE);
982
Alexander Couzens35c34942018-09-17 04:39:14 +0200983 gtp_clear_queues(sgsn->gsn);
Alexander Couzensa66f0f22018-09-18 16:09:18 +0200984 vty_out(vty, "Flushed rx & tx queus towards the GGSN.%s", VTY_NEWLINE);
Alexander Couzens35c34942018-09-17 04:39:14 +0200985
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200986 /* remove all queues to bssgp */
987 return CMD_SUCCESS;
988}
989
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100990DEFUN(show_subscr_cache,
991 show_subscr_cache_cmd,
992 "show subscriber cache",
993 SHOW_STR "Show information about subscribers\n"
994 "Display contents of subscriber cache\n")
995{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100996 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100997
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100998 llist_for_each_entry(subscr, gprs_subscribers, entry) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100999 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
1000 subscr_dump_full_vty(vty, subscr, 0);
1001 }
1002
1003 return CMD_SUCCESS;
1004}
1005
1006#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
1007#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
1008 "Use the IMSI to select the subscriber\n" \
1009 "The IMSI\n"
1010
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001011#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
1012
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001013DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
1014 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
1015 UPDATE_SUBSCR_HELP
1016 UPDATE_SUBSCR_INSERT_HELP
1017 "Update authentication triplet\n"
1018 "Triplet index\n"
1019 "Set SRES value\nSRES value (4 byte) in hex\n"
1020 "Set RAND value\nRAND value (16 byte) in hex\n"
1021 "Set Kc value\nKc value (8 byte) in hex\n")
1022{
1023 const char *imsi = argv[0];
1024 const int cksn = atoi(argv[1]) - 1;
1025 const char *sres_str = argv[2];
1026 const char *rand_str = argv[3];
1027 const char *kc_str = argv[4];
1028 struct gsm_auth_tuple at = {0,};
1029
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001030 struct gprs_subscr *subscr;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001031
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001032 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001033 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001034 vty_out(vty, "%% unable get subscriber record for %s%s",
1035 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001036 return CMD_WARNING;
1037 }
1038
1039 OSMO_ASSERT(subscr->sgsn_data);
1040
Harald Welte121e9a42016-04-20 13:13:19 +02001041 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001042 vty_out(vty, "%% invalid SRES value '%s'%s",
1043 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001044 goto failed;
1045 }
Harald Welte121e9a42016-04-20 13:13:19 +02001046 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001047 vty_out(vty, "%% invalid RAND value '%s'%s",
1048 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001049 goto failed;
1050 }
Harald Welte121e9a42016-04-20 13:13:19 +02001051 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001052 vty_out(vty, "%% invalid Kc value '%s'%s",
1053 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001054 goto failed;
1055 }
1056 at.key_seq = cksn;
1057
1058 subscr->sgsn_data->auth_triplets[cksn] = at;
1059 subscr->sgsn_data->auth_triplets_updated = 1;
1060
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001061 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001062
1063 return CMD_SUCCESS;
1064
1065failed:
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001066 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001067 return CMD_SUCCESS;
1068}
1069
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001070DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001071 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001072 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001073 "Cancel (remove) subscriber record\n"
1074 "The MS moved to another SGSN\n"
1075 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001076{
1077 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001078 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001079
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001080 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001081
1082 subscr = gprs_subscr_get_by_imsi(imsi);
1083 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001084 vty_out(vty, "%% no subscriber record for %s%s",
1085 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001086 return CMD_WARNING;
1087 }
1088
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001089 if (strcmp(cancel_type, "update-procedure") == 0)
1090 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
1091 else
1092 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
1093
Jacob Erlbeck37139e52015-01-23 13:52:55 +01001094 gprs_subscr_cancel(subscr);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001095 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001096
1097 return CMD_SUCCESS;
1098}
1099
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001100DEFUN(update_subscr_create, update_subscr_create_cmd,
1101 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001102 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001103 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001104{
1105 const char *imsi = argv[0];
1106
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001107 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001108
1109 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001110 if (subscr) {
1111 vty_out(vty, "%% subscriber record already exists for %s%s",
1112 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001113 return CMD_WARNING;
1114 }
1115
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001116 subscr = gprs_subscr_get_or_create(imsi);
Alexander Couzens3326ba72020-12-09 22:02:55 +01001117 if (!subscr) {
1118 vty_out(vty, "Can not create subscriber. Out of memory.%s", imsi);
1119 return CMD_WARNING;
1120 }
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001121 subscr->keep_in_ram = 1;
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001122 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001123
1124 return CMD_SUCCESS;
1125}
1126
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001127DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
1128 UPDATE_SUBSCR_STR "destroy",
1129 UPDATE_SUBSCR_HELP
1130 "Destroy a subscriber entry\n")
1131{
1132 const char *imsi = argv[0];
1133
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001134 struct gprs_subscr *subscr;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001135
1136 subscr = gprs_subscr_get_by_imsi(imsi);
1137 if (!subscr) {
1138 vty_out(vty, "%% subscriber record does not exist for %s%s",
1139 imsi, VTY_NEWLINE);
1140 return CMD_WARNING;
1141 }
1142
1143 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001144 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001145 gprs_subscr_cancel(subscr);
1146 if (subscr->use_count > 1)
1147 vty_out(vty, "%% subscriber is still in use%s",
1148 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001149 gprs_subscr_put(subscr);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001150
1151 return CMD_SUCCESS;
1152}
1153
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001154#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
1155 "unknown-subscriber|roaming-not-allowed"
1156
1157#define UL_ERR_HELP \
1158 "Force error code SystemFailure\n" \
1159 "Force error code DataMissing\n" \
1160 "Force error code UnexpectedDataValue\n" \
1161 "Force error code UnknownSubscriber\n" \
1162 "Force error code RoamingNotAllowed\n"
1163
1164DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
1165 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
1166 UPDATE_SUBSCR_HELP
1167 "Complete the update location procedure\n"
1168 "The update location request succeeded\n"
1169 UL_ERR_HELP)
1170{
1171 const char *imsi = argv[0];
1172 const char *ret_code_str = argv[1];
1173
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001174 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001175
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001176 const struct value_string cause_mapping[] = {
1177 { GMM_CAUSE_NET_FAIL, "system-failure" },
1178 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
1179 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
1180 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
1181 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
1182 { 0, NULL }
1183 };
1184
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001185 subscr = gprs_subscr_get_by_imsi(imsi);
1186 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001187 vty_out(vty, "%% unable to get subscriber record for %s%s",
1188 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001189 return CMD_WARNING;
1190 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001191
1192 if (strcmp(ret_code_str, "ok") == 0) {
1193 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001194 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001195 } else {
1196 subscr->sgsn_data->error_cause =
1197 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001198 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001199 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001200
1201 gprs_subscr_update(subscr);
1202
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001203 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001204
1205 return CMD_SUCCESS;
1206}
1207
1208DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
1209 UPDATE_SUBSCR_STR "update-auth-info",
1210 UPDATE_SUBSCR_HELP
1211 "Complete the send authentication info procedure\n")
1212{
1213 const char *imsi = argv[0];
1214
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001215 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001216
1217 subscr = gprs_subscr_get_by_imsi(imsi);
1218 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001219 vty_out(vty, "%% unable to get subscriber record for %s%s",
1220 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001221 return CMD_WARNING;
1222 }
1223
1224 gprs_subscr_update_auth_info(subscr);
1225
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001226 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001227
1228 return CMD_SUCCESS;
1229}
1230
Oliver Smithab39b622021-07-05 15:41:05 +02001231DEFUN(page_subscr, page_subscr_info_cmd,
1232 "page imsi IMSI",
1233 "Send a PS paging request to subscriber\n"
1234 "Use the IMSI to select the subscriber\n"
1235 "The IMSI\n")
1236{
1237 const char *imsi = argv[0];
1238 struct sgsn_mm_ctx *mm;
1239
1240 mm = sgsn_mm_ctx_by_imsi(imsi);
1241 if (!mm) {
1242 vty_out(vty, "No MM context for IMSI %s%s", imsi, VTY_NEWLINE);
1243 return CMD_WARNING;
1244 }
1245
1246 gprs_gb_page_ps_ra(mm);
1247 return CMD_SUCCESS;
1248}
1249
Stefan Sperling88220092018-12-11 14:42:00 +01001250DEFUN(cfg_gsup_ipa_name,
1251 cfg_gsup_ipa_name_cmd,
1252 "gsup ipa-name NAME",
1253 "GSUP Parameters\n"
1254 "Set the IPA name of this SGSN\n"
1255 "A unique name for this SGSN. For example: PLMN + redundancy server number: SGSN-901-70-0. "
1256 "This name is used for GSUP routing and must be set if more than one SGSN is connected to the network. "
1257 "The default is 'SGSN-00-00-00-00-00-00'.\n")
1258{
1259 if (vty->type != VTY_FILE) {
1260 vty_out(vty, "The IPA name cannot be changed at run-time; "
1261 "It can only be set in the configuraton file.%s", VTY_NEWLINE);
1262 return CMD_WARNING;
1263 }
1264
1265 g_cfg->sgsn_ipa_name = talloc_strdup(tall_vty_ctx, argv[0]);
1266 return CMD_SUCCESS;
1267}
1268
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001269DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
1270 "gsup remote-ip A.B.C.D",
1271 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001272 "Set the IP address of the remote GSUP server (e.g. OsmoHLR)."
1273 " This setting only applies if 'auth-policy remote' is used.\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001274 "IPv4 Address\n")
1275{
1276 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
1277
1278 return CMD_SUCCESS;
1279}
1280
1281DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
1282 "gsup remote-port <0-65535>",
1283 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001284 "Set the TCP port of the remote GSUP server, see also 'gsup remote-ip'\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001285 "Remote TCP port\n")
1286{
1287 g_cfg->gsup_server_port = atoi(argv[0]);
1288
1289 return CMD_SUCCESS;
1290}
1291
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001292DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
1293 "gsup oap-id <0-65535>",
1294 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001295 "Set the OAP client ID for authentication on the GSUP protocol."
1296 " This setting only applies if 'auth-policy remote' is used.\n"
1297 "OAP client ID (0 == disabled)\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001298{
1299 /* VTY ensures range */
1300 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
1301 return CMD_SUCCESS;
1302}
1303
1304DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
1305 "gsup oap-k K",
1306 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001307 "Set the OAP shared secret key K for authentication on the GSUP protocol."
1308 " This setting only applies if auth-policy remote is used.\n"
1309 "K value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001310{
1311 const char *k = argv[0];
1312
1313 g_cfg->oap.secret_k_present = 0;
1314
1315 if ((!k) || (strlen(k) == 0))
1316 goto disable;
1317
1318 int k_len = osmo_hexparse(k,
1319 g_cfg->oap.secret_k,
1320 sizeof(g_cfg->oap.secret_k));
1321 if (k_len != 16) {
1322 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
1323 k_len, VTY_NEWLINE);
1324 goto disable;
1325 }
1326
1327 g_cfg->oap.secret_k_present = 1;
1328 return CMD_SUCCESS;
1329
1330disable:
1331 if (g_cfg->oap.client_id > 0) {
1332 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
1333 VTY_NEWLINE);
1334 return CMD_WARNING;
1335 }
1336 return CMD_SUCCESS;
1337}
1338
1339DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1340 "gsup oap-opc OPC",
1341 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001342 "Set the OAP shared secret OPC for authentication on the GSUP protocol."
1343 " This setting only applies if auth-policy remote is used.\n"
1344 "OPC value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001345{
1346 const char *opc = argv[0];
1347
1348 g_cfg->oap.secret_opc_present = 0;
1349
1350 if ((!opc) || (strlen(opc) == 0))
1351 goto disable;
1352
1353 int opc_len = osmo_hexparse(opc,
1354 g_cfg->oap.secret_opc,
1355 sizeof(g_cfg->oap.secret_opc));
1356 if (opc_len != 16) {
1357 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1358 opc_len, VTY_NEWLINE);
1359 goto disable;
1360 }
1361
1362 g_cfg->oap.secret_opc_present = 1;
1363 return CMD_SUCCESS;
1364
1365disable:
1366 if (g_cfg->oap.client_id > 0) {
1367 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1368 VTY_NEWLINE);
1369 return CMD_WARNING;
1370 }
1371 return CMD_SUCCESS;
1372}
1373
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001374DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1375 "access-point-name NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001376 "Globally allow the given APN name for all subscribers.\n"
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001377 "Add this NAME to the list\n")
1378{
1379 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1380}
1381
1382DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1383 "no access-point-name NAME",
1384 NO_STR "Configure a global list of allowed APNs\n"
1385 "Remove entry with NAME\n")
1386{
1387 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1388 if (!apn_ctx)
1389 return CMD_SUCCESS;
1390
1391 sgsn_apn_ctx_free(apn_ctx);
1392 return CMD_SUCCESS;
1393}
1394
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001395DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1396 "cdr filename NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001397 "CDR\n"
1398 "Set the file name for the call-data-record file, logging the data usage of each subscriber.\n"
1399 "filename\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001400{
1401 talloc_free(g_cfg->cdr.filename);
1402 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1403 return CMD_SUCCESS;
1404}
1405
1406DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1407 "no cdr filename",
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001408 NO_STR "CDR\nDisable saving CDR to file\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001409{
1410 talloc_free(g_cfg->cdr.filename);
1411 g_cfg->cdr.filename = NULL;
1412 return CMD_SUCCESS;
1413}
1414
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001415DEFUN(cfg_cdr_trap, cfg_cdr_trap_cmd,
1416 "cdr trap",
1417 "CDR\nEnable sending CDR via TRAP CTRL messages\n")
1418{
1419 g_cfg->cdr.trap = true;
1420 return CMD_SUCCESS;
1421}
1422
1423DEFUN(cfg_no_cdr_trap, cfg_no_cdr_trap_cmd,
1424 "no cdr trap",
1425 NO_STR "CDR\nDisable sending CDR via TRAP CTRL messages\n")
1426{
1427 g_cfg->cdr.trap = false;
1428 return CMD_SUCCESS;
1429}
1430
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001431DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1432 "cdr interval <1-2147483647>",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001433 "CDR\n"
1434 "Set the interval for the call-data-record file\n"
1435 "interval in seconds\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001436{
1437 g_cfg->cdr.interval = atoi(argv[0]);
1438 return CMD_SUCCESS;
1439}
1440
Philippf1f34362016-08-26 17:00:21 +02001441#define COMPRESSION_STR "Configure compression\n"
1442DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1443 "no compression rfc1144",
1444 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1445{
1446 g_cfg->pcomp_rfc1144.active = 0;
1447 g_cfg->pcomp_rfc1144.passive = 0;
1448 return CMD_SUCCESS;
1449}
1450
1451DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1452 "compression rfc1144 active slots <1-256>",
1453 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001454 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001455 "Compression is actively proposed\n"
1456 "Number of compression state slots\n"
1457 "Number of compression state slots\n")
1458{
1459 g_cfg->pcomp_rfc1144.active = 1;
1460 g_cfg->pcomp_rfc1144.passive = 1;
1461 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1462 return CMD_SUCCESS;
1463}
1464
1465DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1466 "compression rfc1144 passive",
1467 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001468 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001469 "Compression is available on request\n")
1470{
1471 g_cfg->pcomp_rfc1144.active = 0;
1472 g_cfg->pcomp_rfc1144.passive = 1;
1473 return CMD_SUCCESS;
1474}
1475
Philipp73f83d52016-09-02 13:38:01 +02001476DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
1477 "no compression v42bis",
1478 NO_STR COMPRESSION_STR "disable V.42bis data compression\n")
1479{
1480 g_cfg->dcomp_v42bis.active = 0;
1481 g_cfg->dcomp_v42bis.passive = 0;
1482 return CMD_SUCCESS;
1483}
1484
1485DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
1486 "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
1487 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001488 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001489 "Compression is actively proposed\n"
1490 "Direction in which the compression shall be active (p0)\n"
1491 "Compress ms->sgsn direction only\n"
1492 "Compress sgsn->ms direction only\n"
1493 "Both directions\n"
1494 "Number of codewords (p1)\n"
1495 "Number of codewords\n"
1496 "Maximum string length (p2)\n" "Maximum string length\n")
1497{
1498 g_cfg->dcomp_v42bis.active = 1;
1499 g_cfg->dcomp_v42bis.passive = 1;
1500
1501 switch (argv[0][0]) {
1502 case 'm':
1503 g_cfg->dcomp_v42bis.p0 = 1;
1504 break;
1505 case 's':
1506 g_cfg->dcomp_v42bis.p0 = 2;
1507 break;
1508 case 'b':
1509 g_cfg->dcomp_v42bis.p0 = 3;
1510 break;
1511 }
1512
1513 g_cfg->dcomp_v42bis.p1 = atoi(argv[1]);
1514 g_cfg->dcomp_v42bis.p2 = atoi(argv[2]);
1515 return CMD_SUCCESS;
1516}
1517
1518DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
1519 "compression v42bis passive",
1520 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001521 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001522 "Compression is available on request\n")
1523{
1524 g_cfg->dcomp_v42bis.active = 0;
1525 g_cfg->dcomp_v42bis.passive = 1;
1526 return CMD_SUCCESS;
1527}
1528
Pau Espin Pedrol2c908992019-08-19 19:06:06 +02001529#if BUILD_IU
1530DEFUN(cfg_sgsn_cs7_instance_iu,
1531 cfg_sgsn_cs7_instance_iu_cmd,
1532 "cs7-instance-iu <0-15>",
1533 "Set SS7 to be used by the Iu-Interface.\n" "SS7 instance reference number (default: 0)\n")
1534{
1535 g_cfg->iu.cs7_instance = atoi(argv[0]);
1536 return CMD_SUCCESS;
1537}
1538#endif
1539
Pau Espin Pedrole5c89982021-05-03 18:16:42 +02001540DEFUN(cfg_sgsn_mme, cfg_sgsn_mme_cmd,
1541 "mme NAME",
1542 "Configure an MME peer\n"
1543 "Name identifying the MME peer\n")
1544{
1545 struct sgsn_mme_ctx *mme;
1546
1547 mme = sgsn_mme_ctx_find_alloc(sgsn, argv[0]);
1548 if (!mme)
1549 return CMD_WARNING;
1550
1551 vty->node = MME_NODE;
1552 vty->index = mme;
1553
1554 return CMD_SUCCESS;
1555}
1556
1557DEFUN(cfg_sgsn_no_mme, cfg_sgsn_no_mme_cmd,
1558 "no mme NAME",
1559 NO_STR "Delete an MME peer configuration\n"
1560 "Name identifying the MME peer\n")
1561{
1562 struct sgsn_mme_ctx *mme;
1563
1564 mme = sgsn_mme_ctx_by_name(sgsn, argv[0]);
1565 if (!mme) {
1566 vty_out(vty, "%% MME %s doesn't exist.%s",
1567 argv[0], VTY_NEWLINE);
1568 return CMD_WARNING;
1569 }
1570
1571 sgsn_mme_ctx_free(mme);
1572
1573 return CMD_SUCCESS;
1574}
1575
1576#define GTP_STR "Configure GTP connection\n"
1577
1578DEFUN(cfg_mme_remote_ip, cfg_mme_remote_ip_cmd,
1579 "gtp remote-ip A.B.C.D",
1580 GTP_STR "Set Remote GTP IP address\n" IP_STR)
1581{
1582 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1583
1584 inet_aton(argv[0], &mme->remote_addr);
1585
1586 return CMD_SUCCESS;
1587}
1588
1589#define RAN_INFO_STR "Configure RAN Information Relay routing\n"
1590#define TAI_DOC "MCC\n" "MNC\n" "TAC\n"
1591
1592DEFUN(cfg_mme_ran_info_relay_tai, cfg_mme_ran_info_relay_tai_cmd,
1593 "gtp ran-info-relay <0-999> <0-999> <0-65535>",
1594 GTP_STR RAN_INFO_STR TAI_DOC)
1595{
1596 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1597 struct sgsn_mme_ctx *mme_tmp;
1598 struct osmo_eutran_tai tai;
1599
1600 const char *mcc = argv[0];
1601 const char *mnc = argv[1];
1602 const char *tac = argv[2];
1603
1604 if (osmo_mcc_from_str(mcc, &tai.mcc)) {
1605 vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
1606 return CMD_WARNING;
1607 }
1608 if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
1609 vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
1610 return CMD_WARNING;
1611 }
1612 tai.tac = atoi(tac);
1613
1614 if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
1615 if (mme_tmp != mme) {
1616 vty_out(vty, "%% Another MME %s already contains this route%s",
1617 mme_tmp->name, VTY_NEWLINE);
1618 return CMD_WARNING;
1619 }
1620 /* else: NO-OP, return */
1621 return CMD_SUCCESS;
1622 }
1623
1624 sgsn_mme_ctx_route_add(mme, &tai);
1625 return CMD_SUCCESS;
1626}
1627
1628DEFUN(cfg_mme_no_ran_info_relay_tai, cfg_mme_no_ran_info_relay_tai_cmd,
1629 "no gtp ran-info-relay <0-999> <0-999> <0-65535>",
1630 NO_STR GTP_STR RAN_INFO_STR TAI_DOC)
1631{
1632 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1633 struct sgsn_mme_ctx *mme_tmp;
1634 struct osmo_eutran_tai tai;
1635
1636 const char *mcc = argv[0];
1637 const char *mnc = argv[1];
1638 const char *tac = argv[2];
1639
1640 if (osmo_mcc_from_str(mcc, &tai.mcc)) {
1641 vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
1642 return CMD_WARNING;
1643 }
1644 if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
1645 vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
1646 return CMD_WARNING;
1647 }
1648 tai.tac = atoi(tac);
1649
1650 if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
1651 if (mme_tmp != mme) {
1652 vty_out(vty, "%% Another MME %s contains this route%s",
1653 mme_tmp->name, VTY_NEWLINE);
1654 return CMD_WARNING;
1655 }
1656 sgsn_mme_ctx_route_del(mme, &tai);
1657 return CMD_SUCCESS;
1658 } else {
1659 vty_out(vty, "%% This route doesn't exist in current MME %s%s",
1660 mme->name, VTY_NEWLINE);
1661 return CMD_WARNING;
1662 }
1663}
1664
1665DEFUN(cfg_mme_ran_info_relay_default, cfg_mme_ran_info_relay_default_cmd,
1666 "gtp ran-info-relay default",
1667 GTP_STR RAN_INFO_STR "Set as default route")
1668{
1669 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1670 struct sgsn_mme_ctx *default_mme;
1671
1672 if (mme->default_route)
1673 return CMD_SUCCESS; /* NO-OP */
1674
1675 if ((default_mme = sgsn_mme_ctx_by_default_route(sgsn))) {
1676 vty_out(vty, "%% Another MME %s is already set as default route, "
1677 "remove it before setting it here.%s",
1678 default_mme->name, VTY_NEWLINE);
1679 return CMD_WARNING;
1680 }
1681
1682 mme->default_route = true;
1683 return CMD_SUCCESS;
1684}
1685
1686DEFUN(cfg_mme_no_ran_info_relay_default, cfg_mme_no_ran_info_relay_default_cmd,
1687 "no gtp ran-info-relay default",
1688 NO_STR GTP_STR RAN_INFO_STR "Set as default route")
1689{
1690 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1691 mme->default_route = false;
1692 return CMD_SUCCESS;
1693}
1694
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001695int sgsn_vty_init(struct sgsn_config *cfg)
Harald Welte288be162010-05-01 16:48:27 +02001696{
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001697 g_cfg = cfg;
1698
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001699 g_cfg->T_defs = sgsn_T_defs;
1700 osmo_tdefs_reset(g_cfg->T_defs);
1701
Harald Welted193cb32010-05-17 22:58:03 +02001702 install_element_ve(&show_sgsn_cmd);
1703 //install_element_ve(&show_mmctx_tlli_cmd);
1704 install_element_ve(&show_mmctx_imsi_cmd);
1705 install_element_ve(&show_mmctx_all_cmd);
1706 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001707 install_element_ve(&show_subscr_cache_cmd);
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001708 install_element_ve(&show_timer_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001709
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001710 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001711 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001712 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001713 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001714 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1715 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Oliver Smithab39b622021-07-05 15:41:05 +02001716 install_element(ENABLE_NODE, &page_subscr_info_cmd);
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001717 install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001718
1719 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1720 install_node(&sgsn_node, config_write_sgsn);
Keithc70e8382020-10-19 22:24:48 +02001721 install_element(SGSN_NODE, &cfg_sgsn_state_dir_cmd);
Harald Weltee300d002010-06-02 12:41:34 +02001722 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001723 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1724 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1725 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +02001726 install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +02001727 install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001728 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001729 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Vadim Yanitskiy794f4462019-05-27 05:39:06 +07001730 install_element(SGSN_NODE, &cfg_authentication_cmd);
Eric2f898262021-05-19 18:57:50 +02001731
1732 /* order matters here: ensure we attempt to parse our new command first! */
1733 install_element(SGSN_NODE, &cfg_encrypt2_cmd);
Max93408ae2016-06-28 14:10:16 +02001734 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Eric2f898262021-05-19 18:57:50 +02001735
Stefan Sperling88220092018-12-11 14:42:00 +01001736 install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001737 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1738 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001739 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1740 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1741 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001742 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1743 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001744 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1745 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001746 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1747 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001748 install_element(SGSN_NODE, &cfg_cdr_trap_cmd);
1749 install_element(SGSN_NODE, &cfg_no_cdr_trap_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001750 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001751 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001752 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001753
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001754 install_element(SGSN_NODE, &cfg_sgsn_timer_cmd);
Harald Welte94508822015-08-15 19:08:21 +02001755
Philippf1f34362016-08-26 17:00:21 +02001756 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1757 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1758 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
Philipp73f83d52016-09-02 13:38:01 +02001759 install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd);
1760 install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
1761 install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001762
Pau Espin Pedrole5c89982021-05-03 18:16:42 +02001763 install_element(SGSN_NODE, &cfg_sgsn_mme_cmd);
1764 install_element(SGSN_NODE, &cfg_sgsn_no_mme_cmd);
1765 install_node(&mme_node, NULL);
1766 install_element(MME_NODE, &cfg_mme_remote_ip_cmd);
1767 install_element(MME_NODE, &cfg_mme_ran_info_relay_default_cmd);
1768 install_element(MME_NODE, &cfg_mme_no_ran_info_relay_default_cmd);
1769 install_element(MME_NODE, &cfg_mme_ran_info_relay_tai_cmd);
1770 install_element(MME_NODE, &cfg_mme_no_ran_info_relay_tai_cmd);
1771
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001772#ifdef BUILD_IU
Pau Espin Pedrol2c908992019-08-19 19:06:06 +02001773 install_element(SGSN_NODE, &cfg_sgsn_cs7_instance_iu_cmd);
Neels Hofmeyra7a39472017-07-05 15:19:52 +02001774 ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001775#endif
Harald Welte288be162010-05-01 16:48:27 +02001776 return 0;
1777}
1778
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001779int sgsn_parse_config(const char *config_file)
Harald Welte288be162010-05-01 16:48:27 +02001780{
1781 int rc;
1782
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001783 /* make sure sgsn_vty_init() was called before this */
1784 OSMO_ASSERT(g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +01001785
Eric2f898262021-05-19 18:57:50 +02001786 g_cfg->cipher_support_mask = 0x1; /* support GEA0 by default unless specific encryption config exists */
1787
Harald Weltedcccb182010-05-16 20:52:23 +02001788 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001789 if (rc < 0) {
1790 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1791 return rc;
1792 }
1793
Neels Hofmeyr27355c92017-02-24 06:28:31 +01001794 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE
1795 && !(g_cfg->gsup_server_addr.sin_addr.s_addr
1796 && g_cfg->gsup_server_port)) {
1797 fprintf(stderr, "Configuration error:"
1798 " 'auth-policy remote' requires both"
1799 " 'gsup remote-ip' and 'gsup remote-port'\n");
1800 return -EINVAL;
1801 }
1802
Harald Welte288be162010-05-01 16:48:27 +02001803 return 0;
1804}