blob: e0e26775efe32b50faf719f3f5b1b5b0f244ebca [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
Holger Hans Peter Freythera2730302014-03-23 18:08:26 +0100138char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
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;
151 strcpy(str, "IPv4 ");
152 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;
157 strcpy(str, "IPv6 ");
158 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
159 return str;
160 default:
161 break;
162 }
163 break;
164 case PDP_TYPE_ORG_ETSI:
165 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
166 return "PPP";
167 break;
168 default:
169 break;
170 }
171
172 return "invalid";
173}
174
Harald Welte288be162010-05-01 16:48:27 +0200175static struct cmd_node sgsn_node = {
176 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200177 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200178 1,
179};
180
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200181static struct cmd_node mme_node = {
182 MME_NODE,
183 "%s(config-sgsn-mme)# ",
184 1,
185};
186
187static void config_write_mme(struct vty *vty, const struct sgsn_mme_ctx *mme, const char *prefix)
188{
189 struct mme_rim_route *rt;
190
191 vty_out(vty, "%smme %s%s", prefix, mme->name, VTY_NEWLINE);
192
193 vty_out(vty, "%s gtp remote-ip %s%s", prefix, inet_ntoa(mme->remote_addr), VTY_NEWLINE);
194 if (mme->default_route)
195 vty_out(vty, "%s gtp ran-info-relay default%s", prefix, VTY_NEWLINE);
196 llist_for_each_entry(rt, &mme->routes, list) {
197 vty_out(vty, "%s gtp ran-info-relay %s %s %u%s", prefix,
198 osmo_mcc_name(rt->tai.mcc), osmo_mnc_name(rt->tai.mnc, rt->tai.mnc_3_digits),
199 rt->tai.tac, VTY_NEWLINE);
200 }
201}
202
Harald Welte288be162010-05-01 16:48:27 +0200203static int config_write_sgsn(struct vty *vty)
204{
Harald Welte77289c22010-05-18 14:32:29 +0200205 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100206 struct imsi_acl_entry *acl;
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100207 struct apn_ctx *actx;
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800208 struct ares_addr_node *server;
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200209 struct sgsn_mme_ctx *mme;
Eric2f898262021-05-19 18:57:50 +0200210 int i;
Harald Welte288be162010-05-01 16:48:27 +0200211
212 vty_out(vty, "sgsn%s", VTY_NEWLINE);
213
Keithc70e8382020-10-19 22:24:48 +0200214 vty_out(vty, " gtp state-dir %s%s",
215 g_cfg->gtp_statedir, VTY_NEWLINE);
Harald Weltee300d002010-06-02 12:41:34 +0200216 vty_out(vty, " gtp local-ip %s%s",
217 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
218
Harald Welted193cb32010-05-17 22:58:03 +0200219 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800220 if (gctx->id == UINT32_MAX)
221 continue;
222
Harald Welteff3bde82010-05-19 15:09:09 +0200223 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200224 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200225 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200226 gctx->gtp_version, VTY_NEWLINE);
Pau Espin Pedrolaa89f5d2019-08-28 16:08:45 +0200227 if (gctx->echo_interval)
228 vty_out(vty, " ggsn %u echo-interval %u%s",
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200229 gctx->id, gctx->echo_interval, VTY_NEWLINE);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200230 else
231 vty_out(vty, " ggsn %u no echo-interval%s",
232 gctx->id, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200233 }
234
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800235 if (sgsn->cfg.dynamic_lookup)
236 vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE);
237
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800238 for (server = sgsn->ares_servers; server; server = server->next)
239 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
240
Eric2f898262021-05-19 18:57:50 +0200241 if (g_cfg->cipher_support_mask != 0) {
242 vty_out(vty, " encryption gea");
243
244 for (i = 0; i < _GPRS_ALGO_NUM; i++)
245 if (g_cfg->cipher_support_mask >> i & 1)
246 vty_out(vty, " %u", i);
247
248 vty_out(vty, "%s", VTY_NEWLINE);
249 }
Stefan Sperling88220092018-12-11 14:42:00 +0100250 if (g_cfg->sgsn_ipa_name)
251 vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100252 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
253 vty_out(vty, " gsup remote-ip %s%s",
254 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
255 if (g_cfg->gsup_server_port)
256 vty_out(vty, " gsup remote-port %d%s",
257 g_cfg->gsup_server_port, VTY_NEWLINE);
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200258 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE && !g_cfg->require_authentication)
259 vty_out(vty, " authentication optional%s", VTY_NEWLINE);
Max176b62a2016-07-04 11:09:07 +0200260 vty_out(vty, " auth-policy %s%s",
261 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
262 VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200263
264 vty_out(vty, " gsup oap-id %d%s",
265 (int)g_cfg->oap.client_id, VTY_NEWLINE);
266 if (g_cfg->oap.secret_k_present != 0)
267 vty_out(vty, " gsup oap-k %s%s",
268 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
269 VTY_NEWLINE);
270 if (g_cfg->oap.secret_opc_present != 0)
271 vty_out(vty, " gsup oap-opc %s%s",
272 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
273 VTY_NEWLINE);
274
Harald Welte7f6da482013-03-19 11:00:13 +0100275 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
276 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
277
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100278 if (llist_empty(&sgsn_apn_ctxts))
279 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
280 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
281 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200282 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100283 actx->name, actx->imsi_prefix, actx->ggsn->id,
284 VTY_NEWLINE);
285 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200286 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100287 actx->ggsn->id, VTY_NEWLINE);
288 }
289
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200290 if (g_cfg->cdr.filename)
291 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
292 else
293 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +0100294 if (g_cfg->cdr.trap)
295 vty_out(vty, " cdr trap%s", VTY_NEWLINE);
296 else
297 vty_out(vty, " no cdr trap%s", VTY_NEWLINE);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200298 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
299
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200300 osmo_tdef_vty_write(vty, g_cfg->T_defs, " timer ");
Harald Welte94508822015-08-15 19:08:21 +0200301
Philippf1f34362016-08-26 17:00:21 +0200302 if (g_cfg->pcomp_rfc1144.active) {
303 vty_out(vty, " compression rfc1144 active slots %d%s",
304 g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE);
305 } else if (g_cfg->pcomp_rfc1144.passive) {
306 vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE);
307 } else
308 vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE);
309
Philipp73f83d52016-09-02 13:38:01 +0200310 if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) {
311 vty_out(vty,
312 " compression v42bis active direction sgsn codewords %d strlen %d%s",
313 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
314 VTY_NEWLINE);
315 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) {
316 vty_out(vty,
317 " compression v42bis active direction ms codewords %d strlen %d%s",
318 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
319 VTY_NEWLINE);
320 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) {
321 vty_out(vty,
322 " compression v42bis active direction both codewords %d strlen %d%s",
323 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
324 VTY_NEWLINE);
325 } else if (g_cfg->dcomp_v42bis.passive) {
326 vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE);
327 } else
328 vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
329
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200330 llist_for_each_entry(mme, &sgsn->mme_list, list) {
331 config_write_mme(vty, mme, " ");
332 }
333
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200334#ifdef BUILD_IU
Pau Espin Pedrol2c908992019-08-19 19:06:06 +0200335 vty_out(vty, " cs7-instance-iu %u%s", g_cfg->iu.cs7_instance,
336 VTY_NEWLINE);
Neels Hofmeyra7a39472017-07-05 15:19:52 +0200337 ranap_iu_vty_config_write(vty, " ");
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200338#endif
339
Harald Welte288be162010-05-01 16:48:27 +0200340 return CMD_SUCCESS;
341}
342
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100343#define SGSN_STR "Configure the SGSN\n"
344#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200345
346DEFUN(cfg_sgsn, cfg_sgsn_cmd,
347 "sgsn",
348 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200349{
350 vty->node = SGSN_NODE;
351 return CMD_SUCCESS;
352}
353
Keithc70e8382020-10-19 22:24:48 +0200354DEFUN(cfg_sgsn_state_dir, cfg_sgsn_state_dir_cmd,
355 "gtp state-dir PATH",
356 "GTP Parameters\n"
357 "Set the directory for the GTP State file\n"
358 "Local Directory\n")
359{
360 osmo_talloc_replace_string(sgsn, &sgsn->cfg.gtp_statedir, argv[0]);
361
362 return CMD_SUCCESS;
363}
364
Harald Weltee300d002010-06-02 12:41:34 +0200365DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
366 "gtp local-ip A.B.C.D",
367 "GTP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100368 "Set the IP address for the local GTP bind for the Gp interface (towards the GGSNs)."
369 " Note: in case you would like to run the GGSN on the same machine as the SGSN, you can not run"
370 " both on the same IP address, since both sides are specified to use the same GTP port numbers"
371 " (" OSMO_STRINGIFY_VAL(GTP1C_PORT) " and " OSMO_STRINGIFY_VAL(GTP1U_PORT) ")."
372 " For example, you could use 127.0.0.1 for the SGSN and 127.0.0.2 for the GGSN in such"
373 " situations.\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100374 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200375{
376 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
377
378 return CMD_SUCCESS;
379}
380
Harald Welted193cb32010-05-17 22:58:03 +0200381DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
382 "ggsn <0-255> remote-ip A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100383 GGSN_STR "GGSN Number\n"
384 "Configure this static GGSN to use the specified remote IP address.\n"
385 "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200386{
387 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200388 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200389
Harald Welted193cb32010-05-17 22:58:03 +0200390 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200391
Harald Welted193cb32010-05-17 22:58:03 +0200392 return CMD_SUCCESS;
393}
394
395#if 0
396DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
397 "ggsn <0-255> remote-port <0-65535>",
398 "")
399{
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 Welted193cb32010-05-17 22:58:03 +0200402 uint16_t port = atoi(argv[1]);
403
404}
405#endif
406
407DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
408 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100409 GGSN_STR "GGSN Number\n" "GTP Version\n"
410 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200411{
412 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200413 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200414
415 if (atoi(argv[1]))
416 ggc->gtp_version = 1;
417 else
418 ggc->gtp_version = 0;
419
420 return CMD_SUCCESS;
421}
422
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200423/* Seee 3GPP TS 29.060 section 7.2.1 */
424DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
425 "ggsn <0-255> echo-interval <1-36000>",
426 GGSN_STR "GGSN Number\n"
427 "Send an echo request to this static GGSN every interval.\n"
428 "Interval between echo requests in seconds.\n")
429{
430 uint32_t id = atoi(argv[0]);
431 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
432
433 ggc->echo_interval = atoi(argv[1]);
434
435 if (ggc->echo_interval < 60)
Pau Espin Pedrolba2e5002019-05-27 17:35:32 +0200436 vty_out(vty, "%% 3GPP TS 29.060 section 7.2.1 states interval should " \
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200437 "not be lower than 60 seconds, use this value for " \
438 "testing purposes only!%s", VTY_NEWLINE);
439
Alexander Couzens176a4d22018-09-18 20:07:37 +0200440 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200441 return CMD_SUCCESS;
442}
443
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200444DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
445 "ggsn <0-255> no echo-interval",
446 GGSN_STR "GGSN Number\n"
447 NO_STR "Send an echo request to this static GGSN every interval.\n")
448{
449 uint32_t id = atoi(argv[0]);
450 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
451
Pau Espin Pedrolaa89f5d2019-08-28 16:08:45 +0200452 ggc->echo_interval = 0;
Alexander Couzens176a4d22018-09-18 20:07:37 +0200453 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200454
455 return CMD_SUCCESS;
456}
457
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800458DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
459 "ggsn dynamic",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100460 GGSN_STR
461 "Enable dynamic resolving of GGSNs based on DNS resolving the APN name like in a GRX-style setup."
462 " Changing this setting requires a restart.\n")
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800463{
464 sgsn->cfg.dynamic_lookup = 1;
465 return CMD_SUCCESS;
466}
467
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800468DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
469 "grx-dns-add A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100470 "Use the specified IP address for DNS-resolving the AP names to GGSN IP addresses\n"
471 "IPv4 address\n")
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800472{
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +0100473 struct ares_addr_node *node = talloc_zero(tall_sgsn_ctx, struct ares_addr_node);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800474 node->family = AF_INET;
475 inet_aton(argv[0], &node->addr.addr4);
476
477 node->next = sgsn->ares_servers;
478 sgsn->ares_servers = node;
479 return CMD_SUCCESS;
480}
481
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100482#define APN_STR "Configure the information per APN\n"
483#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
484
485static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
486 const char *imsi_prefix, int ggsn_id)
487{
488 struct apn_ctx *actx;
489 struct sgsn_ggsn_ctx *ggsn;
490
491 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
492 if (ggsn == NULL) {
493 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
494 ggsn_id, VTY_NEWLINE);
495 return CMD_WARNING;
496 }
497
498 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
499 if (!actx) {
500 vty_out(vty, "%% unable to create APN context for %s/%s%s",
501 apn_str, imsi_prefix, VTY_NEWLINE);
502 return CMD_WARNING;
503 }
504
505 actx->ggsn = ggsn;
506
507 return CMD_SUCCESS;
508}
509
Harald Welted193cb32010-05-17 22:58:03 +0200510DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
511 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100512 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100513 "Select the GGSN to use for the given APN gateway prefix\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100514 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200515{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100516
517 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200518}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100519
520DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
521 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
522 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100523 "Select the GGSN to use for the given APN gateway prefix if and only if the IMSI matches the"
524 " given prefix.\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100525 "An IMSI prefix\n"
526 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
527 "The GGSN id")
528{
529
530 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
531}
Harald Welted193cb32010-05-17 22:58:03 +0200532
Maxc005db72017-10-27 18:43:29 +0200533char *sgsn_gtp_ntoa(struct ul16_t *ul)
Harald Welte471ac7d2016-12-15 19:48:58 +0100534{
Max8492c202017-12-05 17:28:15 +0100535 struct in_addr ia;
536
537 if (gsna2in_addr(&ia, ul) != 0)
Harald Welte471ac7d2016-12-15 19:48:58 +0100538 return "UNKNOWN";
Max8492c202017-12-05 17:28:15 +0100539
540 return inet_ntoa(ia);
Harald Welte471ac7d2016-12-15 19:48:58 +0100541}
542
Harald Welted193cb32010-05-17 22:58:03 +0200543static void vty_dump_pdp(struct vty *vty, const char *pfx,
544 struct sgsn_pdp_ctx *pdp)
545{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200546 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welte471ac7d2016-12-15 19:48:58 +0100547 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s",
548 pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200549 if (pdp->lib) {
Max7933d962017-10-19 16:52:30 +0200550 char apnbuf[APN_MAXLEN + 1];
Harald Weltedfbd2c82017-08-13 00:56:45 +0200551 vty_out(vty, "%s APN: %s%s", pfx,
Max7933d962017-10-19 16:52:30 +0200552 osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200553 VTY_NEWLINE);
554 vty_out(vty, "%s PDP Address: %s%s", pfx,
555 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
556 VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100557 vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200558 sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200559 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200560 sgsn_gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100561 vty_out(vty, "%s GTPv%d Remote Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200562 sgsn_gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200563 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200564 sgsn_gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200565 }
Harald Welte471ac7d2016-12-15 19:48:58 +0100566
Harald Welteefbdee92010-06-10 00:20:12 +0200567 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200568}
569
570static void vty_dump_mmctx(struct vty *vty, const char *pfx,
571 struct sgsn_mm_ctx *mm, int pdp)
572{
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200573 uint32_t id = 0;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200574 const char *mm_state_name = NULL;
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200575
576 switch(mm->ran_type) {
577 case MM_CTX_T_UTRAN_Iu:
578#if BUILD_IU
579 id = mm->iu.ue_ctx->conn_id;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200580 mm_state_name = osmo_fsm_inst_state_name(mm->iu.mm_state_fsm);
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200581#endif
582 break;
583 case MM_CTX_T_GERAN_Gb:
584 id = mm->gb.tlli;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200585 mm_state_name = osmo_fsm_inst_state_name(mm->gb.mm_state_fsm);
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200586 break;
587 }
588
Harald Welted193cb32010-05-17 22:58:03 +0200589 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
590 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200591 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200592 pfx, mm->msisdn, id, mm->hlr, VTY_NEWLINE);
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200593 vty_out(vty, "%s GMM State: %s, Routeing Area: %s, Cell ID: %u%s",
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200594 pfx, osmo_fsm_inst_state_name(mm->gmm_fsm),
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100595 osmo_rai_name(&mm->ra), mm->gb.cell_id, VTY_NEWLINE);
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200596 vty_out(vty, "%s MM State: %s, RAN Type: %s%s", pfx, mm_state_name,
597 get_value_string(sgsn_ran_type_names, mm->ran_type), VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200598
Pau Espin Pedrol3b848bd2019-08-30 18:06:35 +0200599 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
Harald Welte8acd88f2010-05-18 10:57:45 +0200600
Harald Welted193cb32010-05-17 22:58:03 +0200601 if (pdp) {
602 struct sgsn_pdp_ctx *pdp;
603
604 llist_for_each_entry(pdp, &mm->pdp_list, list)
605 vty_dump_pdp(vty, " ", pdp);
606 }
607}
608
609DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
610 SHOW_STR "Display information about the SGSN")
611{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100612 if (sgsn->gsup_client) {
613 struct ipa_client_conn *link = sgsn->gsup_client->link;
614 vty_out(vty,
615 " Remote authorization: %sconnected to %s:%d via GSUP%s",
616 sgsn->gsup_client->is_connected ? "" : "not ",
617 link->addr, link->port,
618 VTY_NEWLINE);
619 }
Maxbaabc682017-10-20 13:39:57 +0200620 if (sgsn->gsn)
621 vty_out(vty, " GSN: signalling %s, user traffic %s%s",
622 inet_ntoa(sgsn->gsn->gsnc), inet_ntoa(sgsn->gsn->gsnu), VTY_NEWLINE);
623
Harald Welted193cb32010-05-17 22:58:03 +0200624 /* FIXME: statistics */
625 return CMD_SUCCESS;
626}
627
628#define MMCTX_STR "MM Context\n"
629#define INCLUDE_PDP_STR "Include PDP Context Information\n"
630
631#if 0
632DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
633 "show mm-context tlli HEX [pdp]",
634 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
635{
636 uint32_t tlli;
637 struct sgsn_mm_ctx *mm;
638
639 tlli = strtoul(argv[0], NULL, 16);
640 mm = sgsn_mm_ctx_by_tlli(tlli);
641 if (!mm) {
642 vty_out(vty, "No MM context for TLLI %08x%s",
643 tlli, VTY_NEWLINE);
644 return CMD_WARNING;
645 }
646 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
647 return CMD_SUCCESS;
648}
649#endif
650
651DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
652 "show mm-context imsi IMSI [pdp]",
653 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
654 INCLUDE_PDP_STR)
655{
656 struct sgsn_mm_ctx *mm;
657
658 mm = sgsn_mm_ctx_by_imsi(argv[0]);
659 if (!mm) {
660 vty_out(vty, "No MM context for IMSI %s%s",
661 argv[0], VTY_NEWLINE);
662 return CMD_WARNING;
663 }
Keithc12c1a62021-05-20 04:41:01 +0200664 vty_dump_mmctx(vty, "", mm, (argc > 1) ? 1 : 0);
Harald Welted193cb32010-05-17 22:58:03 +0200665 return CMD_SUCCESS;
666}
667
668DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
669 "show mm-context all [pdp]",
670 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
671{
672 struct sgsn_mm_ctx *mm;
Harald Welted193cb32010-05-17 22:58:03 +0200673 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
Keithc12c1a62021-05-20 04:41:01 +0200674 vty_dump_mmctx(vty, "", mm, (argc > 0) ? 1 : 0);
Harald Welted193cb32010-05-17 22:58:03 +0200675
676 return CMD_SUCCESS;
677}
678
Harald Welted193cb32010-05-17 22:58:03 +0200679DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
680 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100681 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200682{
683 struct sgsn_pdp_ctx *pdp;
684
685 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
686 vty_dump_pdp(vty, "", pdp);
687
688 return CMD_SUCCESS;
689}
Harald Welte288be162010-05-01 16:48:27 +0200690
Harald Welte7f6da482013-03-19 11:00:13 +0100691
692DEFUN(imsi_acl, cfg_imsi_acl_cmd,
693 "imsi-acl (add|del) IMSI",
694 "Access Control List of foreign IMSIs\n"
695 "Add IMSI to ACL\n"
696 "Remove IMSI from ACL\n"
697 "IMSI of subscriber\n")
698{
Maxef38b4c2018-11-20 10:25:53 +0100699 char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS + 1];
Harald Welte7f6da482013-03-19 11:00:13 +0100700 const char *op = argv[0];
Philipp Maier6ee49d82017-02-28 16:53:07 +0100701 const char *imsi = imsi_sanitized;
Maxf4fa6952018-01-15 12:12:51 +0100702 size_t len = strnlen(argv[1], GSM23003_IMSI_MAX_DIGITS + 1);
Harald Welte7f6da482013-03-19 11:00:13 +0100703 int rc;
704
Maxef38b4c2018-11-20 10:25:53 +0100705 memset(imsi_sanitized, '0', GSM23003_IMSI_MAX_DIGITS);
706 imsi_sanitized[GSM23003_IMSI_MAX_DIGITS] = '\0';
707
Philipp Maier6ee49d82017-02-28 16:53:07 +0100708 /* Sanitize IMSI */
Maxf4fa6952018-01-15 12:12:51 +0100709 if (len > GSM23003_IMSI_MAX_DIGITS) {
710 vty_out(vty, "%% IMSI (%s) too long (max %u digits) -- ignored!%s",
711 argv[1], GSM23003_IMSI_MAX_DIGITS, VTY_NEWLINE);
Philipp Maier6ee49d82017-02-28 16:53:07 +0100712 return CMD_WARNING;
713 }
Maxf4fa6952018-01-15 12:12:51 +0100714
715 osmo_strlcpy(imsi_sanitized + GSM23003_IMSI_MAX_DIGITS - len, argv[1],
716 sizeof(imsi_sanitized) - (GSM23003_IMSI_MAX_DIGITS - len));
Philipp Maier6ee49d82017-02-28 16:53:07 +0100717
Harald Welte7f6da482013-03-19 11:00:13 +0100718 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200719 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100720 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200721 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100722
723 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100724 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100725 return CMD_WARNING;
726 }
727
728 return CMD_SUCCESS;
729}
730
Eric2f898262021-05-19 18:57:50 +0200731DEFUN_DEPRECATED(cfg_encrypt, cfg_encrypt_cmd,
Max93408ae2016-06-28 14:10:16 +0200732 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
733 "Set encryption algorithm for SGSN\n"
734 "Use GEA0 (no encryption)\n"
735 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
736{
Max93408ae2016-06-28 14:10:16 +0200737 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
Eric2f898262021-05-19 18:57:50 +0200738
739 if (strcmp(argv[0], "gea") == 0)
740 return CMD_SUCCESS;
741
Max086067f2017-05-02 13:03:28 +0200742 if (c != GPRS_ALGO_GEA0) {
Eric2f898262021-05-19 18:57:50 +0200743 if (gprs_cipher_supported(c) <= 0) {
Max086067f2017-05-02 13:03:28 +0200744 vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
745 return CMD_WARNING;
746 }
747
748 if (!g_cfg->require_authentication) {
749 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
750 argv[0], VTY_NEWLINE);
751 return CMD_WARNING;
752 }
Max93408ae2016-06-28 14:10:16 +0200753 }
754
Eric2f898262021-05-19 18:57:50 +0200755 g_cfg->cipher_support_mask |= (1 << c);
756
757 return CMD_SUCCESS;
758}
759
760DEFUN(cfg_encrypt2, cfg_encrypt2_cmd,
761 "encryption gea <0-4> [<0-4>] [<0-4>] [<0-4>] [<0-4>]",
762 "Set encryption algorithms for SGSN\n"
763 "GPRS Encryption Algorithm\n"
764 "GEAn Algorithm Number\n"
765 "GEAn Algorithm Number\n"
766 "GEAn Algorithm Number\n"
767 "GEAn Algorithm Number\n"
768 "GEAn Algorithm Number\n")
769{
770 int i = 0;
771
772 g_cfg->cipher_support_mask = 0;
773 for (i = 0; i < argc; i++)
774 g_cfg->cipher_support_mask |= (1 << atoi(argv[i]));
775
776 for (i = 0; i < _GPRS_ALGO_NUM; i++) {
777 if (g_cfg->cipher_support_mask >> i & 1) {
778
779 if (i == GPRS_ALGO_GEA0)
780 continue;
781
782 if (gprs_cipher_supported(i) <= 0) {
783 vty_out(vty, "%% cipher %d is unsupported in current version%s", i, VTY_NEWLINE);
784 return CMD_ERR_INCOMPLETE;
785 }
786
787 if (!g_cfg->require_authentication) {
788 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
789 argv[i], VTY_NEWLINE);
790 return CMD_ERR_INCOMPLETE;
791 }
792
793 }
794 }
Max93408ae2016-06-28 14:10:16 +0200795
796 return CMD_SUCCESS;
797}
798
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700799DEFUN(cfg_authentication, cfg_authentication_cmd,
800 "authentication (optional|required)",
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200801 "Whether to enforce MS authentication in GERAN (only with auth-policy remote)\n"
802 "Allow MS to attach via GERAN without authentication (default and only possible value for non-remote auth-policy)\n"
803 "Always require authentication (only available for auth-policy remote, default with that auth-policy)\n")
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700804{
805 int required = (argv[0][0] == 'r');
806
807 if (vty->type != VTY_FILE) {
808 if (g_cfg->auth_policy != SGSN_AUTH_POLICY_REMOTE && required) {
809 vty_out(vty, "%% Authentication is not possible without HLR, "
810 "consider setting 'auth-policy' to 'remote'%s",
811 VTY_NEWLINE);
812 return CMD_WARNING;
813 }
814 }
815
816 g_cfg->require_authentication = required;
817 return CMD_SUCCESS;
818}
819
Harald Welte3dfb5492013-03-19 11:48:54 +0100820DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100821 "auth-policy (accept-all|closed|acl-only|remote)",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100822 "Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
823 " permitted to register to the network.\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100824 "Accept all IMSIs (DANGEROUS)\n"
825 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100826 "Accept only subscribers in the ACL\n"
827 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100828{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100829 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100830 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100831 g_cfg->auth_policy = val;
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100832 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100833
834 return CMD_SUCCESS;
835}
836
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100837/* Subscriber */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +0200838#include <osmocom/sgsn/gprs_subscriber.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100839
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100840static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100841{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100842#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100843 char expire_time[200];
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100844#endif
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100845 struct gsm_auth_tuple *at;
846 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100847 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100848
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100849 vty_out(vty, " Authorized: %d%s",
850 gsub->authorized, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100851 vty_out(vty, " LAC: %d/0x%x%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100852 gsub->lac, gsub->lac, VTY_NEWLINE);
853 vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
854 if (gsub->tmsi != GSM_RESERVED_TMSI)
855 vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100856 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100857 if (gsub->sgsn_data->msisdn_len > 0)
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400858 vty_out(vty, " MSISDN (BCD): %s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100859 osmo_hexdump(gsub->sgsn_data->msisdn,
860 gsub->sgsn_data->msisdn_len),
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400861 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100862
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100863 if (strlen(gsub->imei) > 0)
864 vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100865
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100866 for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100867 at_idx++) {
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100868 at = &gsub->sgsn_data->auth_triplets[at_idx];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100869 if (at->key_seq == GSM_KEY_SEQ_INVAL)
870 continue;
871
872 vty_out(vty, " A3A8 tuple (used %d times): ",
873 at->use_count);
Harald Welte89837d42016-05-06 23:28:11 +0200874 vty_out(vty, " CKSN: %d, ",
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100875 at->key_seq);
Harald Welte89837d42016-05-06 23:28:11 +0200876 if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
877 vty_out(vty, "RAND: %s, ",
Max34604c22019-02-13 14:11:29 +0100878 osmo_hexdump_nospc(at->vec.rand,
Harald Welte89837d42016-05-06 23:28:11 +0200879 sizeof(at->vec.rand)));
880 vty_out(vty, "SRES: %s, ",
Max34604c22019-02-13 14:11:29 +0100881 osmo_hexdump_nospc(at->vec.sres,
Harald Welte89837d42016-05-06 23:28:11 +0200882 sizeof(at->vec.sres)));
883 vty_out(vty, "Kc: %s%s",
Max34604c22019-02-13 14:11:29 +0100884 osmo_hexdump_nospc(at->vec.kc,
Harald Welte89837d42016-05-06 23:28:11 +0200885 sizeof(at->vec.kc)), VTY_NEWLINE);
886 }
887 if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
888 vty_out(vty, " AUTN: %s, ",
889 osmo_hexdump(at->vec.autn,
890 sizeof(at->vec.autn)));
891 vty_out(vty, "RES: %s, ",
Max34604c22019-02-13 14:11:29 +0100892 osmo_hexdump_nospc(at->vec.res, at->vec.res_len));
Harald Welte89837d42016-05-06 23:28:11 +0200893 vty_out(vty, "IK: %s, ",
Max34604c22019-02-13 14:11:29 +0100894 osmo_hexdump_nospc(at->vec.ik, sizeof(at->vec.ik)));
Harald Welte89837d42016-05-06 23:28:11 +0200895 vty_out(vty, "CK: %s, ",
Max34604c22019-02-13 14:11:29 +0100896 osmo_hexdump_nospc(at->vec.ck, sizeof(at->vec.ck)));
Harald Welte89837d42016-05-06 23:28:11 +0200897 }
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100898 }
899
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100900 llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
Max34604c22019-02-13 14:11:29 +0100901 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'",
902 pdp->context_id, pdp->pdp_type, pdp->apn_str);
903
904 if (pdp->qos_subscribed_len)
905 vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len));
906
907 vty_out(vty, "%s", VTY_NEWLINE);
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100908 }
909
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100910#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100911 /* print the expiration time of a subscriber */
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100912 if (gsub->expire_lu) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100913 strftime(expire_time, sizeof(expire_time),
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100914 "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100915 expire_time[sizeof(expire_time) - 1] = '\0';
916 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
917 }
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100918#endif
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100919
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100920 if (gsub->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100921 vty_out(vty, " Flags: %s%s%s%s%s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100922 gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100923 "FIRST_CONTACT " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100924 gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100925 "CANCELLED " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100926 gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100927 "UPDATE_LOCATION_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100928 gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100929 "AUTH_INFO_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100930 gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100931 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100932 VTY_NEWLINE);
933
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100934 vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100935}
936
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200937#define RESET_SGSN_STATE_STR \
938 "Remove all known subscribers, MM contexts and flush BSSGP queues." \
939 " Useful only when running tests against the SGSN\n"
940
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200941DEFUN_HIDDEN(reset_sgsn_state,
942 reset_sgsn_state_cmd,
943 "reset sgsn state",
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200944 RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR)
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200945{
946 struct gprs_subscr *subscr, *tmp_subscr;
947 struct sgsn_mm_ctx *mm, *tmp_mm;
948
949 llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
950 {
951 gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
952 }
953 vty_out(vty, "Cancelled MM Ctx. %s", VTY_NEWLINE);
954
955 llist_for_each_entry_safe(subscr, tmp_subscr, gprs_subscribers, entry) {
956 gprs_subscr_get(subscr);
957 gprs_subscr_cancel(subscr);
958 gprs_subscr_put(subscr);
959 }
960 vty_out(vty, "Removed all gprs subscribers.%s", VTY_NEWLINE);
961
962 bssgp_flush_all_queues();
963 vty_out(vty, "Flushed all BSSGPs queues.%s", VTY_NEWLINE);
964
Alexander Couzens35c34942018-09-17 04:39:14 +0200965 gtp_clear_queues(sgsn->gsn);
Alexander Couzensa66f0f22018-09-18 16:09:18 +0200966 vty_out(vty, "Flushed rx & tx queus towards the GGSN.%s", VTY_NEWLINE);
Alexander Couzens35c34942018-09-17 04:39:14 +0200967
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200968 /* remove all queues to bssgp */
969 return CMD_SUCCESS;
970}
971
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100972DEFUN(show_subscr_cache,
973 show_subscr_cache_cmd,
974 "show subscriber cache",
975 SHOW_STR "Show information about subscribers\n"
976 "Display contents of subscriber cache\n")
977{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100978 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100979
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100980 llist_for_each_entry(subscr, gprs_subscribers, entry) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100981 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
982 subscr_dump_full_vty(vty, subscr, 0);
983 }
984
985 return CMD_SUCCESS;
986}
987
988#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
989#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
990 "Use the IMSI to select the subscriber\n" \
991 "The IMSI\n"
992
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100993#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
994
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100995DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
996 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
997 UPDATE_SUBSCR_HELP
998 UPDATE_SUBSCR_INSERT_HELP
999 "Update authentication triplet\n"
1000 "Triplet index\n"
1001 "Set SRES value\nSRES value (4 byte) in hex\n"
1002 "Set RAND value\nRAND value (16 byte) in hex\n"
1003 "Set Kc value\nKc value (8 byte) in hex\n")
1004{
1005 const char *imsi = argv[0];
1006 const int cksn = atoi(argv[1]) - 1;
1007 const char *sres_str = argv[2];
1008 const char *rand_str = argv[3];
1009 const char *kc_str = argv[4];
1010 struct gsm_auth_tuple at = {0,};
1011
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001012 struct gprs_subscr *subscr;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001013
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001014 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001015 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001016 vty_out(vty, "%% unable get subscriber record for %s%s",
1017 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001018 return CMD_WARNING;
1019 }
1020
1021 OSMO_ASSERT(subscr->sgsn_data);
1022
Harald Welte121e9a42016-04-20 13:13:19 +02001023 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001024 vty_out(vty, "%% invalid SRES value '%s'%s",
1025 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001026 goto failed;
1027 }
Harald Welte121e9a42016-04-20 13:13:19 +02001028 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001029 vty_out(vty, "%% invalid RAND value '%s'%s",
1030 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001031 goto failed;
1032 }
Harald Welte121e9a42016-04-20 13:13:19 +02001033 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001034 vty_out(vty, "%% invalid Kc value '%s'%s",
1035 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001036 goto failed;
1037 }
1038 at.key_seq = cksn;
1039
1040 subscr->sgsn_data->auth_triplets[cksn] = at;
1041 subscr->sgsn_data->auth_triplets_updated = 1;
1042
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001043 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001044
1045 return CMD_SUCCESS;
1046
1047failed:
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001048 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001049 return CMD_SUCCESS;
1050}
1051
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001052DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001053 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001054 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001055 "Cancel (remove) subscriber record\n"
1056 "The MS moved to another SGSN\n"
1057 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001058{
1059 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001060 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001061
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001062 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001063
1064 subscr = gprs_subscr_get_by_imsi(imsi);
1065 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001066 vty_out(vty, "%% no subscriber record for %s%s",
1067 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001068 return CMD_WARNING;
1069 }
1070
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001071 if (strcmp(cancel_type, "update-procedure") == 0)
1072 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
1073 else
1074 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
1075
Jacob Erlbeck37139e52015-01-23 13:52:55 +01001076 gprs_subscr_cancel(subscr);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001077 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001078
1079 return CMD_SUCCESS;
1080}
1081
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001082DEFUN(update_subscr_create, update_subscr_create_cmd,
1083 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001084 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001085 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001086{
1087 const char *imsi = argv[0];
1088
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001089 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001090
1091 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001092 if (subscr) {
1093 vty_out(vty, "%% subscriber record already exists for %s%s",
1094 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001095 return CMD_WARNING;
1096 }
1097
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001098 subscr = gprs_subscr_get_or_create(imsi);
Alexander Couzens3326ba72020-12-09 22:02:55 +01001099 if (!subscr) {
1100 vty_out(vty, "Can not create subscriber. Out of memory.%s", imsi);
1101 return CMD_WARNING;
1102 }
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001103 subscr->keep_in_ram = 1;
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001104 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001105
1106 return CMD_SUCCESS;
1107}
1108
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001109DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
1110 UPDATE_SUBSCR_STR "destroy",
1111 UPDATE_SUBSCR_HELP
1112 "Destroy a subscriber entry\n")
1113{
1114 const char *imsi = argv[0];
1115
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001116 struct gprs_subscr *subscr;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001117
1118 subscr = gprs_subscr_get_by_imsi(imsi);
1119 if (!subscr) {
1120 vty_out(vty, "%% subscriber record does not exist for %s%s",
1121 imsi, VTY_NEWLINE);
1122 return CMD_WARNING;
1123 }
1124
1125 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001126 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001127 gprs_subscr_cancel(subscr);
1128 if (subscr->use_count > 1)
1129 vty_out(vty, "%% subscriber is still in use%s",
1130 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001131 gprs_subscr_put(subscr);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001132
1133 return CMD_SUCCESS;
1134}
1135
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001136#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
1137 "unknown-subscriber|roaming-not-allowed"
1138
1139#define UL_ERR_HELP \
1140 "Force error code SystemFailure\n" \
1141 "Force error code DataMissing\n" \
1142 "Force error code UnexpectedDataValue\n" \
1143 "Force error code UnknownSubscriber\n" \
1144 "Force error code RoamingNotAllowed\n"
1145
1146DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
1147 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
1148 UPDATE_SUBSCR_HELP
1149 "Complete the update location procedure\n"
1150 "The update location request succeeded\n"
1151 UL_ERR_HELP)
1152{
1153 const char *imsi = argv[0];
1154 const char *ret_code_str = argv[1];
1155
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001156 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001157
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001158 const struct value_string cause_mapping[] = {
1159 { GMM_CAUSE_NET_FAIL, "system-failure" },
1160 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
1161 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
1162 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
1163 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
1164 { 0, NULL }
1165 };
1166
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001167 subscr = gprs_subscr_get_by_imsi(imsi);
1168 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001169 vty_out(vty, "%% unable to get subscriber record for %s%s",
1170 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001171 return CMD_WARNING;
1172 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001173
1174 if (strcmp(ret_code_str, "ok") == 0) {
1175 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001176 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001177 } else {
1178 subscr->sgsn_data->error_cause =
1179 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001180 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001181 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001182
1183 gprs_subscr_update(subscr);
1184
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001185 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001186
1187 return CMD_SUCCESS;
1188}
1189
1190DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
1191 UPDATE_SUBSCR_STR "update-auth-info",
1192 UPDATE_SUBSCR_HELP
1193 "Complete the send authentication info procedure\n")
1194{
1195 const char *imsi = argv[0];
1196
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001197 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001198
1199 subscr = gprs_subscr_get_by_imsi(imsi);
1200 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001201 vty_out(vty, "%% unable to get subscriber record for %s%s",
1202 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001203 return CMD_WARNING;
1204 }
1205
1206 gprs_subscr_update_auth_info(subscr);
1207
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001208 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001209
1210 return CMD_SUCCESS;
1211}
1212
Oliver Smithab39b622021-07-05 15:41:05 +02001213DEFUN(page_subscr, page_subscr_info_cmd,
1214 "page imsi IMSI",
1215 "Send a PS paging request to subscriber\n"
1216 "Use the IMSI to select the subscriber\n"
1217 "The IMSI\n")
1218{
1219 const char *imsi = argv[0];
1220 struct sgsn_mm_ctx *mm;
1221
1222 mm = sgsn_mm_ctx_by_imsi(imsi);
1223 if (!mm) {
1224 vty_out(vty, "No MM context for IMSI %s%s", imsi, VTY_NEWLINE);
1225 return CMD_WARNING;
1226 }
1227
1228 gprs_gb_page_ps_ra(mm);
1229 return CMD_SUCCESS;
1230}
1231
Stefan Sperling88220092018-12-11 14:42:00 +01001232DEFUN(cfg_gsup_ipa_name,
1233 cfg_gsup_ipa_name_cmd,
1234 "gsup ipa-name NAME",
1235 "GSUP Parameters\n"
1236 "Set the IPA name of this SGSN\n"
1237 "A unique name for this SGSN. For example: PLMN + redundancy server number: SGSN-901-70-0. "
1238 "This name is used for GSUP routing and must be set if more than one SGSN is connected to the network. "
1239 "The default is 'SGSN-00-00-00-00-00-00'.\n")
1240{
1241 if (vty->type != VTY_FILE) {
1242 vty_out(vty, "The IPA name cannot be changed at run-time; "
1243 "It can only be set in the configuraton file.%s", VTY_NEWLINE);
1244 return CMD_WARNING;
1245 }
1246
1247 g_cfg->sgsn_ipa_name = talloc_strdup(tall_vty_ctx, argv[0]);
1248 return CMD_SUCCESS;
1249}
1250
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001251DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
1252 "gsup remote-ip A.B.C.D",
1253 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001254 "Set the IP address of the remote GSUP server (e.g. OsmoHLR)."
1255 " This setting only applies if 'auth-policy remote' is used.\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001256 "IPv4 Address\n")
1257{
1258 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
1259
1260 return CMD_SUCCESS;
1261}
1262
1263DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
1264 "gsup remote-port <0-65535>",
1265 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001266 "Set the TCP port of the remote GSUP server, see also 'gsup remote-ip'\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001267 "Remote TCP port\n")
1268{
1269 g_cfg->gsup_server_port = atoi(argv[0]);
1270
1271 return CMD_SUCCESS;
1272}
1273
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001274DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
1275 "gsup oap-id <0-65535>",
1276 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001277 "Set the OAP client ID for authentication on the GSUP protocol."
1278 " This setting only applies if 'auth-policy remote' is used.\n"
1279 "OAP client ID (0 == disabled)\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001280{
1281 /* VTY ensures range */
1282 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
1283 return CMD_SUCCESS;
1284}
1285
1286DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
1287 "gsup oap-k K",
1288 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001289 "Set the OAP shared secret key K for authentication on the GSUP protocol."
1290 " This setting only applies if auth-policy remote is used.\n"
1291 "K value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001292{
1293 const char *k = argv[0];
1294
1295 g_cfg->oap.secret_k_present = 0;
1296
1297 if ((!k) || (strlen(k) == 0))
1298 goto disable;
1299
1300 int k_len = osmo_hexparse(k,
1301 g_cfg->oap.secret_k,
1302 sizeof(g_cfg->oap.secret_k));
1303 if (k_len != 16) {
1304 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
1305 k_len, VTY_NEWLINE);
1306 goto disable;
1307 }
1308
1309 g_cfg->oap.secret_k_present = 1;
1310 return CMD_SUCCESS;
1311
1312disable:
1313 if (g_cfg->oap.client_id > 0) {
1314 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
1315 VTY_NEWLINE);
1316 return CMD_WARNING;
1317 }
1318 return CMD_SUCCESS;
1319}
1320
1321DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1322 "gsup oap-opc OPC",
1323 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001324 "Set the OAP shared secret OPC for authentication on the GSUP protocol."
1325 " This setting only applies if auth-policy remote is used.\n"
1326 "OPC value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001327{
1328 const char *opc = argv[0];
1329
1330 g_cfg->oap.secret_opc_present = 0;
1331
1332 if ((!opc) || (strlen(opc) == 0))
1333 goto disable;
1334
1335 int opc_len = osmo_hexparse(opc,
1336 g_cfg->oap.secret_opc,
1337 sizeof(g_cfg->oap.secret_opc));
1338 if (opc_len != 16) {
1339 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1340 opc_len, VTY_NEWLINE);
1341 goto disable;
1342 }
1343
1344 g_cfg->oap.secret_opc_present = 1;
1345 return CMD_SUCCESS;
1346
1347disable:
1348 if (g_cfg->oap.client_id > 0) {
1349 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1350 VTY_NEWLINE);
1351 return CMD_WARNING;
1352 }
1353 return CMD_SUCCESS;
1354}
1355
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001356DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1357 "access-point-name NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001358 "Globally allow the given APN name for all subscribers.\n"
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001359 "Add this NAME to the list\n")
1360{
1361 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1362}
1363
1364DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1365 "no access-point-name NAME",
1366 NO_STR "Configure a global list of allowed APNs\n"
1367 "Remove entry with NAME\n")
1368{
1369 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1370 if (!apn_ctx)
1371 return CMD_SUCCESS;
1372
1373 sgsn_apn_ctx_free(apn_ctx);
1374 return CMD_SUCCESS;
1375}
1376
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001377DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1378 "cdr filename NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001379 "CDR\n"
1380 "Set the file name for the call-data-record file, logging the data usage of each subscriber.\n"
1381 "filename\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001382{
1383 talloc_free(g_cfg->cdr.filename);
1384 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1385 return CMD_SUCCESS;
1386}
1387
1388DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1389 "no cdr filename",
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001390 NO_STR "CDR\nDisable saving CDR to file\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001391{
1392 talloc_free(g_cfg->cdr.filename);
1393 g_cfg->cdr.filename = NULL;
1394 return CMD_SUCCESS;
1395}
1396
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001397DEFUN(cfg_cdr_trap, cfg_cdr_trap_cmd,
1398 "cdr trap",
1399 "CDR\nEnable sending CDR via TRAP CTRL messages\n")
1400{
1401 g_cfg->cdr.trap = true;
1402 return CMD_SUCCESS;
1403}
1404
1405DEFUN(cfg_no_cdr_trap, cfg_no_cdr_trap_cmd,
1406 "no cdr trap",
1407 NO_STR "CDR\nDisable sending CDR via TRAP CTRL messages\n")
1408{
1409 g_cfg->cdr.trap = false;
1410 return CMD_SUCCESS;
1411}
1412
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001413DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1414 "cdr interval <1-2147483647>",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001415 "CDR\n"
1416 "Set the interval for the call-data-record file\n"
1417 "interval in seconds\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001418{
1419 g_cfg->cdr.interval = atoi(argv[0]);
1420 return CMD_SUCCESS;
1421}
1422
Philippf1f34362016-08-26 17:00:21 +02001423#define COMPRESSION_STR "Configure compression\n"
1424DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1425 "no compression rfc1144",
1426 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1427{
1428 g_cfg->pcomp_rfc1144.active = 0;
1429 g_cfg->pcomp_rfc1144.passive = 0;
1430 return CMD_SUCCESS;
1431}
1432
1433DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1434 "compression rfc1144 active slots <1-256>",
1435 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001436 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001437 "Compression is actively proposed\n"
1438 "Number of compression state slots\n"
1439 "Number of compression state slots\n")
1440{
1441 g_cfg->pcomp_rfc1144.active = 1;
1442 g_cfg->pcomp_rfc1144.passive = 1;
1443 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1444 return CMD_SUCCESS;
1445}
1446
1447DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1448 "compression rfc1144 passive",
1449 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001450 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001451 "Compression is available on request\n")
1452{
1453 g_cfg->pcomp_rfc1144.active = 0;
1454 g_cfg->pcomp_rfc1144.passive = 1;
1455 return CMD_SUCCESS;
1456}
1457
Philipp73f83d52016-09-02 13:38:01 +02001458DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
1459 "no compression v42bis",
1460 NO_STR COMPRESSION_STR "disable V.42bis data compression\n")
1461{
1462 g_cfg->dcomp_v42bis.active = 0;
1463 g_cfg->dcomp_v42bis.passive = 0;
1464 return CMD_SUCCESS;
1465}
1466
1467DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
1468 "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
1469 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001470 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001471 "Compression is actively proposed\n"
1472 "Direction in which the compression shall be active (p0)\n"
1473 "Compress ms->sgsn direction only\n"
1474 "Compress sgsn->ms direction only\n"
1475 "Both directions\n"
1476 "Number of codewords (p1)\n"
1477 "Number of codewords\n"
1478 "Maximum string length (p2)\n" "Maximum string length\n")
1479{
1480 g_cfg->dcomp_v42bis.active = 1;
1481 g_cfg->dcomp_v42bis.passive = 1;
1482
1483 switch (argv[0][0]) {
1484 case 'm':
1485 g_cfg->dcomp_v42bis.p0 = 1;
1486 break;
1487 case 's':
1488 g_cfg->dcomp_v42bis.p0 = 2;
1489 break;
1490 case 'b':
1491 g_cfg->dcomp_v42bis.p0 = 3;
1492 break;
1493 }
1494
1495 g_cfg->dcomp_v42bis.p1 = atoi(argv[1]);
1496 g_cfg->dcomp_v42bis.p2 = atoi(argv[2]);
1497 return CMD_SUCCESS;
1498}
1499
1500DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
1501 "compression v42bis passive",
1502 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001503 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001504 "Compression is available on request\n")
1505{
1506 g_cfg->dcomp_v42bis.active = 0;
1507 g_cfg->dcomp_v42bis.passive = 1;
1508 return CMD_SUCCESS;
1509}
1510
Pau Espin Pedrol2c908992019-08-19 19:06:06 +02001511#if BUILD_IU
1512DEFUN(cfg_sgsn_cs7_instance_iu,
1513 cfg_sgsn_cs7_instance_iu_cmd,
1514 "cs7-instance-iu <0-15>",
1515 "Set SS7 to be used by the Iu-Interface.\n" "SS7 instance reference number (default: 0)\n")
1516{
1517 g_cfg->iu.cs7_instance = atoi(argv[0]);
1518 return CMD_SUCCESS;
1519}
1520#endif
1521
Pau Espin Pedrole5c89982021-05-03 18:16:42 +02001522DEFUN(cfg_sgsn_mme, cfg_sgsn_mme_cmd,
1523 "mme NAME",
1524 "Configure an MME peer\n"
1525 "Name identifying the MME peer\n")
1526{
1527 struct sgsn_mme_ctx *mme;
1528
1529 mme = sgsn_mme_ctx_find_alloc(sgsn, argv[0]);
1530 if (!mme)
1531 return CMD_WARNING;
1532
1533 vty->node = MME_NODE;
1534 vty->index = mme;
1535
1536 return CMD_SUCCESS;
1537}
1538
1539DEFUN(cfg_sgsn_no_mme, cfg_sgsn_no_mme_cmd,
1540 "no mme NAME",
1541 NO_STR "Delete an MME peer configuration\n"
1542 "Name identifying the MME peer\n")
1543{
1544 struct sgsn_mme_ctx *mme;
1545
1546 mme = sgsn_mme_ctx_by_name(sgsn, argv[0]);
1547 if (!mme) {
1548 vty_out(vty, "%% MME %s doesn't exist.%s",
1549 argv[0], VTY_NEWLINE);
1550 return CMD_WARNING;
1551 }
1552
1553 sgsn_mme_ctx_free(mme);
1554
1555 return CMD_SUCCESS;
1556}
1557
1558#define GTP_STR "Configure GTP connection\n"
1559
1560DEFUN(cfg_mme_remote_ip, cfg_mme_remote_ip_cmd,
1561 "gtp remote-ip A.B.C.D",
1562 GTP_STR "Set Remote GTP IP address\n" IP_STR)
1563{
1564 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1565
1566 inet_aton(argv[0], &mme->remote_addr);
1567
1568 return CMD_SUCCESS;
1569}
1570
1571#define RAN_INFO_STR "Configure RAN Information Relay routing\n"
1572#define TAI_DOC "MCC\n" "MNC\n" "TAC\n"
1573
1574DEFUN(cfg_mme_ran_info_relay_tai, cfg_mme_ran_info_relay_tai_cmd,
1575 "gtp ran-info-relay <0-999> <0-999> <0-65535>",
1576 GTP_STR RAN_INFO_STR TAI_DOC)
1577{
1578 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1579 struct sgsn_mme_ctx *mme_tmp;
1580 struct osmo_eutran_tai tai;
1581
1582 const char *mcc = argv[0];
1583 const char *mnc = argv[1];
1584 const char *tac = argv[2];
1585
1586 if (osmo_mcc_from_str(mcc, &tai.mcc)) {
1587 vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
1588 return CMD_WARNING;
1589 }
1590 if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
1591 vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
1592 return CMD_WARNING;
1593 }
1594 tai.tac = atoi(tac);
1595
1596 if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
1597 if (mme_tmp != mme) {
1598 vty_out(vty, "%% Another MME %s already contains this route%s",
1599 mme_tmp->name, VTY_NEWLINE);
1600 return CMD_WARNING;
1601 }
1602 /* else: NO-OP, return */
1603 return CMD_SUCCESS;
1604 }
1605
1606 sgsn_mme_ctx_route_add(mme, &tai);
1607 return CMD_SUCCESS;
1608}
1609
1610DEFUN(cfg_mme_no_ran_info_relay_tai, cfg_mme_no_ran_info_relay_tai_cmd,
1611 "no gtp ran-info-relay <0-999> <0-999> <0-65535>",
1612 NO_STR GTP_STR RAN_INFO_STR TAI_DOC)
1613{
1614 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1615 struct sgsn_mme_ctx *mme_tmp;
1616 struct osmo_eutran_tai tai;
1617
1618 const char *mcc = argv[0];
1619 const char *mnc = argv[1];
1620 const char *tac = argv[2];
1621
1622 if (osmo_mcc_from_str(mcc, &tai.mcc)) {
1623 vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
1624 return CMD_WARNING;
1625 }
1626 if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
1627 vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
1628 return CMD_WARNING;
1629 }
1630 tai.tac = atoi(tac);
1631
1632 if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
1633 if (mme_tmp != mme) {
1634 vty_out(vty, "%% Another MME %s contains this route%s",
1635 mme_tmp->name, VTY_NEWLINE);
1636 return CMD_WARNING;
1637 }
1638 sgsn_mme_ctx_route_del(mme, &tai);
1639 return CMD_SUCCESS;
1640 } else {
1641 vty_out(vty, "%% This route doesn't exist in current MME %s%s",
1642 mme->name, VTY_NEWLINE);
1643 return CMD_WARNING;
1644 }
1645}
1646
1647DEFUN(cfg_mme_ran_info_relay_default, cfg_mme_ran_info_relay_default_cmd,
1648 "gtp ran-info-relay default",
1649 GTP_STR RAN_INFO_STR "Set as default route")
1650{
1651 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1652 struct sgsn_mme_ctx *default_mme;
1653
1654 if (mme->default_route)
1655 return CMD_SUCCESS; /* NO-OP */
1656
1657 if ((default_mme = sgsn_mme_ctx_by_default_route(sgsn))) {
1658 vty_out(vty, "%% Another MME %s is already set as default route, "
1659 "remove it before setting it here.%s",
1660 default_mme->name, VTY_NEWLINE);
1661 return CMD_WARNING;
1662 }
1663
1664 mme->default_route = true;
1665 return CMD_SUCCESS;
1666}
1667
1668DEFUN(cfg_mme_no_ran_info_relay_default, cfg_mme_no_ran_info_relay_default_cmd,
1669 "no gtp ran-info-relay default",
1670 NO_STR GTP_STR RAN_INFO_STR "Set as default route")
1671{
1672 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1673 mme->default_route = false;
1674 return CMD_SUCCESS;
1675}
1676
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001677int sgsn_vty_init(struct sgsn_config *cfg)
Harald Welte288be162010-05-01 16:48:27 +02001678{
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001679 g_cfg = cfg;
1680
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001681 g_cfg->T_defs = sgsn_T_defs;
1682 osmo_tdefs_reset(g_cfg->T_defs);
1683
Harald Welted193cb32010-05-17 22:58:03 +02001684 install_element_ve(&show_sgsn_cmd);
1685 //install_element_ve(&show_mmctx_tlli_cmd);
1686 install_element_ve(&show_mmctx_imsi_cmd);
1687 install_element_ve(&show_mmctx_all_cmd);
1688 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001689 install_element_ve(&show_subscr_cache_cmd);
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001690 install_element_ve(&show_timer_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001691
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001692 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001693 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001694 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001695 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001696 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1697 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Oliver Smithab39b622021-07-05 15:41:05 +02001698 install_element(ENABLE_NODE, &page_subscr_info_cmd);
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001699 install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001700
1701 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1702 install_node(&sgsn_node, config_write_sgsn);
Keithc70e8382020-10-19 22:24:48 +02001703 install_element(SGSN_NODE, &cfg_sgsn_state_dir_cmd);
Harald Weltee300d002010-06-02 12:41:34 +02001704 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001705 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1706 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1707 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +02001708 install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +02001709 install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001710 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001711 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Vadim Yanitskiy794f4462019-05-27 05:39:06 +07001712 install_element(SGSN_NODE, &cfg_authentication_cmd);
Eric2f898262021-05-19 18:57:50 +02001713
1714 /* order matters here: ensure we attempt to parse our new command first! */
1715 install_element(SGSN_NODE, &cfg_encrypt2_cmd);
Max93408ae2016-06-28 14:10:16 +02001716 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Eric2f898262021-05-19 18:57:50 +02001717
Stefan Sperling88220092018-12-11 14:42:00 +01001718 install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001719 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1720 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001721 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1722 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1723 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001724 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1725 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001726 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1727 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001728 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1729 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001730 install_element(SGSN_NODE, &cfg_cdr_trap_cmd);
1731 install_element(SGSN_NODE, &cfg_no_cdr_trap_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001732 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001733 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001734 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001735
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001736 install_element(SGSN_NODE, &cfg_sgsn_timer_cmd);
Harald Welte94508822015-08-15 19:08:21 +02001737
Philippf1f34362016-08-26 17:00:21 +02001738 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1739 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1740 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
Philipp73f83d52016-09-02 13:38:01 +02001741 install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd);
1742 install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
1743 install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001744
Pau Espin Pedrole5c89982021-05-03 18:16:42 +02001745 install_element(SGSN_NODE, &cfg_sgsn_mme_cmd);
1746 install_element(SGSN_NODE, &cfg_sgsn_no_mme_cmd);
1747 install_node(&mme_node, NULL);
1748 install_element(MME_NODE, &cfg_mme_remote_ip_cmd);
1749 install_element(MME_NODE, &cfg_mme_ran_info_relay_default_cmd);
1750 install_element(MME_NODE, &cfg_mme_no_ran_info_relay_default_cmd);
1751 install_element(MME_NODE, &cfg_mme_ran_info_relay_tai_cmd);
1752 install_element(MME_NODE, &cfg_mme_no_ran_info_relay_tai_cmd);
1753
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001754#ifdef BUILD_IU
Pau Espin Pedrol2c908992019-08-19 19:06:06 +02001755 install_element(SGSN_NODE, &cfg_sgsn_cs7_instance_iu_cmd);
Neels Hofmeyra7a39472017-07-05 15:19:52 +02001756 ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001757#endif
Harald Welte288be162010-05-01 16:48:27 +02001758 return 0;
1759}
1760
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001761int sgsn_parse_config(const char *config_file)
Harald Welte288be162010-05-01 16:48:27 +02001762{
1763 int rc;
1764
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001765 /* make sure sgsn_vty_init() was called before this */
1766 OSMO_ASSERT(g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +01001767
Eric2f898262021-05-19 18:57:50 +02001768 g_cfg->cipher_support_mask = 0x1; /* support GEA0 by default unless specific encryption config exists */
1769
Harald Weltedcccb182010-05-16 20:52:23 +02001770 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001771 if (rc < 0) {
1772 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1773 return rc;
1774 }
1775
Neels Hofmeyr27355c92017-02-24 06:28:31 +01001776 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE
1777 && !(g_cfg->gsup_server_addr.sin_addr.s_addr
1778 && g_cfg->gsup_server_port)) {
1779 fprintf(stderr, "Configuration error:"
1780 " 'auth-policy remote' requires both"
1781 " 'gsup remote-ip' and 'gsup remote-port'\n");
1782 return -EINVAL;
1783 }
1784
Harald Welte288be162010-05-01 16:48:27 +02001785 return 0;
1786}