blob: 18951f8e299647791682486e310d8960f8a38871 [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>
Pau Espin Pedrol4398ac02022-12-23 17:12:39 +010038#include <osmocom/sgsn/gprs_ns.h>
Alexander Couzensc503f0a2018-08-07 17:50:04 +020039#include <osmocom/sgsn/gprs_gmm.h>
Pau Espin Pedrol7a74ae42022-12-23 16:33:17 +010040#include <osmocom/sgsn/gprs_bssgp.h>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020041#include <osmocom/sgsn/gprs_sgsn.h>
Pau Espin Pedrol5f4736a2023-01-04 21:30:28 +010042#include <osmocom/sgsn/gtp_ggsn.h>
Pau Espin Pedrole5c89982021-05-03 18:16:42 +020043#include <osmocom/sgsn/gtp_mme.h>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020044#include <osmocom/sgsn/vty.h>
Harald Weltef4b2c4c2018-09-16 07:53:41 +020045#include <osmocom/gsupclient/gsup_client.h>
Harald Welte288be162010-05-01 16:48:27 +020046
Pau Espin Pedrola299d652019-08-14 19:11:10 +020047#include <osmocom/vty/tdef_vty.h>
Harald Welte4b037e42010-05-19 19:45:32 +020048#include <osmocom/vty/command.h>
49#include <osmocom/vty/vty.h>
Pablo Neira Ayuso6110a3f2011-03-28 19:35:00 +020050#include <osmocom/vty/misc.h>
Max93408ae2016-06-28 14:10:16 +020051#include <osmocom/crypt/gprs_cipher.h>
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +010052#include <osmocom/crypt/utran_cipher.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010053#include <osmocom/abis/ipa.h>
54
Alexander Couzensc503f0a2018-08-07 17:50:04 +020055#include <osmocom/gprs/gprs_bssgp.h>
56
Harald Welted193cb32010-05-17 22:58:03 +020057#include <pdp.h>
Maxbaabc682017-10-20 13:39:57 +020058#include <gtp.h>
Harald Welted193cb32010-05-17 22:58:03 +020059
Neels Hofmeyr2188a772016-05-20 21:59:55 +020060#include "../../bscconfig.h"
61
62#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +020063#include <osmocom/ranap/iu_client.h>
Neels Hofmeyr2188a772016-05-20 21:59:55 +020064#endif
65
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +010066extern void *tall_sgsn_ctx;
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020067
Harald Welte288be162010-05-01 16:48:27 +020068static struct sgsn_config *g_cfg = NULL;
69
Jacob Erlbeck106f5472014-11-04 10:08:37 +010070const struct value_string sgsn_auth_pol_strs[] = {
71 { SGSN_AUTH_POLICY_OPEN, "accept-all" },
72 { SGSN_AUTH_POLICY_CLOSED, "closed" },
73 { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" },
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +010074 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeck106f5472014-11-04 10:08:37 +010075 { 0, NULL }
76};
77
Harald Welte94508822015-08-15 19:08:21 +020078/* Section 11.2.2 / Table 11.3a GPRS Mobility management timers – MS side */
79#define GSM0408_T3312_SECS (10*60) /* periodic RAU interval, default 54min */
80
81/* Section 11.2.2 / Table 11.4 MM timers netwokr side */
82#define GSM0408_T3322_SECS 6 /* DETACH_REQ -> DETACH_ACC */
83#define GSM0408_T3350_SECS 6 /* waiting for ATT/RAU/TMSI COMPL */
84#define GSM0408_T3360_SECS 6 /* waiting for AUTH/CIPH RESP */
85#define GSM0408_T3370_SECS 6 /* waiting for ID RESP */
86
Alexander Couzens5ba6fb32017-01-31 18:04:27 +010087/* Section 11.2.2 / Table 11.4a MM timers network side */
Harald Welte94508822015-08-15 19:08:21 +020088#define GSM0408_T3313_SECS 30 /* waiting for paging response */
89#define GSM0408_T3314_SECS 44 /* force to STBY on expiry, Ready timer */
90#define GSM0408_T3316_SECS 44
91
92/* Section 11.3 / Table 11.2d Timers of Session Management - network side */
93#define GSM0408_T3385_SECS 8 /* wait for ACT PDP CTX REQ */
94#define GSM0408_T3386_SECS 8 /* wait for MODIFY PDP CTX ACK */
95#define GSM0408_T3395_SECS 8 /* wait for DEACT PDP CTX ACK */
96#define GSM0408_T3397_SECS 8 /* wait for DEACT AA PDP CTX ACK */
97
Alexander Couzensafadd102019-10-08 14:30:59 +020098/* Non spec timer */
99#define NONSPEC_X1001_SECS 5 /* wait for a RANAP Release Complete */
100
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200101
102static struct osmo_tdef sgsn_T_defs[] = {
103 { .T=3312, .default_val=GSM0408_T3312_SECS, .desc="Periodic RA Update timer (s)" },
104 { .T=3313, .default_val=GSM0408_T3313_SECS, .desc="Waiting for paging response timer (s)" },
Alexander Couzens39cbecd2017-02-03 22:16:05 +0100105 { .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 +0200106 { .T=3316, .default_val=GSM0408_T3316_SECS, .desc="AA-Ready timer (s)" },
107 { .T=3322, .default_val=GSM0408_T3322_SECS, .desc="Detach request -> accept timer (s)" },
108 { .T=3350, .default_val=GSM0408_T3350_SECS, .desc="Waiting for ATT/RAU/TMSI_COMPL timer (s)" },
109 { .T=3360, .default_val=GSM0408_T3360_SECS, .desc="Waiting for AUTH/CIPH response timer (s)" },
110 { .T=3370, .default_val=GSM0408_T3370_SECS, .desc="Waiting for IDENTITY response timer (s)" },
111 { .T=3385, .default_val=GSM0408_T3385_SECS, .desc="Wait for ACT PDP CTX REQ timer (s)" },
112 { .T=3386, .default_val=GSM0408_T3386_SECS, .desc="Wait for MODIFY PDP CTX ACK timer (s)" },
113 { .T=3395, .default_val=GSM0408_T3395_SECS, .desc="Wait for DEACT PDP CTX ACK timer (s)" },
114 { .T=3397, .default_val=GSM0408_T3397_SECS, .desc="Wait for DEACT AA PDP CTX ACK timer (s)" },
Alexander Couzens3bad31b2019-09-11 02:17:31 +0200115 /* non spec timers */
Alexander Couzensafadd102019-10-08 14:30:59 +0200116 { .T=-1001, .default_val=NONSPEC_X1001_SECS, .desc="RANAP Release timeout. Wait for RANAP Release Complete."
117 "On expiry release Iu connection (s)" },
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200118 {}
119};
120
121DEFUN(show_timer, show_timer_cmd,
122 "show timer " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
123 SHOW_STR "Show timers\n"
124 OSMO_TDEF_VTY_DOC_T)
125{
126 const char *T_arg = argc > 0 ? argv[0] : NULL;
127 return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs, T_arg, NULL);
Harald Welte94508822015-08-15 19:08:21 +0200128}
129
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200130DEFUN(cfg_sgsn_timer, cfg_sgsn_timer_cmd,
131 "timer " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
132 "Configure or show timers\n"
133 OSMO_TDEF_VTY_DOC_SET)
134{
135 /* If any arguments are missing, redirect to 'show' */
136 if (argc < 2)
137 return show_timer(self, vty, argc, argv);
138 return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs, argv);
139}
Harald Welte94508822015-08-15 19:08:21 +0200140
Pau Espin Pedrol85011262022-11-02 20:23:09 +0100141DEFUN(show_timer_gtp, show_timer_gtp_cmd,
142 "show timer gtp " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
143 SHOW_STR "Show timers\n" "GTP (libgtp) timers\n"
144 OSMO_TDEF_VTY_DOC_T)
145{
146 const char *T_arg = argc > 0 ? argv[0] : NULL;
147 return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs_gtp, T_arg, NULL);
148}
149
150DEFUN(cfg_sgsn_timer_gtp, cfg_sgsn_timer_gtp_cmd,
151 "timer gtp " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
152 "Configure or show timers\n" "GTP (libgtp) timers\n"
153 OSMO_TDEF_VTY_DOC_SET)
154{
155 /* If any arguments are missing, redirect to 'show' */
156 if (argc < 2)
157 return show_timer(self, vty, argc, argv);
158 return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs_gtp, argv);
159}
160
Keith6cee1a12021-09-29 21:00:04 +0200161char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6)
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200162{
163 static char str[INET6_ADDRSTRLEN + 10];
164
165 if (!pdpa || len < 2)
166 return "none";
167
168 switch (pdpa[0] & 0x0f) {
169 case PDP_TYPE_ORG_IETF:
170 switch (pdpa[1]) {
171 case PDP_TYPE_N_IETF_IPv4:
172 if (len < 2 + 4)
173 break;
Keith6cee1a12021-09-29 21:00:04 +0200174 osmo_strlcpy(str, "IPv4 ", sizeof(str));
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200175 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
176 return str;
177 case PDP_TYPE_N_IETF_IPv6:
178 if (len < 2 + 8)
179 break;
Keith6cee1a12021-09-29 21:00:04 +0200180 osmo_strlcpy(str, "IPv6 ", sizeof(str));
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200181 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
182 return str;
Keith6cee1a12021-09-29 21:00:04 +0200183 case PDP_TYPE_N_IETF_IPv4v6:
184 if (len < 2 + 20)
185 break;
186 if (return_ipv6) {
187 /* The IPv6 token, (rightmost four fields) is a duplicate of
188 * the site prefix + subnetID (leftmost fields) in pdpa here */
189 osmo_strlcpy(str, "IPv6 ", sizeof(str));
190 inet_ntop(AF_INET6, pdpa+6, str+5, sizeof(str)-5);
191 return str;
192 }
193 osmo_strlcpy(str, "IPv4 ", sizeof(str));
194 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
195 return str;
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200196 default:
197 break;
198 }
199 break;
200 case PDP_TYPE_ORG_ETSI:
201 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
202 return "PPP";
203 break;
204 default:
205 break;
206 }
207
208 return "invalid";
209}
210
Harald Welte288be162010-05-01 16:48:27 +0200211static struct cmd_node sgsn_node = {
212 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200213 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200214 1,
215};
216
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200217static struct cmd_node mme_node = {
218 MME_NODE,
219 "%s(config-sgsn-mme)# ",
220 1,
221};
222
223static void config_write_mme(struct vty *vty, const struct sgsn_mme_ctx *mme, const char *prefix)
224{
225 struct mme_rim_route *rt;
226
227 vty_out(vty, "%smme %s%s", prefix, mme->name, VTY_NEWLINE);
228
229 vty_out(vty, "%s gtp remote-ip %s%s", prefix, inet_ntoa(mme->remote_addr), VTY_NEWLINE);
230 if (mme->default_route)
231 vty_out(vty, "%s gtp ran-info-relay default%s", prefix, VTY_NEWLINE);
232 llist_for_each_entry(rt, &mme->routes, list) {
233 vty_out(vty, "%s gtp ran-info-relay %s %s %u%s", prefix,
234 osmo_mcc_name(rt->tai.mcc), osmo_mnc_name(rt->tai.mnc, rt->tai.mnc_3_digits),
235 rt->tai.tac, VTY_NEWLINE);
236 }
237}
238
Harald Welte288be162010-05-01 16:48:27 +0200239static int config_write_sgsn(struct vty *vty)
240{
Harald Welte77289c22010-05-18 14:32:29 +0200241 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100242 struct imsi_acl_entry *acl;
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100243 struct apn_ctx *actx;
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800244 struct ares_addr_node *server;
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200245 struct sgsn_mme_ctx *mme;
Eric2f898262021-05-19 18:57:50 +0200246 int i;
Harald Welte288be162010-05-01 16:48:27 +0200247
248 vty_out(vty, "sgsn%s", VTY_NEWLINE);
249
Keithc70e8382020-10-19 22:24:48 +0200250 vty_out(vty, " gtp state-dir %s%s",
251 g_cfg->gtp_statedir, VTY_NEWLINE);
Harald Weltee300d002010-06-02 12:41:34 +0200252 vty_out(vty, " gtp local-ip %s%s",
253 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
254
Harald Welted193cb32010-05-17 22:58:03 +0200255 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800256 if (gctx->id == UINT32_MAX)
257 continue;
258
Harald Welteff3bde82010-05-19 15:09:09 +0200259 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200260 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200261 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200262 gctx->gtp_version, VTY_NEWLINE);
Pau Espin Pedrolaa89f5d2019-08-28 16:08:45 +0200263 if (gctx->echo_interval)
264 vty_out(vty, " ggsn %u echo-interval %u%s",
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200265 gctx->id, gctx->echo_interval, VTY_NEWLINE);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200266 else
267 vty_out(vty, " ggsn %u no echo-interval%s",
268 gctx->id, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200269 }
270
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800271 if (sgsn->cfg.dynamic_lookup)
272 vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE);
273
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800274 for (server = sgsn->ares_servers; server; server = server->next)
275 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
276
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100277 if (g_cfg->gea_encryption_mask != 0) {
Eric2f898262021-05-19 18:57:50 +0200278 vty_out(vty, " encryption gea");
279
280 for (i = 0; i < _GPRS_ALGO_NUM; i++)
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100281 if (g_cfg->gea_encryption_mask >> i & 1)
Eric2f898262021-05-19 18:57:50 +0200282 vty_out(vty, " %u", i);
283
284 vty_out(vty, "%s", VTY_NEWLINE);
285 }
Stefan Sperling88220092018-12-11 14:42:00 +0100286 if (g_cfg->sgsn_ipa_name)
287 vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100288 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
289 vty_out(vty, " gsup remote-ip %s%s",
290 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
291 if (g_cfg->gsup_server_port)
292 vty_out(vty, " gsup remote-port %d%s",
293 g_cfg->gsup_server_port, VTY_NEWLINE);
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200294 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE && !g_cfg->require_authentication)
295 vty_out(vty, " authentication optional%s", VTY_NEWLINE);
Max176b62a2016-07-04 11:09:07 +0200296 vty_out(vty, " auth-policy %s%s",
297 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
298 VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200299
300 vty_out(vty, " gsup oap-id %d%s",
301 (int)g_cfg->oap.client_id, VTY_NEWLINE);
302 if (g_cfg->oap.secret_k_present != 0)
303 vty_out(vty, " gsup oap-k %s%s",
304 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
305 VTY_NEWLINE);
306 if (g_cfg->oap.secret_opc_present != 0)
307 vty_out(vty, " gsup oap-opc %s%s",
308 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
309 VTY_NEWLINE);
310
Harald Welte7f6da482013-03-19 11:00:13 +0100311 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
312 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
313
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100314 if (llist_empty(&sgsn_apn_ctxts))
315 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
316 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
317 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200318 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100319 actx->name, actx->imsi_prefix, actx->ggsn->id,
320 VTY_NEWLINE);
321 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200322 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100323 actx->ggsn->id, VTY_NEWLINE);
324 }
325
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200326 if (g_cfg->cdr.filename)
327 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
328 else
329 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +0100330 if (g_cfg->cdr.trap)
331 vty_out(vty, " cdr trap%s", VTY_NEWLINE);
332 else
333 vty_out(vty, " no cdr trap%s", VTY_NEWLINE);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200334 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
335
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200336 osmo_tdef_vty_write(vty, g_cfg->T_defs, " timer ");
Pau Espin Pedrol85011262022-11-02 20:23:09 +0100337 osmo_tdef_vty_write(vty, g_cfg->T_defs_gtp, " timer gtp ");
Harald Welte94508822015-08-15 19:08:21 +0200338
Philippf1f34362016-08-26 17:00:21 +0200339 if (g_cfg->pcomp_rfc1144.active) {
340 vty_out(vty, " compression rfc1144 active slots %d%s",
341 g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE);
342 } else if (g_cfg->pcomp_rfc1144.passive) {
343 vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE);
344 } else
345 vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE);
346
Philipp73f83d52016-09-02 13:38:01 +0200347 if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) {
348 vty_out(vty,
349 " compression v42bis active direction sgsn codewords %d strlen %d%s",
350 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
351 VTY_NEWLINE);
352 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) {
353 vty_out(vty,
354 " compression v42bis active direction ms codewords %d strlen %d%s",
355 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
356 VTY_NEWLINE);
357 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) {
358 vty_out(vty,
359 " compression v42bis active direction both codewords %d strlen %d%s",
360 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
361 VTY_NEWLINE);
362 } else if (g_cfg->dcomp_v42bis.passive) {
363 vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE);
364 } else
365 vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
366
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200367 llist_for_each_entry(mme, &sgsn->mme_list, list) {
368 config_write_mme(vty, mme, " ");
369 }
370
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200371#ifdef BUILD_IU
Pau Espin Pedrol2c908992019-08-19 19:06:06 +0200372 vty_out(vty, " cs7-instance-iu %u%s", g_cfg->iu.cs7_instance,
373 VTY_NEWLINE);
Neels Hofmeyra7a39472017-07-05 15:19:52 +0200374 ranap_iu_vty_config_write(vty, " ");
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200375#endif
376
Harald Welte288be162010-05-01 16:48:27 +0200377 return CMD_SUCCESS;
378}
379
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100380#define SGSN_STR "Configure the SGSN\n"
381#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200382
383DEFUN(cfg_sgsn, cfg_sgsn_cmd,
384 "sgsn",
385 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200386{
387 vty->node = SGSN_NODE;
388 return CMD_SUCCESS;
389}
390
Keithc70e8382020-10-19 22:24:48 +0200391DEFUN(cfg_sgsn_state_dir, cfg_sgsn_state_dir_cmd,
392 "gtp state-dir PATH",
393 "GTP Parameters\n"
394 "Set the directory for the GTP State file\n"
395 "Local Directory\n")
396{
397 osmo_talloc_replace_string(sgsn, &sgsn->cfg.gtp_statedir, argv[0]);
398
399 return CMD_SUCCESS;
400}
401
Harald Weltee300d002010-06-02 12:41:34 +0200402DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
403 "gtp local-ip A.B.C.D",
404 "GTP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100405 "Set the IP address for the local GTP bind for the Gp interface (towards the GGSNs)."
406 " Note: in case you would like to run the GGSN on the same machine as the SGSN, you can not run"
407 " both on the same IP address, since both sides are specified to use the same GTP port numbers"
408 " (" OSMO_STRINGIFY_VAL(GTP1C_PORT) " and " OSMO_STRINGIFY_VAL(GTP1U_PORT) ")."
409 " For example, you could use 127.0.0.1 for the SGSN and 127.0.0.2 for the GGSN in such"
410 " situations.\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100411 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200412{
413 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
414
415 return CMD_SUCCESS;
416}
417
Harald Welted193cb32010-05-17 22:58:03 +0200418DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
419 "ggsn <0-255> remote-ip A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100420 GGSN_STR "GGSN Number\n"
421 "Configure this static GGSN to use the specified remote IP address.\n"
422 "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200423{
424 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200425 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200426
Harald Welted193cb32010-05-17 22:58:03 +0200427 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200428
Harald Welted193cb32010-05-17 22:58:03 +0200429 return CMD_SUCCESS;
430}
431
432#if 0
433DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
434 "ggsn <0-255> remote-port <0-65535>",
435 "")
436{
437 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200438 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200439 uint16_t port = atoi(argv[1]);
440
441}
442#endif
443
444DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
445 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100446 GGSN_STR "GGSN Number\n" "GTP Version\n"
447 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200448{
449 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200450 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200451
452 if (atoi(argv[1]))
453 ggc->gtp_version = 1;
454 else
455 ggc->gtp_version = 0;
456
457 return CMD_SUCCESS;
458}
459
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200460/* Seee 3GPP TS 29.060 section 7.2.1 */
461DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
462 "ggsn <0-255> echo-interval <1-36000>",
463 GGSN_STR "GGSN Number\n"
464 "Send an echo request to this static GGSN every interval.\n"
465 "Interval between echo requests in seconds.\n")
466{
467 uint32_t id = atoi(argv[0]);
468 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
469
470 ggc->echo_interval = atoi(argv[1]);
471
472 if (ggc->echo_interval < 60)
Pau Espin Pedrolba2e5002019-05-27 17:35:32 +0200473 vty_out(vty, "%% 3GPP TS 29.060 section 7.2.1 states interval should " \
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200474 "not be lower than 60 seconds, use this value for " \
475 "testing purposes only!%s", VTY_NEWLINE);
476
Alexander Couzens176a4d22018-09-18 20:07:37 +0200477 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200478 return CMD_SUCCESS;
479}
480
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200481DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
482 "ggsn <0-255> no echo-interval",
483 GGSN_STR "GGSN Number\n"
484 NO_STR "Send an echo request to this static GGSN every interval.\n")
485{
486 uint32_t id = atoi(argv[0]);
487 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
488
Pau Espin Pedrolaa89f5d2019-08-28 16:08:45 +0200489 ggc->echo_interval = 0;
Alexander Couzens176a4d22018-09-18 20:07:37 +0200490 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200491
492 return CMD_SUCCESS;
493}
494
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800495DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
496 "ggsn dynamic",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100497 GGSN_STR
498 "Enable dynamic resolving of GGSNs based on DNS resolving the APN name like in a GRX-style setup."
499 " Changing this setting requires a restart.\n")
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800500{
501 sgsn->cfg.dynamic_lookup = 1;
502 return CMD_SUCCESS;
503}
504
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800505DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
506 "grx-dns-add A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100507 "Use the specified IP address for DNS-resolving the AP names to GGSN IP addresses\n"
508 "IPv4 address\n")
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800509{
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +0100510 struct ares_addr_node *node = talloc_zero(tall_sgsn_ctx, struct ares_addr_node);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800511 node->family = AF_INET;
512 inet_aton(argv[0], &node->addr.addr4);
513
514 node->next = sgsn->ares_servers;
515 sgsn->ares_servers = node;
516 return CMD_SUCCESS;
517}
518
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100519#define APN_STR "Configure the information per APN\n"
520#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
521
522static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
523 const char *imsi_prefix, int ggsn_id)
524{
525 struct apn_ctx *actx;
526 struct sgsn_ggsn_ctx *ggsn;
527
528 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
529 if (ggsn == NULL) {
530 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
531 ggsn_id, VTY_NEWLINE);
532 return CMD_WARNING;
533 }
534
535 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
536 if (!actx) {
537 vty_out(vty, "%% unable to create APN context for %s/%s%s",
538 apn_str, imsi_prefix, VTY_NEWLINE);
539 return CMD_WARNING;
540 }
541
542 actx->ggsn = ggsn;
543
544 return CMD_SUCCESS;
545}
546
Harald Welted193cb32010-05-17 22:58:03 +0200547DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
548 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100549 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100550 "Select the GGSN to use for the given APN gateway prefix\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100551 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200552{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100553
554 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200555}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100556
557DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
558 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
559 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100560 "Select the GGSN to use for the given APN gateway prefix if and only if the IMSI matches the"
561 " given prefix.\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100562 "An IMSI prefix\n"
563 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
564 "The GGSN id")
565{
566
567 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
568}
Harald Welted193cb32010-05-17 22:58:03 +0200569
Maxc005db72017-10-27 18:43:29 +0200570char *sgsn_gtp_ntoa(struct ul16_t *ul)
Harald Welte471ac7d2016-12-15 19:48:58 +0100571{
Max8492c202017-12-05 17:28:15 +0100572 struct in_addr ia;
573
574 if (gsna2in_addr(&ia, ul) != 0)
Harald Welte471ac7d2016-12-15 19:48:58 +0100575 return "UNKNOWN";
Max8492c202017-12-05 17:28:15 +0100576
577 return inet_ntoa(ia);
Harald Welte471ac7d2016-12-15 19:48:58 +0100578}
579
Harald Welted193cb32010-05-17 22:58:03 +0200580static void vty_dump_pdp(struct vty *vty, const char *pfx,
581 struct sgsn_pdp_ctx *pdp)
582{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200583 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welte471ac7d2016-12-15 19:48:58 +0100584 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s",
585 pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200586 if (pdp->lib) {
Max7933d962017-10-19 16:52:30 +0200587 char apnbuf[APN_MAXLEN + 1];
Harald Weltedfbd2c82017-08-13 00:56:45 +0200588 vty_out(vty, "%s APN: %s%s", pfx,
Max7933d962017-10-19 16:52:30 +0200589 osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200590 VTY_NEWLINE);
591 vty_out(vty, "%s PDP Address: %s%s", pfx,
Keith6cee1a12021-09-29 21:00:04 +0200592 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, false),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200593 VTY_NEWLINE);
Keith6cee1a12021-09-29 21:00:04 +0200594 if (pdp->lib->eua.v[1] == PDP_TYPE_N_IETF_IPv4v6) {
595 vty_out(vty, "%s PDP Address: %s%s", pfx,
596 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, true),
597 VTY_NEWLINE);
598 }
Maxb24af2b2017-12-05 17:54:42 +0100599 vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200600 sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200601 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200602 sgsn_gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100603 vty_out(vty, "%s GTPv%d Remote Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200604 sgsn_gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200605 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200606 sgsn_gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200607 }
Harald Welte471ac7d2016-12-15 19:48:58 +0100608
Harald Welteefbdee92010-06-10 00:20:12 +0200609 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200610}
611
612static void vty_dump_mmctx(struct vty *vty, const char *pfx,
613 struct sgsn_mm_ctx *mm, int pdp)
614{
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200615 uint32_t id = 0;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200616 const char *mm_state_name = NULL;
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200617
618 switch(mm->ran_type) {
619 case MM_CTX_T_UTRAN_Iu:
620#if BUILD_IU
621 id = mm->iu.ue_ctx->conn_id;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200622 mm_state_name = osmo_fsm_inst_state_name(mm->iu.mm_state_fsm);
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200623#endif
624 break;
625 case MM_CTX_T_GERAN_Gb:
626 id = mm->gb.tlli;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200627 mm_state_name = osmo_fsm_inst_state_name(mm->gb.mm_state_fsm);
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200628 break;
629 }
630
Harald Welted193cb32010-05-17 22:58:03 +0200631 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
632 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200633 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200634 pfx, mm->msisdn, id, mm->hlr, VTY_NEWLINE);
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200635 vty_out(vty, "%s GMM State: %s, Routeing Area: %s, Cell ID: %u%s",
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200636 pfx, osmo_fsm_inst_state_name(mm->gmm_fsm),
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100637 osmo_rai_name(&mm->ra), mm->gb.cell_id, VTY_NEWLINE);
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200638 vty_out(vty, "%s MM State: %s, RAN Type: %s%s", pfx, mm_state_name,
639 get_value_string(sgsn_ran_type_names, mm->ran_type), VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200640
Pau Espin Pedrol3b848bd2019-08-30 18:06:35 +0200641 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
Harald Welte8acd88f2010-05-18 10:57:45 +0200642
Harald Welted193cb32010-05-17 22:58:03 +0200643 if (pdp) {
644 struct sgsn_pdp_ctx *pdp;
645
646 llist_for_each_entry(pdp, &mm->pdp_list, list)
647 vty_dump_pdp(vty, " ", pdp);
648 }
649}
650
651DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
652 SHOW_STR "Display information about the SGSN")
653{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100654 if (sgsn->gsup_client) {
655 struct ipa_client_conn *link = sgsn->gsup_client->link;
656 vty_out(vty,
657 " Remote authorization: %sconnected to %s:%d via GSUP%s",
658 sgsn->gsup_client->is_connected ? "" : "not ",
659 link->addr, link->port,
660 VTY_NEWLINE);
661 }
Maxbaabc682017-10-20 13:39:57 +0200662 if (sgsn->gsn)
663 vty_out(vty, " GSN: signalling %s, user traffic %s%s",
664 inet_ntoa(sgsn->gsn->gsnc), inet_ntoa(sgsn->gsn->gsnu), VTY_NEWLINE);
665
Harald Welted193cb32010-05-17 22:58:03 +0200666 /* FIXME: statistics */
667 return CMD_SUCCESS;
668}
669
670#define MMCTX_STR "MM Context\n"
671#define INCLUDE_PDP_STR "Include PDP Context Information\n"
672
673#if 0
674DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
675 "show mm-context tlli HEX [pdp]",
676 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
677{
678 uint32_t tlli;
679 struct sgsn_mm_ctx *mm;
680
681 tlli = strtoul(argv[0], NULL, 16);
682 mm = sgsn_mm_ctx_by_tlli(tlli);
683 if (!mm) {
684 vty_out(vty, "No MM context for TLLI %08x%s",
685 tlli, VTY_NEWLINE);
686 return CMD_WARNING;
687 }
688 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
689 return CMD_SUCCESS;
690}
691#endif
692
693DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
694 "show mm-context imsi IMSI [pdp]",
695 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
696 INCLUDE_PDP_STR)
697{
698 struct sgsn_mm_ctx *mm;
699
700 mm = sgsn_mm_ctx_by_imsi(argv[0]);
701 if (!mm) {
702 vty_out(vty, "No MM context for IMSI %s%s",
703 argv[0], VTY_NEWLINE);
704 return CMD_WARNING;
705 }
Keithc12c1a62021-05-20 04:41:01 +0200706 vty_dump_mmctx(vty, "", mm, (argc > 1) ? 1 : 0);
Harald Welted193cb32010-05-17 22:58:03 +0200707 return CMD_SUCCESS;
708}
709
710DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
711 "show mm-context all [pdp]",
712 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
713{
714 struct sgsn_mm_ctx *mm;
Harald Welted193cb32010-05-17 22:58:03 +0200715 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
Keithc12c1a62021-05-20 04:41:01 +0200716 vty_dump_mmctx(vty, "", mm, (argc > 0) ? 1 : 0);
Harald Welted193cb32010-05-17 22:58:03 +0200717
718 return CMD_SUCCESS;
719}
720
Harald Welted193cb32010-05-17 22:58:03 +0200721DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
722 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100723 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200724{
725 struct sgsn_pdp_ctx *pdp;
726
727 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
728 vty_dump_pdp(vty, "", pdp);
729
730 return CMD_SUCCESS;
731}
Harald Welte288be162010-05-01 16:48:27 +0200732
Harald Welte7f6da482013-03-19 11:00:13 +0100733
734DEFUN(imsi_acl, cfg_imsi_acl_cmd,
735 "imsi-acl (add|del) IMSI",
736 "Access Control List of foreign IMSIs\n"
737 "Add IMSI to ACL\n"
738 "Remove IMSI from ACL\n"
739 "IMSI of subscriber\n")
740{
Maxef38b4c2018-11-20 10:25:53 +0100741 char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS + 1];
Harald Welte7f6da482013-03-19 11:00:13 +0100742 const char *op = argv[0];
Philipp Maier6ee49d82017-02-28 16:53:07 +0100743 const char *imsi = imsi_sanitized;
Maxf4fa6952018-01-15 12:12:51 +0100744 size_t len = strnlen(argv[1], GSM23003_IMSI_MAX_DIGITS + 1);
Harald Welte7f6da482013-03-19 11:00:13 +0100745 int rc;
746
Maxef38b4c2018-11-20 10:25:53 +0100747 memset(imsi_sanitized, '0', GSM23003_IMSI_MAX_DIGITS);
748 imsi_sanitized[GSM23003_IMSI_MAX_DIGITS] = '\0';
749
Philipp Maier6ee49d82017-02-28 16:53:07 +0100750 /* Sanitize IMSI */
Maxf4fa6952018-01-15 12:12:51 +0100751 if (len > GSM23003_IMSI_MAX_DIGITS) {
752 vty_out(vty, "%% IMSI (%s) too long (max %u digits) -- ignored!%s",
753 argv[1], GSM23003_IMSI_MAX_DIGITS, VTY_NEWLINE);
Philipp Maier6ee49d82017-02-28 16:53:07 +0100754 return CMD_WARNING;
755 }
Maxf4fa6952018-01-15 12:12:51 +0100756
757 osmo_strlcpy(imsi_sanitized + GSM23003_IMSI_MAX_DIGITS - len, argv[1],
758 sizeof(imsi_sanitized) - (GSM23003_IMSI_MAX_DIGITS - len));
Philipp Maier6ee49d82017-02-28 16:53:07 +0100759
Harald Welte7f6da482013-03-19 11:00:13 +0100760 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200761 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100762 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200763 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100764
765 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100766 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100767 return CMD_WARNING;
768 }
769
770 return CMD_SUCCESS;
771}
772
Eric2f898262021-05-19 18:57:50 +0200773DEFUN_DEPRECATED(cfg_encrypt, cfg_encrypt_cmd,
Max93408ae2016-06-28 14:10:16 +0200774 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
775 "Set encryption algorithm for SGSN\n"
776 "Use GEA0 (no encryption)\n"
777 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
778{
Max93408ae2016-06-28 14:10:16 +0200779 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
Eric2f898262021-05-19 18:57:50 +0200780
781 if (strcmp(argv[0], "gea") == 0)
782 return CMD_SUCCESS;
783
Max086067f2017-05-02 13:03:28 +0200784 if (c != GPRS_ALGO_GEA0) {
Eric2f898262021-05-19 18:57:50 +0200785 if (gprs_cipher_supported(c) <= 0) {
Max086067f2017-05-02 13:03:28 +0200786 vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
787 return CMD_WARNING;
788 }
789
790 if (!g_cfg->require_authentication) {
791 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
792 argv[0], VTY_NEWLINE);
793 return CMD_WARNING;
794 }
Max93408ae2016-06-28 14:10:16 +0200795 }
796
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100797 g_cfg->gea_encryption_mask |= (1 << c);
Eric2f898262021-05-19 18:57:50 +0200798
799 return CMD_SUCCESS;
800}
801
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +0100802#define ENCRYPTION_STR "Set encryption algorithms for SGSN\n"
803
Eric2f898262021-05-19 18:57:50 +0200804DEFUN(cfg_encrypt2, cfg_encrypt2_cmd,
805 "encryption gea <0-4> [<0-4>] [<0-4>] [<0-4>] [<0-4>]",
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +0100806 ENCRYPTION_STR
Eric2f898262021-05-19 18:57:50 +0200807 "GPRS Encryption Algorithm\n"
808 "GEAn Algorithm Number\n"
809 "GEAn Algorithm Number\n"
810 "GEAn Algorithm Number\n"
811 "GEAn Algorithm Number\n"
812 "GEAn Algorithm Number\n")
813{
814 int i = 0;
815
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100816 g_cfg->gea_encryption_mask = 0;
Eric2f898262021-05-19 18:57:50 +0200817 for (i = 0; i < argc; i++)
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100818 g_cfg->gea_encryption_mask |= (1 << atoi(argv[i]));
Eric2f898262021-05-19 18:57:50 +0200819
820 for (i = 0; i < _GPRS_ALGO_NUM; i++) {
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100821 if (g_cfg->gea_encryption_mask >> i & 1) {
Eric2f898262021-05-19 18:57:50 +0200822
823 if (i == GPRS_ALGO_GEA0)
824 continue;
825
826 if (gprs_cipher_supported(i) <= 0) {
827 vty_out(vty, "%% cipher %d is unsupported in current version%s", i, VTY_NEWLINE);
828 return CMD_ERR_INCOMPLETE;
829 }
830
831 if (!g_cfg->require_authentication) {
832 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
833 argv[i], VTY_NEWLINE);
834 return CMD_ERR_INCOMPLETE;
835 }
836
837 }
838 }
Max93408ae2016-06-28 14:10:16 +0200839
840 return CMD_SUCCESS;
841}
842
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700843DEFUN(cfg_authentication, cfg_authentication_cmd,
844 "authentication (optional|required)",
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200845 "Whether to enforce MS authentication in GERAN (only with auth-policy remote)\n"
846 "Allow MS to attach via GERAN without authentication (default and only possible value for non-remote auth-policy)\n"
847 "Always require authentication (only available for auth-policy remote, default with that auth-policy)\n")
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700848{
849 int required = (argv[0][0] == 'r');
850
851 if (vty->type != VTY_FILE) {
852 if (g_cfg->auth_policy != SGSN_AUTH_POLICY_REMOTE && required) {
853 vty_out(vty, "%% Authentication is not possible without HLR, "
854 "consider setting 'auth-policy' to 'remote'%s",
855 VTY_NEWLINE);
856 return CMD_WARNING;
857 }
858 }
859
860 g_cfg->require_authentication = required;
861 return CMD_SUCCESS;
862}
863
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +0100864DEFUN(cfg_encryption_uea, cfg_encryption_uea_cmd,
865 "encryption uea <0-2> [<0-2>] [<0-2>]",
866 ENCRYPTION_STR
867 "UTRAN (3G) encryption algorithms to allow: 0 = UEA0 (no encryption), 1 = UEA1, 2 = UEA2.\n"
868 "UEAn Algorithm Number\n"
869 "UEAn Algorithm Number\n"
870 "UEAn Algorithm Number\n")
871{
872 unsigned int i;
873
874 g_cfg->uea_encryption_mask = 0;
875 for (i = 0; i < argc; i++)
876 g_cfg->uea_encryption_mask |= (1 << atoi(argv[i]));
877
878 return CMD_SUCCESS;
879}
880
Harald Welte3dfb5492013-03-19 11:48:54 +0100881DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100882 "auth-policy (accept-all|closed|acl-only|remote)",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100883 "Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
884 " permitted to register to the network.\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100885 "Accept all IMSIs (DANGEROUS)\n"
886 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100887 "Accept only subscribers in the ACL\n"
888 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100889{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100890 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100891 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100892 g_cfg->auth_policy = val;
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100893 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100894
895 return CMD_SUCCESS;
896}
897
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100898/* Subscriber */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +0200899#include <osmocom/sgsn/gprs_subscriber.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100900
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100901static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100902{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100903#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100904 char expire_time[200];
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100905#endif
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100906 struct gsm_auth_tuple *at;
907 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100908 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100909
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100910 vty_out(vty, " Authorized: %d%s",
911 gsub->authorized, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100912 vty_out(vty, " LAC: %d/0x%x%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100913 gsub->lac, gsub->lac, VTY_NEWLINE);
914 vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
915 if (gsub->tmsi != GSM_RESERVED_TMSI)
916 vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100917 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100918 if (gsub->sgsn_data->msisdn_len > 0)
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400919 vty_out(vty, " MSISDN (BCD): %s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100920 osmo_hexdump(gsub->sgsn_data->msisdn,
921 gsub->sgsn_data->msisdn_len),
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400922 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100923
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100924 if (strlen(gsub->imei) > 0)
925 vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100926
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100927 for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100928 at_idx++) {
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100929 at = &gsub->sgsn_data->auth_triplets[at_idx];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100930 if (at->key_seq == GSM_KEY_SEQ_INVAL)
931 continue;
932
933 vty_out(vty, " A3A8 tuple (used %d times): ",
934 at->use_count);
Harald Welte89837d42016-05-06 23:28:11 +0200935 vty_out(vty, " CKSN: %d, ",
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100936 at->key_seq);
Harald Welte89837d42016-05-06 23:28:11 +0200937 if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
938 vty_out(vty, "RAND: %s, ",
Max34604c22019-02-13 14:11:29 +0100939 osmo_hexdump_nospc(at->vec.rand,
Harald Welte89837d42016-05-06 23:28:11 +0200940 sizeof(at->vec.rand)));
941 vty_out(vty, "SRES: %s, ",
Max34604c22019-02-13 14:11:29 +0100942 osmo_hexdump_nospc(at->vec.sres,
Harald Welte89837d42016-05-06 23:28:11 +0200943 sizeof(at->vec.sres)));
944 vty_out(vty, "Kc: %s%s",
Max34604c22019-02-13 14:11:29 +0100945 osmo_hexdump_nospc(at->vec.kc,
Harald Welte89837d42016-05-06 23:28:11 +0200946 sizeof(at->vec.kc)), VTY_NEWLINE);
947 }
948 if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
949 vty_out(vty, " AUTN: %s, ",
950 osmo_hexdump(at->vec.autn,
951 sizeof(at->vec.autn)));
952 vty_out(vty, "RES: %s, ",
Max34604c22019-02-13 14:11:29 +0100953 osmo_hexdump_nospc(at->vec.res, at->vec.res_len));
Harald Welte89837d42016-05-06 23:28:11 +0200954 vty_out(vty, "IK: %s, ",
Max34604c22019-02-13 14:11:29 +0100955 osmo_hexdump_nospc(at->vec.ik, sizeof(at->vec.ik)));
Harald Welte89837d42016-05-06 23:28:11 +0200956 vty_out(vty, "CK: %s, ",
Max34604c22019-02-13 14:11:29 +0100957 osmo_hexdump_nospc(at->vec.ck, sizeof(at->vec.ck)));
Harald Welte89837d42016-05-06 23:28:11 +0200958 }
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100959 }
960
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100961 llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
Max34604c22019-02-13 14:11:29 +0100962 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'",
963 pdp->context_id, pdp->pdp_type, pdp->apn_str);
964
965 if (pdp->qos_subscribed_len)
966 vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len));
967
968 vty_out(vty, "%s", VTY_NEWLINE);
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100969 }
970
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100971#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100972 /* print the expiration time of a subscriber */
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100973 if (gsub->expire_lu) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100974 strftime(expire_time, sizeof(expire_time),
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100975 "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100976 expire_time[sizeof(expire_time) - 1] = '\0';
977 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
978 }
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100979#endif
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100980
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100981 if (gsub->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100982 vty_out(vty, " Flags: %s%s%s%s%s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100983 gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100984 "FIRST_CONTACT " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100985 gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100986 "CANCELLED " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100987 gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100988 "UPDATE_LOCATION_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100989 gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100990 "AUTH_INFO_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100991 gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100992 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100993 VTY_NEWLINE);
994
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100995 vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100996}
997
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200998#define RESET_SGSN_STATE_STR \
999 "Remove all known subscribers, MM contexts and flush BSSGP queues." \
1000 " Useful only when running tests against the SGSN\n"
1001
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001002DEFUN_HIDDEN(reset_sgsn_state,
1003 reset_sgsn_state_cmd,
1004 "reset sgsn state",
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +02001005 RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR)
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001006{
1007 struct gprs_subscr *subscr, *tmp_subscr;
1008 struct sgsn_mm_ctx *mm, *tmp_mm;
1009
1010 llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
1011 {
1012 gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
1013 }
1014 vty_out(vty, "Cancelled MM Ctx. %s", VTY_NEWLINE);
1015
1016 llist_for_each_entry_safe(subscr, tmp_subscr, gprs_subscribers, entry) {
1017 gprs_subscr_get(subscr);
1018 gprs_subscr_cancel(subscr);
1019 gprs_subscr_put(subscr);
1020 }
1021 vty_out(vty, "Removed all gprs subscribers.%s", VTY_NEWLINE);
1022
1023 bssgp_flush_all_queues();
1024 vty_out(vty, "Flushed all BSSGPs queues.%s", VTY_NEWLINE);
1025
Alexander Couzens35c34942018-09-17 04:39:14 +02001026 gtp_clear_queues(sgsn->gsn);
Alexander Couzensa66f0f22018-09-18 16:09:18 +02001027 vty_out(vty, "Flushed rx & tx queus towards the GGSN.%s", VTY_NEWLINE);
Alexander Couzens35c34942018-09-17 04:39:14 +02001028
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001029 /* remove all queues to bssgp */
1030 return CMD_SUCCESS;
1031}
1032
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001033DEFUN(show_subscr_cache,
1034 show_subscr_cache_cmd,
1035 "show subscriber cache",
1036 SHOW_STR "Show information about subscribers\n"
1037 "Display contents of subscriber cache\n")
1038{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001039 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001040
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001041 llist_for_each_entry(subscr, gprs_subscribers, entry) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001042 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
1043 subscr_dump_full_vty(vty, subscr, 0);
1044 }
1045
1046 return CMD_SUCCESS;
1047}
1048
1049#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
1050#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
1051 "Use the IMSI to select the subscriber\n" \
1052 "The IMSI\n"
1053
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001054#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
1055
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001056DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
1057 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
1058 UPDATE_SUBSCR_HELP
1059 UPDATE_SUBSCR_INSERT_HELP
1060 "Update authentication triplet\n"
1061 "Triplet index\n"
1062 "Set SRES value\nSRES value (4 byte) in hex\n"
1063 "Set RAND value\nRAND value (16 byte) in hex\n"
1064 "Set Kc value\nKc value (8 byte) in hex\n")
1065{
1066 const char *imsi = argv[0];
1067 const int cksn = atoi(argv[1]) - 1;
1068 const char *sres_str = argv[2];
1069 const char *rand_str = argv[3];
1070 const char *kc_str = argv[4];
1071 struct gsm_auth_tuple at = {0,};
1072
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001073 struct gprs_subscr *subscr;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001074
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001075 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001076 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001077 vty_out(vty, "%% unable get subscriber record for %s%s",
1078 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001079 return CMD_WARNING;
1080 }
1081
1082 OSMO_ASSERT(subscr->sgsn_data);
1083
Harald Welte121e9a42016-04-20 13:13:19 +02001084 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001085 vty_out(vty, "%% invalid SRES value '%s'%s",
1086 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001087 goto failed;
1088 }
Harald Welte121e9a42016-04-20 13:13:19 +02001089 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001090 vty_out(vty, "%% invalid RAND value '%s'%s",
1091 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001092 goto failed;
1093 }
Harald Welte121e9a42016-04-20 13:13:19 +02001094 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001095 vty_out(vty, "%% invalid Kc value '%s'%s",
1096 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001097 goto failed;
1098 }
1099 at.key_seq = cksn;
1100
1101 subscr->sgsn_data->auth_triplets[cksn] = at;
1102 subscr->sgsn_data->auth_triplets_updated = 1;
1103
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001104 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001105
1106 return CMD_SUCCESS;
1107
1108failed:
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001109 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001110 return CMD_SUCCESS;
1111}
1112
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001113DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001114 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001115 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001116 "Cancel (remove) subscriber record\n"
1117 "The MS moved to another SGSN\n"
1118 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001119{
1120 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001121 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001122
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001123 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001124
1125 subscr = gprs_subscr_get_by_imsi(imsi);
1126 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001127 vty_out(vty, "%% no subscriber record for %s%s",
1128 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001129 return CMD_WARNING;
1130 }
1131
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001132 if (strcmp(cancel_type, "update-procedure") == 0)
1133 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
1134 else
1135 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
1136
Jacob Erlbeck37139e52015-01-23 13:52:55 +01001137 gprs_subscr_cancel(subscr);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001138 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001139
1140 return CMD_SUCCESS;
1141}
1142
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001143DEFUN(update_subscr_create, update_subscr_create_cmd,
1144 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001145 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001146 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001147{
1148 const char *imsi = argv[0];
1149
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001150 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001151
1152 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001153 if (subscr) {
1154 vty_out(vty, "%% subscriber record already exists for %s%s",
1155 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001156 return CMD_WARNING;
1157 }
1158
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001159 subscr = gprs_subscr_get_or_create(imsi);
Alexander Couzens3326ba72020-12-09 22:02:55 +01001160 if (!subscr) {
1161 vty_out(vty, "Can not create subscriber. Out of memory.%s", imsi);
1162 return CMD_WARNING;
1163 }
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001164 subscr->keep_in_ram = 1;
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001165 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001166
1167 return CMD_SUCCESS;
1168}
1169
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001170DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
1171 UPDATE_SUBSCR_STR "destroy",
1172 UPDATE_SUBSCR_HELP
1173 "Destroy a subscriber entry\n")
1174{
1175 const char *imsi = argv[0];
1176
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001177 struct gprs_subscr *subscr;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001178
1179 subscr = gprs_subscr_get_by_imsi(imsi);
1180 if (!subscr) {
1181 vty_out(vty, "%% subscriber record does not exist for %s%s",
1182 imsi, VTY_NEWLINE);
1183 return CMD_WARNING;
1184 }
1185
1186 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001187 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001188 gprs_subscr_cancel(subscr);
1189 if (subscr->use_count > 1)
1190 vty_out(vty, "%% subscriber is still in use%s",
1191 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001192 gprs_subscr_put(subscr);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001193
1194 return CMD_SUCCESS;
1195}
1196
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001197#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
1198 "unknown-subscriber|roaming-not-allowed"
1199
1200#define UL_ERR_HELP \
1201 "Force error code SystemFailure\n" \
1202 "Force error code DataMissing\n" \
1203 "Force error code UnexpectedDataValue\n" \
1204 "Force error code UnknownSubscriber\n" \
1205 "Force error code RoamingNotAllowed\n"
1206
1207DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
1208 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
1209 UPDATE_SUBSCR_HELP
1210 "Complete the update location procedure\n"
1211 "The update location request succeeded\n"
1212 UL_ERR_HELP)
1213{
1214 const char *imsi = argv[0];
1215 const char *ret_code_str = argv[1];
1216
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001217 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001218
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001219 const struct value_string cause_mapping[] = {
1220 { GMM_CAUSE_NET_FAIL, "system-failure" },
1221 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
1222 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
1223 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
1224 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
1225 { 0, NULL }
1226 };
1227
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001228 subscr = gprs_subscr_get_by_imsi(imsi);
1229 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001230 vty_out(vty, "%% unable to get subscriber record for %s%s",
1231 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001232 return CMD_WARNING;
1233 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001234
1235 if (strcmp(ret_code_str, "ok") == 0) {
1236 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001237 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001238 } else {
1239 subscr->sgsn_data->error_cause =
1240 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001241 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001242 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001243
1244 gprs_subscr_update(subscr);
1245
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001246 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001247
1248 return CMD_SUCCESS;
1249}
1250
1251DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
1252 UPDATE_SUBSCR_STR "update-auth-info",
1253 UPDATE_SUBSCR_HELP
1254 "Complete the send authentication info procedure\n")
1255{
1256 const char *imsi = argv[0];
1257
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001258 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001259
1260 subscr = gprs_subscr_get_by_imsi(imsi);
1261 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001262 vty_out(vty, "%% unable to get subscriber record for %s%s",
1263 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001264 return CMD_WARNING;
1265 }
1266
1267 gprs_subscr_update_auth_info(subscr);
1268
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001269 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001270
1271 return CMD_SUCCESS;
1272}
1273
Oliver Smithab39b622021-07-05 15:41:05 +02001274DEFUN(page_subscr, page_subscr_info_cmd,
1275 "page imsi IMSI",
1276 "Send a PS paging request to subscriber\n"
1277 "Use the IMSI to select the subscriber\n"
1278 "The IMSI\n")
1279{
1280 const char *imsi = argv[0];
1281 struct sgsn_mm_ctx *mm;
1282
1283 mm = sgsn_mm_ctx_by_imsi(imsi);
1284 if (!mm) {
1285 vty_out(vty, "No MM context for IMSI %s%s", imsi, VTY_NEWLINE);
1286 return CMD_WARNING;
1287 }
1288
Pau Espin Pedrol7a74ae42022-12-23 16:33:17 +01001289 sgsn_bssgp_page_ps_ra(mm);
Oliver Smithab39b622021-07-05 15:41:05 +02001290 return CMD_SUCCESS;
1291}
1292
Stefan Sperling88220092018-12-11 14:42:00 +01001293DEFUN(cfg_gsup_ipa_name,
1294 cfg_gsup_ipa_name_cmd,
1295 "gsup ipa-name NAME",
1296 "GSUP Parameters\n"
1297 "Set the IPA name of this SGSN\n"
1298 "A unique name for this SGSN. For example: PLMN + redundancy server number: SGSN-901-70-0. "
1299 "This name is used for GSUP routing and must be set if more than one SGSN is connected to the network. "
1300 "The default is 'SGSN-00-00-00-00-00-00'.\n")
1301{
1302 if (vty->type != VTY_FILE) {
1303 vty_out(vty, "The IPA name cannot be changed at run-time; "
1304 "It can only be set in the configuraton file.%s", VTY_NEWLINE);
1305 return CMD_WARNING;
1306 }
1307
1308 g_cfg->sgsn_ipa_name = talloc_strdup(tall_vty_ctx, argv[0]);
1309 return CMD_SUCCESS;
1310}
1311
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001312DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
1313 "gsup remote-ip A.B.C.D",
1314 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001315 "Set the IP address of the remote GSUP server (e.g. OsmoHLR)."
1316 " This setting only applies if 'auth-policy remote' is used.\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001317 "IPv4 Address\n")
1318{
1319 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
1320
1321 return CMD_SUCCESS;
1322}
1323
1324DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
1325 "gsup remote-port <0-65535>",
1326 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001327 "Set the TCP port of the remote GSUP server, see also 'gsup remote-ip'\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001328 "Remote TCP port\n")
1329{
1330 g_cfg->gsup_server_port = atoi(argv[0]);
1331
1332 return CMD_SUCCESS;
1333}
1334
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001335DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
1336 "gsup oap-id <0-65535>",
1337 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001338 "Set the OAP client ID for authentication on the GSUP protocol."
1339 " This setting only applies if 'auth-policy remote' is used.\n"
1340 "OAP client ID (0 == disabled)\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001341{
1342 /* VTY ensures range */
1343 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
1344 return CMD_SUCCESS;
1345}
1346
1347DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
1348 "gsup oap-k K",
1349 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001350 "Set the OAP shared secret key K for authentication on the GSUP protocol."
1351 " This setting only applies if auth-policy remote is used.\n"
1352 "K value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001353{
1354 const char *k = argv[0];
1355
1356 g_cfg->oap.secret_k_present = 0;
1357
1358 if ((!k) || (strlen(k) == 0))
1359 goto disable;
1360
1361 int k_len = osmo_hexparse(k,
1362 g_cfg->oap.secret_k,
1363 sizeof(g_cfg->oap.secret_k));
1364 if (k_len != 16) {
1365 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
1366 k_len, VTY_NEWLINE);
1367 goto disable;
1368 }
1369
1370 g_cfg->oap.secret_k_present = 1;
1371 return CMD_SUCCESS;
1372
1373disable:
1374 if (g_cfg->oap.client_id > 0) {
1375 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
1376 VTY_NEWLINE);
1377 return CMD_WARNING;
1378 }
1379 return CMD_SUCCESS;
1380}
1381
1382DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1383 "gsup oap-opc OPC",
1384 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001385 "Set the OAP shared secret OPC for authentication on the GSUP protocol."
1386 " This setting only applies if auth-policy remote is used.\n"
1387 "OPC value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001388{
1389 const char *opc = argv[0];
1390
1391 g_cfg->oap.secret_opc_present = 0;
1392
1393 if ((!opc) || (strlen(opc) == 0))
1394 goto disable;
1395
1396 int opc_len = osmo_hexparse(opc,
1397 g_cfg->oap.secret_opc,
1398 sizeof(g_cfg->oap.secret_opc));
1399 if (opc_len != 16) {
1400 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1401 opc_len, VTY_NEWLINE);
1402 goto disable;
1403 }
1404
1405 g_cfg->oap.secret_opc_present = 1;
1406 return CMD_SUCCESS;
1407
1408disable:
1409 if (g_cfg->oap.client_id > 0) {
1410 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1411 VTY_NEWLINE);
1412 return CMD_WARNING;
1413 }
1414 return CMD_SUCCESS;
1415}
1416
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001417DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1418 "access-point-name NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001419 "Globally allow the given APN name for all subscribers.\n"
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001420 "Add this NAME to the list\n")
1421{
1422 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1423}
1424
1425DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1426 "no access-point-name NAME",
1427 NO_STR "Configure a global list of allowed APNs\n"
1428 "Remove entry with NAME\n")
1429{
1430 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1431 if (!apn_ctx)
1432 return CMD_SUCCESS;
1433
1434 sgsn_apn_ctx_free(apn_ctx);
1435 return CMD_SUCCESS;
1436}
1437
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001438DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1439 "cdr filename NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001440 "CDR\n"
1441 "Set the file name for the call-data-record file, logging the data usage of each subscriber.\n"
1442 "filename\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001443{
1444 talloc_free(g_cfg->cdr.filename);
1445 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1446 return CMD_SUCCESS;
1447}
1448
1449DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1450 "no cdr filename",
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001451 NO_STR "CDR\nDisable saving CDR to file\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001452{
1453 talloc_free(g_cfg->cdr.filename);
1454 g_cfg->cdr.filename = NULL;
1455 return CMD_SUCCESS;
1456}
1457
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001458DEFUN(cfg_cdr_trap, cfg_cdr_trap_cmd,
1459 "cdr trap",
1460 "CDR\nEnable sending CDR via TRAP CTRL messages\n")
1461{
1462 g_cfg->cdr.trap = true;
1463 return CMD_SUCCESS;
1464}
1465
1466DEFUN(cfg_no_cdr_trap, cfg_no_cdr_trap_cmd,
1467 "no cdr trap",
1468 NO_STR "CDR\nDisable sending CDR via TRAP CTRL messages\n")
1469{
1470 g_cfg->cdr.trap = false;
1471 return CMD_SUCCESS;
1472}
1473
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001474DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1475 "cdr interval <1-2147483647>",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001476 "CDR\n"
1477 "Set the interval for the call-data-record file\n"
1478 "interval in seconds\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001479{
1480 g_cfg->cdr.interval = atoi(argv[0]);
1481 return CMD_SUCCESS;
1482}
1483
Philippf1f34362016-08-26 17:00:21 +02001484#define COMPRESSION_STR "Configure compression\n"
1485DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1486 "no compression rfc1144",
1487 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1488{
1489 g_cfg->pcomp_rfc1144.active = 0;
1490 g_cfg->pcomp_rfc1144.passive = 0;
1491 return CMD_SUCCESS;
1492}
1493
1494DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1495 "compression rfc1144 active slots <1-256>",
1496 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001497 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001498 "Compression is actively proposed\n"
1499 "Number of compression state slots\n"
1500 "Number of compression state slots\n")
1501{
1502 g_cfg->pcomp_rfc1144.active = 1;
1503 g_cfg->pcomp_rfc1144.passive = 1;
1504 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1505 return CMD_SUCCESS;
1506}
1507
1508DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1509 "compression rfc1144 passive",
1510 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001511 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001512 "Compression is available on request\n")
1513{
1514 g_cfg->pcomp_rfc1144.active = 0;
1515 g_cfg->pcomp_rfc1144.passive = 1;
1516 return CMD_SUCCESS;
1517}
1518
Philipp73f83d52016-09-02 13:38:01 +02001519DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
1520 "no compression v42bis",
1521 NO_STR COMPRESSION_STR "disable V.42bis data compression\n")
1522{
1523 g_cfg->dcomp_v42bis.active = 0;
1524 g_cfg->dcomp_v42bis.passive = 0;
1525 return CMD_SUCCESS;
1526}
1527
1528DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
1529 "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
1530 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001531 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001532 "Compression is actively proposed\n"
1533 "Direction in which the compression shall be active (p0)\n"
1534 "Compress ms->sgsn direction only\n"
1535 "Compress sgsn->ms direction only\n"
1536 "Both directions\n"
1537 "Number of codewords (p1)\n"
1538 "Number of codewords\n"
1539 "Maximum string length (p2)\n" "Maximum string length\n")
1540{
1541 g_cfg->dcomp_v42bis.active = 1;
1542 g_cfg->dcomp_v42bis.passive = 1;
1543
1544 switch (argv[0][0]) {
1545 case 'm':
1546 g_cfg->dcomp_v42bis.p0 = 1;
1547 break;
1548 case 's':
1549 g_cfg->dcomp_v42bis.p0 = 2;
1550 break;
1551 case 'b':
1552 g_cfg->dcomp_v42bis.p0 = 3;
1553 break;
1554 }
1555
1556 g_cfg->dcomp_v42bis.p1 = atoi(argv[1]);
1557 g_cfg->dcomp_v42bis.p2 = atoi(argv[2]);
1558 return CMD_SUCCESS;
1559}
1560
1561DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
1562 "compression v42bis passive",
1563 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001564 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001565 "Compression is available on request\n")
1566{
1567 g_cfg->dcomp_v42bis.active = 0;
1568 g_cfg->dcomp_v42bis.passive = 1;
1569 return CMD_SUCCESS;
1570}
1571
Pau Espin Pedrol2c908992019-08-19 19:06:06 +02001572#if BUILD_IU
1573DEFUN(cfg_sgsn_cs7_instance_iu,
1574 cfg_sgsn_cs7_instance_iu_cmd,
1575 "cs7-instance-iu <0-15>",
1576 "Set SS7 to be used by the Iu-Interface.\n" "SS7 instance reference number (default: 0)\n")
1577{
1578 g_cfg->iu.cs7_instance = atoi(argv[0]);
1579 return CMD_SUCCESS;
1580}
1581#endif
1582
Pau Espin Pedrole5c89982021-05-03 18:16:42 +02001583DEFUN(cfg_sgsn_mme, cfg_sgsn_mme_cmd,
1584 "mme NAME",
1585 "Configure an MME peer\n"
1586 "Name identifying the MME peer\n")
1587{
1588 struct sgsn_mme_ctx *mme;
1589
1590 mme = sgsn_mme_ctx_find_alloc(sgsn, argv[0]);
1591 if (!mme)
1592 return CMD_WARNING;
1593
1594 vty->node = MME_NODE;
1595 vty->index = mme;
1596
1597 return CMD_SUCCESS;
1598}
1599
1600DEFUN(cfg_sgsn_no_mme, cfg_sgsn_no_mme_cmd,
1601 "no mme NAME",
1602 NO_STR "Delete an MME peer configuration\n"
1603 "Name identifying the MME peer\n")
1604{
1605 struct sgsn_mme_ctx *mme;
1606
1607 mme = sgsn_mme_ctx_by_name(sgsn, argv[0]);
1608 if (!mme) {
1609 vty_out(vty, "%% MME %s doesn't exist.%s",
1610 argv[0], VTY_NEWLINE);
1611 return CMD_WARNING;
1612 }
1613
1614 sgsn_mme_ctx_free(mme);
1615
1616 return CMD_SUCCESS;
1617}
1618
1619#define GTP_STR "Configure GTP connection\n"
1620
1621DEFUN(cfg_mme_remote_ip, cfg_mme_remote_ip_cmd,
1622 "gtp remote-ip A.B.C.D",
1623 GTP_STR "Set Remote GTP IP address\n" IP_STR)
1624{
1625 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1626
1627 inet_aton(argv[0], &mme->remote_addr);
1628
1629 return CMD_SUCCESS;
1630}
1631
1632#define RAN_INFO_STR "Configure RAN Information Relay routing\n"
1633#define TAI_DOC "MCC\n" "MNC\n" "TAC\n"
1634
1635DEFUN(cfg_mme_ran_info_relay_tai, cfg_mme_ran_info_relay_tai_cmd,
1636 "gtp ran-info-relay <0-999> <0-999> <0-65535>",
1637 GTP_STR RAN_INFO_STR TAI_DOC)
1638{
1639 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1640 struct sgsn_mme_ctx *mme_tmp;
1641 struct osmo_eutran_tai tai;
1642
1643 const char *mcc = argv[0];
1644 const char *mnc = argv[1];
1645 const char *tac = argv[2];
1646
1647 if (osmo_mcc_from_str(mcc, &tai.mcc)) {
1648 vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
1649 return CMD_WARNING;
1650 }
1651 if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
1652 vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
1653 return CMD_WARNING;
1654 }
1655 tai.tac = atoi(tac);
1656
1657 if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
1658 if (mme_tmp != mme) {
1659 vty_out(vty, "%% Another MME %s already contains this route%s",
1660 mme_tmp->name, VTY_NEWLINE);
1661 return CMD_WARNING;
1662 }
1663 /* else: NO-OP, return */
1664 return CMD_SUCCESS;
1665 }
1666
1667 sgsn_mme_ctx_route_add(mme, &tai);
1668 return CMD_SUCCESS;
1669}
1670
1671DEFUN(cfg_mme_no_ran_info_relay_tai, cfg_mme_no_ran_info_relay_tai_cmd,
1672 "no gtp ran-info-relay <0-999> <0-999> <0-65535>",
1673 NO_STR GTP_STR RAN_INFO_STR TAI_DOC)
1674{
1675 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1676 struct sgsn_mme_ctx *mme_tmp;
1677 struct osmo_eutran_tai tai;
1678
1679 const char *mcc = argv[0];
1680 const char *mnc = argv[1];
1681 const char *tac = argv[2];
1682
1683 if (osmo_mcc_from_str(mcc, &tai.mcc)) {
1684 vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
1685 return CMD_WARNING;
1686 }
1687 if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
1688 vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
1689 return CMD_WARNING;
1690 }
1691 tai.tac = atoi(tac);
1692
1693 if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
1694 if (mme_tmp != mme) {
1695 vty_out(vty, "%% Another MME %s contains this route%s",
1696 mme_tmp->name, VTY_NEWLINE);
1697 return CMD_WARNING;
1698 }
1699 sgsn_mme_ctx_route_del(mme, &tai);
1700 return CMD_SUCCESS;
1701 } else {
1702 vty_out(vty, "%% This route doesn't exist in current MME %s%s",
1703 mme->name, VTY_NEWLINE);
1704 return CMD_WARNING;
1705 }
1706}
1707
1708DEFUN(cfg_mme_ran_info_relay_default, cfg_mme_ran_info_relay_default_cmd,
1709 "gtp ran-info-relay default",
1710 GTP_STR RAN_INFO_STR "Set as default route")
1711{
1712 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1713 struct sgsn_mme_ctx *default_mme;
1714
1715 if (mme->default_route)
1716 return CMD_SUCCESS; /* NO-OP */
1717
1718 if ((default_mme = sgsn_mme_ctx_by_default_route(sgsn))) {
1719 vty_out(vty, "%% Another MME %s is already set as default route, "
1720 "remove it before setting it here.%s",
1721 default_mme->name, VTY_NEWLINE);
1722 return CMD_WARNING;
1723 }
1724
1725 mme->default_route = true;
1726 return CMD_SUCCESS;
1727}
1728
1729DEFUN(cfg_mme_no_ran_info_relay_default, cfg_mme_no_ran_info_relay_default_cmd,
1730 "no gtp ran-info-relay default",
1731 NO_STR GTP_STR RAN_INFO_STR "Set as default route")
1732{
1733 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1734 mme->default_route = false;
1735 return CMD_SUCCESS;
1736}
1737
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001738int sgsn_vty_init(struct sgsn_config *cfg)
Harald Welte288be162010-05-01 16:48:27 +02001739{
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001740 g_cfg = cfg;
1741
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001742 g_cfg->T_defs = sgsn_T_defs;
1743 osmo_tdefs_reset(g_cfg->T_defs);
1744
Pau Espin Pedrol85011262022-11-02 20:23:09 +01001745 g_cfg->T_defs_gtp = gtp_T_defs;
1746 osmo_tdefs_reset(g_cfg->T_defs_gtp);
1747
Harald Welted193cb32010-05-17 22:58:03 +02001748 install_element_ve(&show_sgsn_cmd);
1749 //install_element_ve(&show_mmctx_tlli_cmd);
1750 install_element_ve(&show_mmctx_imsi_cmd);
1751 install_element_ve(&show_mmctx_all_cmd);
1752 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001753 install_element_ve(&show_subscr_cache_cmd);
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001754 install_element_ve(&show_timer_cmd);
Pau Espin Pedrol85011262022-11-02 20:23:09 +01001755 install_element_ve(&show_timer_gtp_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001756
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001757 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001758 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001759 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001760 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001761 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1762 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Oliver Smithab39b622021-07-05 15:41:05 +02001763 install_element(ENABLE_NODE, &page_subscr_info_cmd);
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001764 install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001765
1766 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1767 install_node(&sgsn_node, config_write_sgsn);
Keithc70e8382020-10-19 22:24:48 +02001768 install_element(SGSN_NODE, &cfg_sgsn_state_dir_cmd);
Harald Weltee300d002010-06-02 12:41:34 +02001769 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001770 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1771 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1772 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +02001773 install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +02001774 install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001775 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001776 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Vadim Yanitskiy794f4462019-05-27 05:39:06 +07001777 install_element(SGSN_NODE, &cfg_authentication_cmd);
Eric2f898262021-05-19 18:57:50 +02001778
1779 /* order matters here: ensure we attempt to parse our new command first! */
1780 install_element(SGSN_NODE, &cfg_encrypt2_cmd);
Max93408ae2016-06-28 14:10:16 +02001781 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +01001782 install_element(SGSN_NODE, &cfg_encryption_uea_cmd);
Eric2f898262021-05-19 18:57:50 +02001783
Stefan Sperling88220092018-12-11 14:42:00 +01001784 install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001785 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1786 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001787 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1788 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1789 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001790 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1791 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001792 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1793 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001794 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1795 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001796 install_element(SGSN_NODE, &cfg_cdr_trap_cmd);
1797 install_element(SGSN_NODE, &cfg_no_cdr_trap_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001798 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001799 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001800 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001801
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001802 install_element(SGSN_NODE, &cfg_sgsn_timer_cmd);
Pau Espin Pedrol85011262022-11-02 20:23:09 +01001803 install_element(SGSN_NODE, &cfg_sgsn_timer_gtp_cmd);
Harald Welte94508822015-08-15 19:08:21 +02001804
Philippf1f34362016-08-26 17:00:21 +02001805 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1806 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1807 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
Philipp73f83d52016-09-02 13:38:01 +02001808 install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd);
1809 install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
1810 install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001811
Pau Espin Pedrole5c89982021-05-03 18:16:42 +02001812 install_element(SGSN_NODE, &cfg_sgsn_mme_cmd);
1813 install_element(SGSN_NODE, &cfg_sgsn_no_mme_cmd);
1814 install_node(&mme_node, NULL);
1815 install_element(MME_NODE, &cfg_mme_remote_ip_cmd);
1816 install_element(MME_NODE, &cfg_mme_ran_info_relay_default_cmd);
1817 install_element(MME_NODE, &cfg_mme_no_ran_info_relay_default_cmd);
1818 install_element(MME_NODE, &cfg_mme_ran_info_relay_tai_cmd);
1819 install_element(MME_NODE, &cfg_mme_no_ran_info_relay_tai_cmd);
1820
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001821#ifdef BUILD_IU
Pau Espin Pedrol2c908992019-08-19 19:06:06 +02001822 install_element(SGSN_NODE, &cfg_sgsn_cs7_instance_iu_cmd);
Neels Hofmeyra7a39472017-07-05 15:19:52 +02001823 ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001824#endif
Harald Welte288be162010-05-01 16:48:27 +02001825 return 0;
1826}
1827
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001828int sgsn_parse_config(const char *config_file)
Harald Welte288be162010-05-01 16:48:27 +02001829{
1830 int rc;
1831
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001832 /* make sure sgsn_vty_init() was called before this */
1833 OSMO_ASSERT(g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +01001834
Neels Hofmeyr340a7e92022-03-07 15:37:24 +01001835 g_cfg->gea_encryption_mask = 0x1; /* support GEA0 by default unless specific encryption config exists */
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +01001836 g_cfg->uea_encryption_mask = (1 << OSMO_UTRAN_UEA0); /* support UEA0 by default unless specific encryption config exists */
Eric2f898262021-05-19 18:57:50 +02001837
Harald Weltedcccb182010-05-16 20:52:23 +02001838 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001839 if (rc < 0) {
1840 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1841 return rc;
1842 }
1843
Neels Hofmeyr27355c92017-02-24 06:28:31 +01001844 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE
1845 && !(g_cfg->gsup_server_addr.sin_addr.s_addr
1846 && g_cfg->gsup_server_port)) {
1847 fprintf(stderr, "Configuration error:"
1848 " 'auth-policy remote' requires both"
1849 " 'gsup remote-ip' and 'gsup remote-port'\n");
1850 return -EINVAL;
1851 }
1852
Harald Welte288be162010-05-01 16:48:27 +02001853 return 0;
1854}