blob: d8ea420085244434d7d08c0d9c25fe8322ed16b4 [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>
Pau Espin Pedrol05190c32023-01-05 20:13:13 +010045#include <osmocom/sgsn/pdpctx.h>
Harald Weltef4b2c4c2018-09-16 07:53:41 +020046#include <osmocom/gsupclient/gsup_client.h>
Harald Welte288be162010-05-01 16:48:27 +020047
Pau Espin Pedrola299d652019-08-14 19:11:10 +020048#include <osmocom/vty/tdef_vty.h>
Harald Welte4b037e42010-05-19 19:45:32 +020049#include <osmocom/vty/command.h>
50#include <osmocom/vty/vty.h>
Pablo Neira Ayuso6110a3f2011-03-28 19:35:00 +020051#include <osmocom/vty/misc.h>
Max93408ae2016-06-28 14:10:16 +020052#include <osmocom/crypt/gprs_cipher.h>
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +010053#include <osmocom/crypt/utran_cipher.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010054#include <osmocom/abis/ipa.h>
55
Alexander Couzensc503f0a2018-08-07 17:50:04 +020056#include <osmocom/gprs/gprs_bssgp.h>
57
Harald Welted193cb32010-05-17 22:58:03 +020058#include <pdp.h>
Maxbaabc682017-10-20 13:39:57 +020059#include <gtp.h>
Harald Welted193cb32010-05-17 22:58:03 +020060
Neels Hofmeyr2188a772016-05-20 21:59:55 +020061#include "../../bscconfig.h"
62
63#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +020064#include <osmocom/ranap/iu_client.h>
Neels Hofmeyr2188a772016-05-20 21:59:55 +020065#endif
66
Harald Welte288be162010-05-01 16:48:27 +020067static struct sgsn_config *g_cfg = NULL;
68
Jacob Erlbeck106f5472014-11-04 10:08:37 +010069const struct value_string sgsn_auth_pol_strs[] = {
70 { SGSN_AUTH_POLICY_OPEN, "accept-all" },
71 { SGSN_AUTH_POLICY_CLOSED, "closed" },
72 { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" },
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +010073 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeck106f5472014-11-04 10:08:37 +010074 { 0, NULL }
75};
76
Harald Welte94508822015-08-15 19:08:21 +020077/* Section 11.2.2 / Table 11.3a GPRS Mobility management timers – MS side */
78#define GSM0408_T3312_SECS (10*60) /* periodic RAU interval, default 54min */
79
80/* Section 11.2.2 / Table 11.4 MM timers netwokr side */
81#define GSM0408_T3322_SECS 6 /* DETACH_REQ -> DETACH_ACC */
82#define GSM0408_T3350_SECS 6 /* waiting for ATT/RAU/TMSI COMPL */
83#define GSM0408_T3360_SECS 6 /* waiting for AUTH/CIPH RESP */
84#define GSM0408_T3370_SECS 6 /* waiting for ID RESP */
85
Alexander Couzens5ba6fb32017-01-31 18:04:27 +010086/* Section 11.2.2 / Table 11.4a MM timers network side */
Harald Welte94508822015-08-15 19:08:21 +020087#define GSM0408_T3313_SECS 30 /* waiting for paging response */
88#define GSM0408_T3314_SECS 44 /* force to STBY on expiry, Ready timer */
89#define GSM0408_T3316_SECS 44
90
91/* Section 11.3 / Table 11.2d Timers of Session Management - network side */
92#define GSM0408_T3385_SECS 8 /* wait for ACT PDP CTX REQ */
93#define GSM0408_T3386_SECS 8 /* wait for MODIFY PDP CTX ACK */
94#define GSM0408_T3395_SECS 8 /* wait for DEACT PDP CTX ACK */
95#define GSM0408_T3397_SECS 8 /* wait for DEACT AA PDP CTX ACK */
96
Alexander Couzensafadd102019-10-08 14:30:59 +020097/* Non spec timer */
98#define NONSPEC_X1001_SECS 5 /* wait for a RANAP Release Complete */
99
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200100
Pau Espin Pedrole659f752023-01-05 17:20:37 +0100101struct osmo_tdef sgsn_T_defs[] = {
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200102 { .T=3312, .default_val=GSM0408_T3312_SECS, .desc="Periodic RA Update timer (s)" },
103 { .T=3313, .default_val=GSM0408_T3313_SECS, .desc="Waiting for paging response timer (s)" },
Alexander Couzens39cbecd2017-02-03 22:16:05 +0100104 { .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 +0200105 { .T=3316, .default_val=GSM0408_T3316_SECS, .desc="AA-Ready timer (s)" },
106 { .T=3322, .default_val=GSM0408_T3322_SECS, .desc="Detach request -> accept timer (s)" },
107 { .T=3350, .default_val=GSM0408_T3350_SECS, .desc="Waiting for ATT/RAU/TMSI_COMPL timer (s)" },
108 { .T=3360, .default_val=GSM0408_T3360_SECS, .desc="Waiting for AUTH/CIPH response timer (s)" },
109 { .T=3370, .default_val=GSM0408_T3370_SECS, .desc="Waiting for IDENTITY response timer (s)" },
110 { .T=3385, .default_val=GSM0408_T3385_SECS, .desc="Wait for ACT PDP CTX REQ timer (s)" },
111 { .T=3386, .default_val=GSM0408_T3386_SECS, .desc="Wait for MODIFY PDP CTX ACK timer (s)" },
112 { .T=3395, .default_val=GSM0408_T3395_SECS, .desc="Wait for DEACT PDP CTX ACK timer (s)" },
113 { .T=3397, .default_val=GSM0408_T3397_SECS, .desc="Wait for DEACT AA PDP CTX ACK timer (s)" },
Alexander Couzens3bad31b2019-09-11 02:17:31 +0200114 /* non spec timers */
Alexander Couzensafadd102019-10-08 14:30:59 +0200115 { .T=-1001, .default_val=NONSPEC_X1001_SECS, .desc="RANAP Release timeout. Wait for RANAP Release Complete."
116 "On expiry release Iu connection (s)" },
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200117 {}
118};
119
120DEFUN(show_timer, show_timer_cmd,
121 "show timer " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
122 SHOW_STR "Show timers\n"
123 OSMO_TDEF_VTY_DOC_T)
124{
125 const char *T_arg = argc > 0 ? argv[0] : NULL;
126 return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs, T_arg, NULL);
Harald Welte94508822015-08-15 19:08:21 +0200127}
128
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200129DEFUN(cfg_sgsn_timer, cfg_sgsn_timer_cmd,
130 "timer " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
131 "Configure or show timers\n"
132 OSMO_TDEF_VTY_DOC_SET)
133{
134 /* If any arguments are missing, redirect to 'show' */
135 if (argc < 2)
136 return show_timer(self, vty, argc, argv);
137 return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs, argv);
138}
Harald Welte94508822015-08-15 19:08:21 +0200139
Pau Espin Pedrol85011262022-11-02 20:23:09 +0100140DEFUN(show_timer_gtp, show_timer_gtp_cmd,
141 "show timer gtp " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
142 SHOW_STR "Show timers\n" "GTP (libgtp) timers\n"
143 OSMO_TDEF_VTY_DOC_T)
144{
145 const char *T_arg = argc > 0 ? argv[0] : NULL;
146 return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs_gtp, T_arg, NULL);
147}
148
149DEFUN(cfg_sgsn_timer_gtp, cfg_sgsn_timer_gtp_cmd,
150 "timer gtp " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
151 "Configure or show timers\n" "GTP (libgtp) timers\n"
152 OSMO_TDEF_VTY_DOC_SET)
153{
154 /* If any arguments are missing, redirect to 'show' */
155 if (argc < 2)
156 return show_timer(self, vty, argc, argv);
157 return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs_gtp, argv);
158}
159
Keith6cee1a12021-09-29 21:00:04 +0200160char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6)
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200161{
162 static char str[INET6_ADDRSTRLEN + 10];
163
164 if (!pdpa || len < 2)
165 return "none";
166
167 switch (pdpa[0] & 0x0f) {
168 case PDP_TYPE_ORG_IETF:
169 switch (pdpa[1]) {
170 case PDP_TYPE_N_IETF_IPv4:
171 if (len < 2 + 4)
172 break;
Keith6cee1a12021-09-29 21:00:04 +0200173 osmo_strlcpy(str, "IPv4 ", sizeof(str));
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200174 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
175 return str;
176 case PDP_TYPE_N_IETF_IPv6:
177 if (len < 2 + 8)
178 break;
Keith6cee1a12021-09-29 21:00:04 +0200179 osmo_strlcpy(str, "IPv6 ", sizeof(str));
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200180 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
181 return str;
Keith6cee1a12021-09-29 21:00:04 +0200182 case PDP_TYPE_N_IETF_IPv4v6:
183 if (len < 2 + 20)
184 break;
185 if (return_ipv6) {
186 /* The IPv6 token, (rightmost four fields) is a duplicate of
187 * the site prefix + subnetID (leftmost fields) in pdpa here */
188 osmo_strlcpy(str, "IPv6 ", sizeof(str));
189 inet_ntop(AF_INET6, pdpa+6, str+5, sizeof(str)-5);
190 return str;
191 }
192 osmo_strlcpy(str, "IPv4 ", sizeof(str));
193 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
194 return str;
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200195 default:
196 break;
197 }
198 break;
199 case PDP_TYPE_ORG_ETSI:
200 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
201 return "PPP";
202 break;
203 default:
204 break;
205 }
206
207 return "invalid";
208}
209
Harald Welte288be162010-05-01 16:48:27 +0200210static struct cmd_node sgsn_node = {
211 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200212 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200213 1,
214};
215
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200216static struct cmd_node mme_node = {
217 MME_NODE,
218 "%s(config-sgsn-mme)# ",
219 1,
220};
221
222static void config_write_mme(struct vty *vty, const struct sgsn_mme_ctx *mme, const char *prefix)
223{
224 struct mme_rim_route *rt;
225
226 vty_out(vty, "%smme %s%s", prefix, mme->name, VTY_NEWLINE);
227
228 vty_out(vty, "%s gtp remote-ip %s%s", prefix, inet_ntoa(mme->remote_addr), VTY_NEWLINE);
229 if (mme->default_route)
230 vty_out(vty, "%s gtp ran-info-relay default%s", prefix, VTY_NEWLINE);
231 llist_for_each_entry(rt, &mme->routes, list) {
232 vty_out(vty, "%s gtp ran-info-relay %s %s %u%s", prefix,
233 osmo_mcc_name(rt->tai.mcc), osmo_mnc_name(rt->tai.mnc, rt->tai.mnc_3_digits),
234 rt->tai.tac, VTY_NEWLINE);
235 }
236}
237
Harald Welte288be162010-05-01 16:48:27 +0200238static int config_write_sgsn(struct vty *vty)
239{
Harald Welte77289c22010-05-18 14:32:29 +0200240 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100241 struct imsi_acl_entry *acl;
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100242 struct apn_ctx *actx;
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800243 struct ares_addr_node *server;
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200244 struct sgsn_mme_ctx *mme;
Eric2f898262021-05-19 18:57:50 +0200245 int i;
Harald Welte288be162010-05-01 16:48:27 +0200246
247 vty_out(vty, "sgsn%s", VTY_NEWLINE);
248
Keithc70e8382020-10-19 22:24:48 +0200249 vty_out(vty, " gtp state-dir %s%s",
250 g_cfg->gtp_statedir, VTY_NEWLINE);
Harald Weltee300d002010-06-02 12:41:34 +0200251 vty_out(vty, " gtp local-ip %s%s",
252 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
253
Pau Espin Pedrol44bde6b2023-01-05 17:23:26 +0100254 llist_for_each_entry(gctx, &sgsn->ggsn_list, list) {
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800255 if (gctx->id == UINT32_MAX)
256 continue;
257
Harald Welteff3bde82010-05-19 15:09:09 +0200258 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200259 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200260 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200261 gctx->gtp_version, VTY_NEWLINE);
Pau Espin Pedrolaa89f5d2019-08-28 16:08:45 +0200262 if (gctx->echo_interval)
263 vty_out(vty, " ggsn %u echo-interval %u%s",
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200264 gctx->id, gctx->echo_interval, VTY_NEWLINE);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200265 else
266 vty_out(vty, " ggsn %u no echo-interval%s",
267 gctx->id, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200268 }
269
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800270 if (sgsn->cfg.dynamic_lookup)
271 vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE);
272
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800273 for (server = sgsn->ares_servers; server; server = server->next)
274 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
275
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100276 if (g_cfg->gea_encryption_mask != 0) {
Eric2f898262021-05-19 18:57:50 +0200277 vty_out(vty, " encryption gea");
278
279 for (i = 0; i < _GPRS_ALGO_NUM; i++)
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100280 if (g_cfg->gea_encryption_mask >> i & 1)
Eric2f898262021-05-19 18:57:50 +0200281 vty_out(vty, " %u", i);
282
283 vty_out(vty, "%s", VTY_NEWLINE);
284 }
Stefan Sperling88220092018-12-11 14:42:00 +0100285 if (g_cfg->sgsn_ipa_name)
286 vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100287 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
288 vty_out(vty, " gsup remote-ip %s%s",
289 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
290 if (g_cfg->gsup_server_port)
291 vty_out(vty, " gsup remote-port %d%s",
292 g_cfg->gsup_server_port, VTY_NEWLINE);
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200293 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE && !g_cfg->require_authentication)
294 vty_out(vty, " authentication optional%s", VTY_NEWLINE);
Max176b62a2016-07-04 11:09:07 +0200295 vty_out(vty, " auth-policy %s%s",
296 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
297 VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200298
299 vty_out(vty, " gsup oap-id %d%s",
300 (int)g_cfg->oap.client_id, VTY_NEWLINE);
301 if (g_cfg->oap.secret_k_present != 0)
302 vty_out(vty, " gsup oap-k %s%s",
303 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
304 VTY_NEWLINE);
305 if (g_cfg->oap.secret_opc_present != 0)
306 vty_out(vty, " gsup oap-opc %s%s",
307 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
308 VTY_NEWLINE);
309
Harald Welte7f6da482013-03-19 11:00:13 +0100310 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
311 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
312
Pau Espin Pedrolfd4d4352023-01-05 19:37:05 +0100313 if (llist_empty(&sgsn->apn_list))
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100314 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
Pau Espin Pedrolfd4d4352023-01-05 19:37:05 +0100315 llist_for_each_entry(actx, &sgsn->apn_list, list) {
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100316 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200317 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100318 actx->name, actx->imsi_prefix, actx->ggsn->id,
319 VTY_NEWLINE);
320 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200321 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100322 actx->ggsn->id, VTY_NEWLINE);
323 }
324
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200325 if (g_cfg->cdr.filename)
326 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
327 else
328 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +0100329 if (g_cfg->cdr.trap)
330 vty_out(vty, " cdr trap%s", VTY_NEWLINE);
331 else
332 vty_out(vty, " no cdr trap%s", VTY_NEWLINE);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200333 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
334
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200335 osmo_tdef_vty_write(vty, g_cfg->T_defs, " timer ");
Pau Espin Pedrol85011262022-11-02 20:23:09 +0100336 osmo_tdef_vty_write(vty, g_cfg->T_defs_gtp, " timer gtp ");
Harald Welte94508822015-08-15 19:08:21 +0200337
Philippf1f34362016-08-26 17:00:21 +0200338 if (g_cfg->pcomp_rfc1144.active) {
339 vty_out(vty, " compression rfc1144 active slots %d%s",
340 g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE);
341 } else if (g_cfg->pcomp_rfc1144.passive) {
342 vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE);
343 } else
344 vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE);
345
Philipp73f83d52016-09-02 13:38:01 +0200346 if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) {
347 vty_out(vty,
348 " compression v42bis active direction sgsn codewords %d strlen %d%s",
349 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
350 VTY_NEWLINE);
351 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) {
352 vty_out(vty,
353 " compression v42bis active direction ms codewords %d strlen %d%s",
354 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
355 VTY_NEWLINE);
356 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) {
357 vty_out(vty,
358 " compression v42bis active direction both codewords %d strlen %d%s",
359 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
360 VTY_NEWLINE);
361 } else if (g_cfg->dcomp_v42bis.passive) {
362 vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE);
363 } else
364 vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
365
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200366 llist_for_each_entry(mme, &sgsn->mme_list, list) {
367 config_write_mme(vty, mme, " ");
368 }
369
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200370#ifdef BUILD_IU
Pau Espin Pedrol2c908992019-08-19 19:06:06 +0200371 vty_out(vty, " cs7-instance-iu %u%s", g_cfg->iu.cs7_instance,
372 VTY_NEWLINE);
Neels Hofmeyra7a39472017-07-05 15:19:52 +0200373 ranap_iu_vty_config_write(vty, " ");
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200374#endif
375
Harald Welte288be162010-05-01 16:48:27 +0200376 return CMD_SUCCESS;
377}
378
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100379#define SGSN_STR "Configure the SGSN\n"
380#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200381
382DEFUN(cfg_sgsn, cfg_sgsn_cmd,
383 "sgsn",
384 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200385{
386 vty->node = SGSN_NODE;
387 return CMD_SUCCESS;
388}
389
Keithc70e8382020-10-19 22:24:48 +0200390DEFUN(cfg_sgsn_state_dir, cfg_sgsn_state_dir_cmd,
391 "gtp state-dir PATH",
392 "GTP Parameters\n"
393 "Set the directory for the GTP State file\n"
394 "Local Directory\n")
395{
396 osmo_talloc_replace_string(sgsn, &sgsn->cfg.gtp_statedir, argv[0]);
397
398 return CMD_SUCCESS;
399}
400
Harald Weltee300d002010-06-02 12:41:34 +0200401DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
402 "gtp local-ip A.B.C.D",
403 "GTP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100404 "Set the IP address for the local GTP bind for the Gp interface (towards the GGSNs)."
405 " Note: in case you would like to run the GGSN on the same machine as the SGSN, you can not run"
406 " both on the same IP address, since both sides are specified to use the same GTP port numbers"
407 " (" OSMO_STRINGIFY_VAL(GTP1C_PORT) " and " OSMO_STRINGIFY_VAL(GTP1U_PORT) ")."
408 " For example, you could use 127.0.0.1 for the SGSN and 127.0.0.2 for the GGSN in such"
409 " situations.\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100410 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200411{
412 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
413
414 return CMD_SUCCESS;
415}
416
Harald Welted193cb32010-05-17 22:58:03 +0200417DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
418 "ggsn <0-255> remote-ip A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100419 GGSN_STR "GGSN Number\n"
420 "Configure this static GGSN to use the specified remote IP address.\n"
421 "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200422{
423 uint32_t id = atoi(argv[0]);
Pau Espin Pedrol69569872023-01-05 19:39:01 +0100424 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
Harald Welte288be162010-05-01 16:48:27 +0200425
Harald Welted193cb32010-05-17 22:58:03 +0200426 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200427
Harald Welted193cb32010-05-17 22:58:03 +0200428 return CMD_SUCCESS;
429}
430
431#if 0
432DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
433 "ggsn <0-255> remote-port <0-65535>",
434 "")
435{
436 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200437 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200438 uint16_t port = atoi(argv[1]);
439
440}
441#endif
442
443DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
444 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100445 GGSN_STR "GGSN Number\n" "GTP Version\n"
446 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200447{
448 uint32_t id = atoi(argv[0]);
Pau Espin Pedrol69569872023-01-05 19:39:01 +0100449 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
Harald Welted193cb32010-05-17 22:58:03 +0200450
451 if (atoi(argv[1]))
452 ggc->gtp_version = 1;
453 else
454 ggc->gtp_version = 0;
455
456 return CMD_SUCCESS;
457}
458
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200459/* Seee 3GPP TS 29.060 section 7.2.1 */
460DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
461 "ggsn <0-255> echo-interval <1-36000>",
462 GGSN_STR "GGSN Number\n"
463 "Send an echo request to this static GGSN every interval.\n"
464 "Interval between echo requests in seconds.\n")
465{
466 uint32_t id = atoi(argv[0]);
Pau Espin Pedrol69569872023-01-05 19:39:01 +0100467 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200468
469 ggc->echo_interval = atoi(argv[1]);
470
471 if (ggc->echo_interval < 60)
Pau Espin Pedrolba2e5002019-05-27 17:35:32 +0200472 vty_out(vty, "%% 3GPP TS 29.060 section 7.2.1 states interval should " \
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200473 "not be lower than 60 seconds, use this value for " \
474 "testing purposes only!%s", VTY_NEWLINE);
475
Alexander Couzens176a4d22018-09-18 20:07:37 +0200476 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200477 return CMD_SUCCESS;
478}
479
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200480DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
481 "ggsn <0-255> no echo-interval",
482 GGSN_STR "GGSN Number\n"
483 NO_STR "Send an echo request to this static GGSN every interval.\n")
484{
485 uint32_t id = atoi(argv[0]);
Pau Espin Pedrol69569872023-01-05 19:39:01 +0100486 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200487
Pau Espin Pedrolaa89f5d2019-08-28 16:08:45 +0200488 ggc->echo_interval = 0;
Alexander Couzens176a4d22018-09-18 20:07:37 +0200489 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200490
491 return CMD_SUCCESS;
492}
493
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800494DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
495 "ggsn dynamic",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100496 GGSN_STR
497 "Enable dynamic resolving of GGSNs based on DNS resolving the APN name like in a GRX-style setup."
498 " Changing this setting requires a restart.\n")
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800499{
500 sgsn->cfg.dynamic_lookup = 1;
501 return CMD_SUCCESS;
502}
503
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800504DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
505 "grx-dns-add A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100506 "Use the specified IP address for DNS-resolving the AP names to GGSN IP addresses\n"
507 "IPv4 address\n")
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800508{
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +0100509 struct ares_addr_node *node = talloc_zero(tall_sgsn_ctx, struct ares_addr_node);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800510 node->family = AF_INET;
511 inet_aton(argv[0], &node->addr.addr4);
512
513 node->next = sgsn->ares_servers;
514 sgsn->ares_servers = node;
515 return CMD_SUCCESS;
516}
517
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100518#define APN_STR "Configure the information per APN\n"
519#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
520
521static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
522 const char *imsi_prefix, int ggsn_id)
523{
524 struct apn_ctx *actx;
525 struct sgsn_ggsn_ctx *ggsn;
526
Pau Espin Pedrol69569872023-01-05 19:39:01 +0100527 ggsn = sgsn_ggsn_ctx_by_id(sgsn, ggsn_id);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100528 if (ggsn == NULL) {
529 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
530 ggsn_id, VTY_NEWLINE);
531 return CMD_WARNING;
532 }
533
534 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
535 if (!actx) {
536 vty_out(vty, "%% unable to create APN context for %s/%s%s",
537 apn_str, imsi_prefix, VTY_NEWLINE);
538 return CMD_WARNING;
539 }
540
541 actx->ggsn = ggsn;
542
543 return CMD_SUCCESS;
544}
545
Harald Welted193cb32010-05-17 22:58:03 +0200546DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
547 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100548 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100549 "Select the GGSN to use for the given APN gateway prefix\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100550 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200551{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100552
553 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200554}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100555
556DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
557 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
558 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100559 "Select the GGSN to use for the given APN gateway prefix if and only if the IMSI matches the"
560 " given prefix.\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100561 "An IMSI prefix\n"
562 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
563 "The GGSN id")
564{
565
566 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
567}
Harald Welted193cb32010-05-17 22:58:03 +0200568
Maxc005db72017-10-27 18:43:29 +0200569char *sgsn_gtp_ntoa(struct ul16_t *ul)
Harald Welte471ac7d2016-12-15 19:48:58 +0100570{
Max8492c202017-12-05 17:28:15 +0100571 struct in_addr ia;
572
573 if (gsna2in_addr(&ia, ul) != 0)
Harald Welte471ac7d2016-12-15 19:48:58 +0100574 return "UNKNOWN";
Max8492c202017-12-05 17:28:15 +0100575
576 return inet_ntoa(ia);
Harald Welte471ac7d2016-12-15 19:48:58 +0100577}
578
Harald Welted193cb32010-05-17 22:58:03 +0200579static void vty_dump_pdp(struct vty *vty, const char *pfx,
580 struct sgsn_pdp_ctx *pdp)
581{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200582 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welte471ac7d2016-12-15 19:48:58 +0100583 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s",
584 pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200585 if (pdp->lib) {
Max7933d962017-10-19 16:52:30 +0200586 char apnbuf[APN_MAXLEN + 1];
Harald Weltedfbd2c82017-08-13 00:56:45 +0200587 vty_out(vty, "%s APN: %s%s", pfx,
Max7933d962017-10-19 16:52:30 +0200588 osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200589 VTY_NEWLINE);
590 vty_out(vty, "%s PDP Address: %s%s", pfx,
Keith6cee1a12021-09-29 21:00:04 +0200591 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, false),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200592 VTY_NEWLINE);
Keith6cee1a12021-09-29 21:00:04 +0200593 if (pdp->lib->eua.v[1] == PDP_TYPE_N_IETF_IPv4v6) {
594 vty_out(vty, "%s PDP Address: %s%s", pfx,
595 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, true),
596 VTY_NEWLINE);
597 }
Maxb24af2b2017-12-05 17:54:42 +0100598 vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200599 sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200600 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200601 sgsn_gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100602 vty_out(vty, "%s GTPv%d Remote Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200603 sgsn_gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200604 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200605 sgsn_gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200606 }
Harald Welte471ac7d2016-12-15 19:48:58 +0100607
Harald Welteefbdee92010-06-10 00:20:12 +0200608 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200609}
610
611static void vty_dump_mmctx(struct vty *vty, const char *pfx,
612 struct sgsn_mm_ctx *mm, int pdp)
613{
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200614 uint32_t id = 0;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200615 const char *mm_state_name = NULL;
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200616
617 switch(mm->ran_type) {
618 case MM_CTX_T_UTRAN_Iu:
619#if BUILD_IU
620 id = mm->iu.ue_ctx->conn_id;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200621 mm_state_name = osmo_fsm_inst_state_name(mm->iu.mm_state_fsm);
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200622#endif
623 break;
624 case MM_CTX_T_GERAN_Gb:
625 id = mm->gb.tlli;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200626 mm_state_name = osmo_fsm_inst_state_name(mm->gb.mm_state_fsm);
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200627 break;
628 }
629
Harald Welted193cb32010-05-17 22:58:03 +0200630 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
631 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200632 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200633 pfx, mm->msisdn, id, mm->hlr, VTY_NEWLINE);
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200634 vty_out(vty, "%s GMM State: %s, Routeing Area: %s, Cell ID: %u%s",
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200635 pfx, osmo_fsm_inst_state_name(mm->gmm_fsm),
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100636 osmo_rai_name(&mm->ra), mm->gb.cell_id, VTY_NEWLINE);
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200637 vty_out(vty, "%s MM State: %s, RAN Type: %s%s", pfx, mm_state_name,
638 get_value_string(sgsn_ran_type_names, mm->ran_type), VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200639
Pau Espin Pedrol3b848bd2019-08-30 18:06:35 +0200640 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
Harald Welte8acd88f2010-05-18 10:57:45 +0200641
Harald Welted193cb32010-05-17 22:58:03 +0200642 if (pdp) {
643 struct sgsn_pdp_ctx *pdp;
644
645 llist_for_each_entry(pdp, &mm->pdp_list, list)
646 vty_dump_pdp(vty, " ", pdp);
647 }
648}
649
650DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
651 SHOW_STR "Display information about the SGSN")
652{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100653 if (sgsn->gsup_client) {
654 struct ipa_client_conn *link = sgsn->gsup_client->link;
655 vty_out(vty,
656 " Remote authorization: %sconnected to %s:%d via GSUP%s",
657 sgsn->gsup_client->is_connected ? "" : "not ",
658 link->addr, link->port,
659 VTY_NEWLINE);
660 }
Maxbaabc682017-10-20 13:39:57 +0200661 if (sgsn->gsn)
662 vty_out(vty, " GSN: signalling %s, user traffic %s%s",
663 inet_ntoa(sgsn->gsn->gsnc), inet_ntoa(sgsn->gsn->gsnu), VTY_NEWLINE);
664
Harald Welted193cb32010-05-17 22:58:03 +0200665 /* FIXME: statistics */
666 return CMD_SUCCESS;
667}
668
669#define MMCTX_STR "MM Context\n"
670#define INCLUDE_PDP_STR "Include PDP Context Information\n"
671
672#if 0
673DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
674 "show mm-context tlli HEX [pdp]",
675 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
676{
677 uint32_t tlli;
678 struct sgsn_mm_ctx *mm;
679
680 tlli = strtoul(argv[0], NULL, 16);
681 mm = sgsn_mm_ctx_by_tlli(tlli);
682 if (!mm) {
683 vty_out(vty, "No MM context for TLLI %08x%s",
684 tlli, VTY_NEWLINE);
685 return CMD_WARNING;
686 }
687 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
688 return CMD_SUCCESS;
689}
690#endif
691
692DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
693 "show mm-context imsi IMSI [pdp]",
694 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
695 INCLUDE_PDP_STR)
696{
697 struct sgsn_mm_ctx *mm;
698
699 mm = sgsn_mm_ctx_by_imsi(argv[0]);
700 if (!mm) {
701 vty_out(vty, "No MM context for IMSI %s%s",
702 argv[0], VTY_NEWLINE);
703 return CMD_WARNING;
704 }
Keithc12c1a62021-05-20 04:41:01 +0200705 vty_dump_mmctx(vty, "", mm, (argc > 1) ? 1 : 0);
Harald Welted193cb32010-05-17 22:58:03 +0200706 return CMD_SUCCESS;
707}
708
709DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
710 "show mm-context all [pdp]",
711 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
712{
713 struct sgsn_mm_ctx *mm;
Harald Welted193cb32010-05-17 22:58:03 +0200714 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
Keithc12c1a62021-05-20 04:41:01 +0200715 vty_dump_mmctx(vty, "", mm, (argc > 0) ? 1 : 0);
Harald Welted193cb32010-05-17 22:58:03 +0200716
717 return CMD_SUCCESS;
718}
719
Harald Welted193cb32010-05-17 22:58:03 +0200720DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
721 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100722 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200723{
724 struct sgsn_pdp_ctx *pdp;
725
Pau Espin Pedrol15a52d92023-01-05 20:26:31 +0100726 llist_for_each_entry(pdp, &sgsn->pdp_list, g_list)
Harald Welted193cb32010-05-17 22:58:03 +0200727 vty_dump_pdp(vty, "", pdp);
728
729 return CMD_SUCCESS;
730}
Harald Welte288be162010-05-01 16:48:27 +0200731
Harald Welte7f6da482013-03-19 11:00:13 +0100732
733DEFUN(imsi_acl, cfg_imsi_acl_cmd,
734 "imsi-acl (add|del) IMSI",
735 "Access Control List of foreign IMSIs\n"
736 "Add IMSI to ACL\n"
737 "Remove IMSI from ACL\n"
738 "IMSI of subscriber\n")
739{
Maxef38b4c2018-11-20 10:25:53 +0100740 char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS + 1];
Harald Welte7f6da482013-03-19 11:00:13 +0100741 const char *op = argv[0];
Philipp Maier6ee49d82017-02-28 16:53:07 +0100742 const char *imsi = imsi_sanitized;
Maxf4fa6952018-01-15 12:12:51 +0100743 size_t len = strnlen(argv[1], GSM23003_IMSI_MAX_DIGITS + 1);
Harald Welte7f6da482013-03-19 11:00:13 +0100744 int rc;
745
Maxef38b4c2018-11-20 10:25:53 +0100746 memset(imsi_sanitized, '0', GSM23003_IMSI_MAX_DIGITS);
747 imsi_sanitized[GSM23003_IMSI_MAX_DIGITS] = '\0';
748
Philipp Maier6ee49d82017-02-28 16:53:07 +0100749 /* Sanitize IMSI */
Maxf4fa6952018-01-15 12:12:51 +0100750 if (len > GSM23003_IMSI_MAX_DIGITS) {
751 vty_out(vty, "%% IMSI (%s) too long (max %u digits) -- ignored!%s",
752 argv[1], GSM23003_IMSI_MAX_DIGITS, VTY_NEWLINE);
Philipp Maier6ee49d82017-02-28 16:53:07 +0100753 return CMD_WARNING;
754 }
Maxf4fa6952018-01-15 12:12:51 +0100755
756 osmo_strlcpy(imsi_sanitized + GSM23003_IMSI_MAX_DIGITS - len, argv[1],
757 sizeof(imsi_sanitized) - (GSM23003_IMSI_MAX_DIGITS - len));
Philipp Maier6ee49d82017-02-28 16:53:07 +0100758
Harald Welte7f6da482013-03-19 11:00:13 +0100759 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200760 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100761 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200762 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100763
764 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100765 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100766 return CMD_WARNING;
767 }
768
769 return CMD_SUCCESS;
770}
771
Eric2f898262021-05-19 18:57:50 +0200772DEFUN_DEPRECATED(cfg_encrypt, cfg_encrypt_cmd,
Max93408ae2016-06-28 14:10:16 +0200773 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
774 "Set encryption algorithm for SGSN\n"
775 "Use GEA0 (no encryption)\n"
776 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
777{
Max93408ae2016-06-28 14:10:16 +0200778 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
Eric2f898262021-05-19 18:57:50 +0200779
780 if (strcmp(argv[0], "gea") == 0)
781 return CMD_SUCCESS;
782
Max086067f2017-05-02 13:03:28 +0200783 if (c != GPRS_ALGO_GEA0) {
Eric2f898262021-05-19 18:57:50 +0200784 if (gprs_cipher_supported(c) <= 0) {
Max086067f2017-05-02 13:03:28 +0200785 vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
786 return CMD_WARNING;
787 }
788
789 if (!g_cfg->require_authentication) {
790 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
791 argv[0], VTY_NEWLINE);
792 return CMD_WARNING;
793 }
Max93408ae2016-06-28 14:10:16 +0200794 }
795
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100796 g_cfg->gea_encryption_mask |= (1 << c);
Eric2f898262021-05-19 18:57:50 +0200797
798 return CMD_SUCCESS;
799}
800
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +0100801#define ENCRYPTION_STR "Set encryption algorithms for SGSN\n"
802
Eric2f898262021-05-19 18:57:50 +0200803DEFUN(cfg_encrypt2, cfg_encrypt2_cmd,
804 "encryption gea <0-4> [<0-4>] [<0-4>] [<0-4>] [<0-4>]",
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +0100805 ENCRYPTION_STR
Eric2f898262021-05-19 18:57:50 +0200806 "GPRS Encryption Algorithm\n"
807 "GEAn Algorithm Number\n"
808 "GEAn Algorithm Number\n"
809 "GEAn Algorithm Number\n"
810 "GEAn Algorithm Number\n"
811 "GEAn Algorithm Number\n")
812{
813 int i = 0;
814
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100815 g_cfg->gea_encryption_mask = 0;
Eric2f898262021-05-19 18:57:50 +0200816 for (i = 0; i < argc; i++)
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100817 g_cfg->gea_encryption_mask |= (1 << atoi(argv[i]));
Eric2f898262021-05-19 18:57:50 +0200818
819 for (i = 0; i < _GPRS_ALGO_NUM; i++) {
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100820 if (g_cfg->gea_encryption_mask >> i & 1) {
Eric2f898262021-05-19 18:57:50 +0200821
822 if (i == GPRS_ALGO_GEA0)
823 continue;
824
825 if (gprs_cipher_supported(i) <= 0) {
826 vty_out(vty, "%% cipher %d is unsupported in current version%s", i, VTY_NEWLINE);
827 return CMD_ERR_INCOMPLETE;
828 }
829
830 if (!g_cfg->require_authentication) {
831 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
832 argv[i], VTY_NEWLINE);
833 return CMD_ERR_INCOMPLETE;
834 }
835
836 }
837 }
Max93408ae2016-06-28 14:10:16 +0200838
839 return CMD_SUCCESS;
840}
841
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700842DEFUN(cfg_authentication, cfg_authentication_cmd,
843 "authentication (optional|required)",
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200844 "Whether to enforce MS authentication in GERAN (only with auth-policy remote)\n"
845 "Allow MS to attach via GERAN without authentication (default and only possible value for non-remote auth-policy)\n"
846 "Always require authentication (only available for auth-policy remote, default with that auth-policy)\n")
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700847{
848 int required = (argv[0][0] == 'r');
849
850 if (vty->type != VTY_FILE) {
851 if (g_cfg->auth_policy != SGSN_AUTH_POLICY_REMOTE && required) {
852 vty_out(vty, "%% Authentication is not possible without HLR, "
853 "consider setting 'auth-policy' to 'remote'%s",
854 VTY_NEWLINE);
855 return CMD_WARNING;
856 }
857 }
858
859 g_cfg->require_authentication = required;
860 return CMD_SUCCESS;
861}
862
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +0100863DEFUN(cfg_encryption_uea, cfg_encryption_uea_cmd,
864 "encryption uea <0-2> [<0-2>] [<0-2>]",
865 ENCRYPTION_STR
866 "UTRAN (3G) encryption algorithms to allow: 0 = UEA0 (no encryption), 1 = UEA1, 2 = UEA2.\n"
867 "UEAn Algorithm Number\n"
868 "UEAn Algorithm Number\n"
869 "UEAn Algorithm Number\n")
870{
871 unsigned int i;
872
873 g_cfg->uea_encryption_mask = 0;
874 for (i = 0; i < argc; i++)
875 g_cfg->uea_encryption_mask |= (1 << atoi(argv[i]));
876
877 return CMD_SUCCESS;
878}
879
Harald Welte3dfb5492013-03-19 11:48:54 +0100880DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100881 "auth-policy (accept-all|closed|acl-only|remote)",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100882 "Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
883 " permitted to register to the network.\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100884 "Accept all IMSIs (DANGEROUS)\n"
885 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100886 "Accept only subscribers in the ACL\n"
887 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100888{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100889 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100890 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100891 g_cfg->auth_policy = val;
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100892 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100893
894 return CMD_SUCCESS;
895}
896
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100897/* Subscriber */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +0200898#include <osmocom/sgsn/gprs_subscriber.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100899
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100900static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100901{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100902#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100903 char expire_time[200];
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100904#endif
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100905 struct gsm_auth_tuple *at;
906 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100907 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100908
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100909 vty_out(vty, " Authorized: %d%s",
910 gsub->authorized, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100911 vty_out(vty, " LAC: %d/0x%x%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100912 gsub->lac, gsub->lac, VTY_NEWLINE);
913 vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
914 if (gsub->tmsi != GSM_RESERVED_TMSI)
915 vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100916 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100917 if (gsub->sgsn_data->msisdn_len > 0)
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400918 vty_out(vty, " MSISDN (BCD): %s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100919 osmo_hexdump(gsub->sgsn_data->msisdn,
920 gsub->sgsn_data->msisdn_len),
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400921 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100922
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100923 if (strlen(gsub->imei) > 0)
924 vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100925
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100926 for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100927 at_idx++) {
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100928 at = &gsub->sgsn_data->auth_triplets[at_idx];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100929 if (at->key_seq == GSM_KEY_SEQ_INVAL)
930 continue;
931
932 vty_out(vty, " A3A8 tuple (used %d times): ",
933 at->use_count);
Harald Welte89837d42016-05-06 23:28:11 +0200934 vty_out(vty, " CKSN: %d, ",
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100935 at->key_seq);
Harald Welte89837d42016-05-06 23:28:11 +0200936 if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
937 vty_out(vty, "RAND: %s, ",
Max34604c22019-02-13 14:11:29 +0100938 osmo_hexdump_nospc(at->vec.rand,
Harald Welte89837d42016-05-06 23:28:11 +0200939 sizeof(at->vec.rand)));
940 vty_out(vty, "SRES: %s, ",
Max34604c22019-02-13 14:11:29 +0100941 osmo_hexdump_nospc(at->vec.sres,
Harald Welte89837d42016-05-06 23:28:11 +0200942 sizeof(at->vec.sres)));
943 vty_out(vty, "Kc: %s%s",
Max34604c22019-02-13 14:11:29 +0100944 osmo_hexdump_nospc(at->vec.kc,
Harald Welte89837d42016-05-06 23:28:11 +0200945 sizeof(at->vec.kc)), VTY_NEWLINE);
946 }
947 if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
948 vty_out(vty, " AUTN: %s, ",
949 osmo_hexdump(at->vec.autn,
950 sizeof(at->vec.autn)));
951 vty_out(vty, "RES: %s, ",
Max34604c22019-02-13 14:11:29 +0100952 osmo_hexdump_nospc(at->vec.res, at->vec.res_len));
Harald Welte89837d42016-05-06 23:28:11 +0200953 vty_out(vty, "IK: %s, ",
Max34604c22019-02-13 14:11:29 +0100954 osmo_hexdump_nospc(at->vec.ik, sizeof(at->vec.ik)));
Harald Welte89837d42016-05-06 23:28:11 +0200955 vty_out(vty, "CK: %s, ",
Max34604c22019-02-13 14:11:29 +0100956 osmo_hexdump_nospc(at->vec.ck, sizeof(at->vec.ck)));
Harald Welte89837d42016-05-06 23:28:11 +0200957 }
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100958 }
959
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100960 llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
Max34604c22019-02-13 14:11:29 +0100961 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'",
962 pdp->context_id, pdp->pdp_type, pdp->apn_str);
963
964 if (pdp->qos_subscribed_len)
965 vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len));
966
967 vty_out(vty, "%s", VTY_NEWLINE);
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100968 }
969
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100970#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100971 /* print the expiration time of a subscriber */
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100972 if (gsub->expire_lu) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100973 strftime(expire_time, sizeof(expire_time),
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100974 "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100975 expire_time[sizeof(expire_time) - 1] = '\0';
976 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
977 }
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100978#endif
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100979
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100980 if (gsub->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100981 vty_out(vty, " Flags: %s%s%s%s%s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100982 gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100983 "FIRST_CONTACT " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100984 gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100985 "CANCELLED " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100986 gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100987 "UPDATE_LOCATION_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100988 gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100989 "AUTH_INFO_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100990 gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100991 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100992 VTY_NEWLINE);
993
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100994 vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100995}
996
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200997#define RESET_SGSN_STATE_STR \
998 "Remove all known subscribers, MM contexts and flush BSSGP queues." \
999 " Useful only when running tests against the SGSN\n"
1000
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001001DEFUN_HIDDEN(reset_sgsn_state,
1002 reset_sgsn_state_cmd,
1003 "reset sgsn state",
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +02001004 RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR)
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001005{
1006 struct gprs_subscr *subscr, *tmp_subscr;
1007 struct sgsn_mm_ctx *mm, *tmp_mm;
1008
1009 llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
1010 {
1011 gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
1012 }
1013 vty_out(vty, "Cancelled MM Ctx. %s", VTY_NEWLINE);
1014
1015 llist_for_each_entry_safe(subscr, tmp_subscr, gprs_subscribers, entry) {
1016 gprs_subscr_get(subscr);
1017 gprs_subscr_cancel(subscr);
1018 gprs_subscr_put(subscr);
1019 }
1020 vty_out(vty, "Removed all gprs subscribers.%s", VTY_NEWLINE);
1021
1022 bssgp_flush_all_queues();
1023 vty_out(vty, "Flushed all BSSGPs queues.%s", VTY_NEWLINE);
1024
Alexander Couzens35c34942018-09-17 04:39:14 +02001025 gtp_clear_queues(sgsn->gsn);
Alexander Couzensa66f0f22018-09-18 16:09:18 +02001026 vty_out(vty, "Flushed rx & tx queus towards the GGSN.%s", VTY_NEWLINE);
Alexander Couzens35c34942018-09-17 04:39:14 +02001027
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001028 /* remove all queues to bssgp */
1029 return CMD_SUCCESS;
1030}
1031
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001032DEFUN(show_subscr_cache,
1033 show_subscr_cache_cmd,
1034 "show subscriber cache",
1035 SHOW_STR "Show information about subscribers\n"
1036 "Display contents of subscriber cache\n")
1037{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001038 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001039
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001040 llist_for_each_entry(subscr, gprs_subscribers, entry) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001041 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
1042 subscr_dump_full_vty(vty, subscr, 0);
1043 }
1044
1045 return CMD_SUCCESS;
1046}
1047
1048#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
1049#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
1050 "Use the IMSI to select the subscriber\n" \
1051 "The IMSI\n"
1052
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001053#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
1054
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001055DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
1056 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
1057 UPDATE_SUBSCR_HELP
1058 UPDATE_SUBSCR_INSERT_HELP
1059 "Update authentication triplet\n"
1060 "Triplet index\n"
1061 "Set SRES value\nSRES value (4 byte) in hex\n"
1062 "Set RAND value\nRAND value (16 byte) in hex\n"
1063 "Set Kc value\nKc value (8 byte) in hex\n")
1064{
1065 const char *imsi = argv[0];
1066 const int cksn = atoi(argv[1]) - 1;
1067 const char *sres_str = argv[2];
1068 const char *rand_str = argv[3];
1069 const char *kc_str = argv[4];
1070 struct gsm_auth_tuple at = {0,};
1071
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001072 struct gprs_subscr *subscr;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001073
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001074 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001075 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001076 vty_out(vty, "%% unable get subscriber record for %s%s",
1077 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001078 return CMD_WARNING;
1079 }
1080
1081 OSMO_ASSERT(subscr->sgsn_data);
1082
Harald Welte121e9a42016-04-20 13:13:19 +02001083 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001084 vty_out(vty, "%% invalid SRES value '%s'%s",
1085 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001086 goto failed;
1087 }
Harald Welte121e9a42016-04-20 13:13:19 +02001088 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001089 vty_out(vty, "%% invalid RAND value '%s'%s",
1090 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001091 goto failed;
1092 }
Harald Welte121e9a42016-04-20 13:13:19 +02001093 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001094 vty_out(vty, "%% invalid Kc value '%s'%s",
1095 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001096 goto failed;
1097 }
1098 at.key_seq = cksn;
1099
1100 subscr->sgsn_data->auth_triplets[cksn] = at;
1101 subscr->sgsn_data->auth_triplets_updated = 1;
1102
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001103 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001104
1105 return CMD_SUCCESS;
1106
1107failed:
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001108 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001109 return CMD_SUCCESS;
1110}
1111
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001112DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001113 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001114 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001115 "Cancel (remove) subscriber record\n"
1116 "The MS moved to another SGSN\n"
1117 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001118{
1119 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001120 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001121
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001122 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001123
1124 subscr = gprs_subscr_get_by_imsi(imsi);
1125 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001126 vty_out(vty, "%% no subscriber record for %s%s",
1127 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001128 return CMD_WARNING;
1129 }
1130
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001131 if (strcmp(cancel_type, "update-procedure") == 0)
1132 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
1133 else
1134 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
1135
Jacob Erlbeck37139e52015-01-23 13:52:55 +01001136 gprs_subscr_cancel(subscr);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001137 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001138
1139 return CMD_SUCCESS;
1140}
1141
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001142DEFUN(update_subscr_create, update_subscr_create_cmd,
1143 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001144 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001145 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001146{
1147 const char *imsi = argv[0];
1148
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001149 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001150
1151 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001152 if (subscr) {
1153 vty_out(vty, "%% subscriber record already exists for %s%s",
1154 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001155 return CMD_WARNING;
1156 }
1157
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001158 subscr = gprs_subscr_get_or_create(imsi);
Alexander Couzens3326ba72020-12-09 22:02:55 +01001159 if (!subscr) {
1160 vty_out(vty, "Can not create subscriber. Out of memory.%s", imsi);
1161 return CMD_WARNING;
1162 }
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001163 subscr->keep_in_ram = 1;
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001164 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001165
1166 return CMD_SUCCESS;
1167}
1168
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001169DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
1170 UPDATE_SUBSCR_STR "destroy",
1171 UPDATE_SUBSCR_HELP
1172 "Destroy a subscriber entry\n")
1173{
1174 const char *imsi = argv[0];
1175
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001176 struct gprs_subscr *subscr;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001177
1178 subscr = gprs_subscr_get_by_imsi(imsi);
1179 if (!subscr) {
1180 vty_out(vty, "%% subscriber record does not exist for %s%s",
1181 imsi, VTY_NEWLINE);
1182 return CMD_WARNING;
1183 }
1184
1185 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001186 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001187 gprs_subscr_cancel(subscr);
1188 if (subscr->use_count > 1)
1189 vty_out(vty, "%% subscriber is still in use%s",
1190 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001191 gprs_subscr_put(subscr);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001192
1193 return CMD_SUCCESS;
1194}
1195
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001196#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
1197 "unknown-subscriber|roaming-not-allowed"
1198
1199#define UL_ERR_HELP \
1200 "Force error code SystemFailure\n" \
1201 "Force error code DataMissing\n" \
1202 "Force error code UnexpectedDataValue\n" \
1203 "Force error code UnknownSubscriber\n" \
1204 "Force error code RoamingNotAllowed\n"
1205
1206DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
1207 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
1208 UPDATE_SUBSCR_HELP
1209 "Complete the update location procedure\n"
1210 "The update location request succeeded\n"
1211 UL_ERR_HELP)
1212{
1213 const char *imsi = argv[0];
1214 const char *ret_code_str = argv[1];
1215
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001216 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001217
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001218 const struct value_string cause_mapping[] = {
1219 { GMM_CAUSE_NET_FAIL, "system-failure" },
1220 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
1221 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
1222 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
1223 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
1224 { 0, NULL }
1225 };
1226
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001227 subscr = gprs_subscr_get_by_imsi(imsi);
1228 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001229 vty_out(vty, "%% unable to get subscriber record for %s%s",
1230 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001231 return CMD_WARNING;
1232 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001233
1234 if (strcmp(ret_code_str, "ok") == 0) {
1235 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001236 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001237 } else {
1238 subscr->sgsn_data->error_cause =
1239 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001240 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001241 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001242
1243 gprs_subscr_update(subscr);
1244
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001245 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001246
1247 return CMD_SUCCESS;
1248}
1249
1250DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
1251 UPDATE_SUBSCR_STR "update-auth-info",
1252 UPDATE_SUBSCR_HELP
1253 "Complete the send authentication info procedure\n")
1254{
1255 const char *imsi = argv[0];
1256
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001257 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001258
1259 subscr = gprs_subscr_get_by_imsi(imsi);
1260 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001261 vty_out(vty, "%% unable to get subscriber record for %s%s",
1262 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001263 return CMD_WARNING;
1264 }
1265
1266 gprs_subscr_update_auth_info(subscr);
1267
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001268 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001269
1270 return CMD_SUCCESS;
1271}
1272
Oliver Smithab39b622021-07-05 15:41:05 +02001273DEFUN(page_subscr, page_subscr_info_cmd,
1274 "page imsi IMSI",
1275 "Send a PS paging request to subscriber\n"
1276 "Use the IMSI to select the subscriber\n"
1277 "The IMSI\n")
1278{
1279 const char *imsi = argv[0];
1280 struct sgsn_mm_ctx *mm;
1281
1282 mm = sgsn_mm_ctx_by_imsi(imsi);
1283 if (!mm) {
1284 vty_out(vty, "No MM context for IMSI %s%s", imsi, VTY_NEWLINE);
1285 return CMD_WARNING;
1286 }
1287
Pau Espin Pedrol7a74ae42022-12-23 16:33:17 +01001288 sgsn_bssgp_page_ps_ra(mm);
Oliver Smithab39b622021-07-05 15:41:05 +02001289 return CMD_SUCCESS;
1290}
1291
Stefan Sperling88220092018-12-11 14:42:00 +01001292DEFUN(cfg_gsup_ipa_name,
1293 cfg_gsup_ipa_name_cmd,
1294 "gsup ipa-name NAME",
1295 "GSUP Parameters\n"
1296 "Set the IPA name of this SGSN\n"
1297 "A unique name for this SGSN. For example: PLMN + redundancy server number: SGSN-901-70-0. "
1298 "This name is used for GSUP routing and must be set if more than one SGSN is connected to the network. "
1299 "The default is 'SGSN-00-00-00-00-00-00'.\n")
1300{
1301 if (vty->type != VTY_FILE) {
1302 vty_out(vty, "The IPA name cannot be changed at run-time; "
1303 "It can only be set in the configuraton file.%s", VTY_NEWLINE);
1304 return CMD_WARNING;
1305 }
1306
1307 g_cfg->sgsn_ipa_name = talloc_strdup(tall_vty_ctx, argv[0]);
1308 return CMD_SUCCESS;
1309}
1310
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001311DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
1312 "gsup remote-ip A.B.C.D",
1313 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001314 "Set the IP address of the remote GSUP server (e.g. OsmoHLR)."
1315 " This setting only applies if 'auth-policy remote' is used.\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001316 "IPv4 Address\n")
1317{
1318 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
1319
1320 return CMD_SUCCESS;
1321}
1322
1323DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
1324 "gsup remote-port <0-65535>",
1325 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001326 "Set the TCP port of the remote GSUP server, see also 'gsup remote-ip'\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001327 "Remote TCP port\n")
1328{
1329 g_cfg->gsup_server_port = atoi(argv[0]);
1330
1331 return CMD_SUCCESS;
1332}
1333
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001334DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
1335 "gsup oap-id <0-65535>",
1336 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001337 "Set the OAP client ID for authentication on the GSUP protocol."
1338 " This setting only applies if 'auth-policy remote' is used.\n"
1339 "OAP client ID (0 == disabled)\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001340{
1341 /* VTY ensures range */
1342 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
1343 return CMD_SUCCESS;
1344}
1345
1346DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
1347 "gsup oap-k K",
1348 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001349 "Set the OAP shared secret key K for authentication on the GSUP protocol."
1350 " This setting only applies if auth-policy remote is used.\n"
1351 "K value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001352{
1353 const char *k = argv[0];
1354
1355 g_cfg->oap.secret_k_present = 0;
1356
1357 if ((!k) || (strlen(k) == 0))
1358 goto disable;
1359
1360 int k_len = osmo_hexparse(k,
1361 g_cfg->oap.secret_k,
1362 sizeof(g_cfg->oap.secret_k));
1363 if (k_len != 16) {
1364 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
1365 k_len, VTY_NEWLINE);
1366 goto disable;
1367 }
1368
1369 g_cfg->oap.secret_k_present = 1;
1370 return CMD_SUCCESS;
1371
1372disable:
1373 if (g_cfg->oap.client_id > 0) {
1374 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
1375 VTY_NEWLINE);
1376 return CMD_WARNING;
1377 }
1378 return CMD_SUCCESS;
1379}
1380
1381DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1382 "gsup oap-opc OPC",
1383 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001384 "Set the OAP shared secret OPC for authentication on the GSUP protocol."
1385 " This setting only applies if auth-policy remote is used.\n"
1386 "OPC value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001387{
1388 const char *opc = argv[0];
1389
1390 g_cfg->oap.secret_opc_present = 0;
1391
1392 if ((!opc) || (strlen(opc) == 0))
1393 goto disable;
1394
1395 int opc_len = osmo_hexparse(opc,
1396 g_cfg->oap.secret_opc,
1397 sizeof(g_cfg->oap.secret_opc));
1398 if (opc_len != 16) {
1399 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1400 opc_len, VTY_NEWLINE);
1401 goto disable;
1402 }
1403
1404 g_cfg->oap.secret_opc_present = 1;
1405 return CMD_SUCCESS;
1406
1407disable:
1408 if (g_cfg->oap.client_id > 0) {
1409 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1410 VTY_NEWLINE);
1411 return CMD_WARNING;
1412 }
1413 return CMD_SUCCESS;
1414}
1415
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001416DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1417 "access-point-name NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001418 "Globally allow the given APN name for all subscribers.\n"
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001419 "Add this NAME to the list\n")
1420{
1421 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1422}
1423
1424DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1425 "no access-point-name NAME",
1426 NO_STR "Configure a global list of allowed APNs\n"
1427 "Remove entry with NAME\n")
1428{
1429 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1430 if (!apn_ctx)
1431 return CMD_SUCCESS;
1432
1433 sgsn_apn_ctx_free(apn_ctx);
1434 return CMD_SUCCESS;
1435}
1436
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001437DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1438 "cdr filename NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001439 "CDR\n"
1440 "Set the file name for the call-data-record file, logging the data usage of each subscriber.\n"
1441 "filename\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001442{
1443 talloc_free(g_cfg->cdr.filename);
1444 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1445 return CMD_SUCCESS;
1446}
1447
1448DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1449 "no cdr filename",
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001450 NO_STR "CDR\nDisable saving CDR to file\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001451{
1452 talloc_free(g_cfg->cdr.filename);
1453 g_cfg->cdr.filename = NULL;
1454 return CMD_SUCCESS;
1455}
1456
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001457DEFUN(cfg_cdr_trap, cfg_cdr_trap_cmd,
1458 "cdr trap",
1459 "CDR\nEnable sending CDR via TRAP CTRL messages\n")
1460{
1461 g_cfg->cdr.trap = true;
1462 return CMD_SUCCESS;
1463}
1464
1465DEFUN(cfg_no_cdr_trap, cfg_no_cdr_trap_cmd,
1466 "no cdr trap",
1467 NO_STR "CDR\nDisable sending CDR via TRAP CTRL messages\n")
1468{
1469 g_cfg->cdr.trap = false;
1470 return CMD_SUCCESS;
1471}
1472
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001473DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1474 "cdr interval <1-2147483647>",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001475 "CDR\n"
1476 "Set the interval for the call-data-record file\n"
1477 "interval in seconds\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001478{
1479 g_cfg->cdr.interval = atoi(argv[0]);
1480 return CMD_SUCCESS;
1481}
1482
Philippf1f34362016-08-26 17:00:21 +02001483#define COMPRESSION_STR "Configure compression\n"
1484DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1485 "no compression rfc1144",
1486 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1487{
1488 g_cfg->pcomp_rfc1144.active = 0;
1489 g_cfg->pcomp_rfc1144.passive = 0;
1490 return CMD_SUCCESS;
1491}
1492
1493DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1494 "compression rfc1144 active slots <1-256>",
1495 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001496 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001497 "Compression is actively proposed\n"
1498 "Number of compression state slots\n"
1499 "Number of compression state slots\n")
1500{
1501 g_cfg->pcomp_rfc1144.active = 1;
1502 g_cfg->pcomp_rfc1144.passive = 1;
1503 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1504 return CMD_SUCCESS;
1505}
1506
1507DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1508 "compression rfc1144 passive",
1509 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001510 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001511 "Compression is available on request\n")
1512{
1513 g_cfg->pcomp_rfc1144.active = 0;
1514 g_cfg->pcomp_rfc1144.passive = 1;
1515 return CMD_SUCCESS;
1516}
1517
Philipp73f83d52016-09-02 13:38:01 +02001518DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
1519 "no compression v42bis",
1520 NO_STR COMPRESSION_STR "disable V.42bis data compression\n")
1521{
1522 g_cfg->dcomp_v42bis.active = 0;
1523 g_cfg->dcomp_v42bis.passive = 0;
1524 return CMD_SUCCESS;
1525}
1526
1527DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
1528 "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
1529 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001530 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001531 "Compression is actively proposed\n"
1532 "Direction in which the compression shall be active (p0)\n"
1533 "Compress ms->sgsn direction only\n"
1534 "Compress sgsn->ms direction only\n"
1535 "Both directions\n"
1536 "Number of codewords (p1)\n"
1537 "Number of codewords\n"
1538 "Maximum string length (p2)\n" "Maximum string length\n")
1539{
1540 g_cfg->dcomp_v42bis.active = 1;
1541 g_cfg->dcomp_v42bis.passive = 1;
1542
1543 switch (argv[0][0]) {
1544 case 'm':
1545 g_cfg->dcomp_v42bis.p0 = 1;
1546 break;
1547 case 's':
1548 g_cfg->dcomp_v42bis.p0 = 2;
1549 break;
1550 case 'b':
1551 g_cfg->dcomp_v42bis.p0 = 3;
1552 break;
1553 }
1554
1555 g_cfg->dcomp_v42bis.p1 = atoi(argv[1]);
1556 g_cfg->dcomp_v42bis.p2 = atoi(argv[2]);
1557 return CMD_SUCCESS;
1558}
1559
1560DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
1561 "compression v42bis passive",
1562 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001563 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001564 "Compression is available on request\n")
1565{
1566 g_cfg->dcomp_v42bis.active = 0;
1567 g_cfg->dcomp_v42bis.passive = 1;
1568 return CMD_SUCCESS;
1569}
1570
Pau Espin Pedrol2c908992019-08-19 19:06:06 +02001571#if BUILD_IU
1572DEFUN(cfg_sgsn_cs7_instance_iu,
1573 cfg_sgsn_cs7_instance_iu_cmd,
1574 "cs7-instance-iu <0-15>",
1575 "Set SS7 to be used by the Iu-Interface.\n" "SS7 instance reference number (default: 0)\n")
1576{
1577 g_cfg->iu.cs7_instance = atoi(argv[0]);
1578 return CMD_SUCCESS;
1579}
1580#endif
1581
Pau Espin Pedrole5c89982021-05-03 18:16:42 +02001582DEFUN(cfg_sgsn_mme, cfg_sgsn_mme_cmd,
1583 "mme NAME",
1584 "Configure an MME peer\n"
1585 "Name identifying the MME peer\n")
1586{
1587 struct sgsn_mme_ctx *mme;
1588
1589 mme = sgsn_mme_ctx_find_alloc(sgsn, argv[0]);
1590 if (!mme)
1591 return CMD_WARNING;
1592
1593 vty->node = MME_NODE;
1594 vty->index = mme;
1595
1596 return CMD_SUCCESS;
1597}
1598
1599DEFUN(cfg_sgsn_no_mme, cfg_sgsn_no_mme_cmd,
1600 "no mme NAME",
1601 NO_STR "Delete an MME peer configuration\n"
1602 "Name identifying the MME peer\n")
1603{
1604 struct sgsn_mme_ctx *mme;
1605
1606 mme = sgsn_mme_ctx_by_name(sgsn, argv[0]);
1607 if (!mme) {
1608 vty_out(vty, "%% MME %s doesn't exist.%s",
1609 argv[0], VTY_NEWLINE);
1610 return CMD_WARNING;
1611 }
1612
1613 sgsn_mme_ctx_free(mme);
1614
1615 return CMD_SUCCESS;
1616}
1617
1618#define GTP_STR "Configure GTP connection\n"
1619
1620DEFUN(cfg_mme_remote_ip, cfg_mme_remote_ip_cmd,
1621 "gtp remote-ip A.B.C.D",
1622 GTP_STR "Set Remote GTP IP address\n" IP_STR)
1623{
1624 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1625
1626 inet_aton(argv[0], &mme->remote_addr);
1627
1628 return CMD_SUCCESS;
1629}
1630
1631#define RAN_INFO_STR "Configure RAN Information Relay routing\n"
1632#define TAI_DOC "MCC\n" "MNC\n" "TAC\n"
1633
1634DEFUN(cfg_mme_ran_info_relay_tai, cfg_mme_ran_info_relay_tai_cmd,
1635 "gtp ran-info-relay <0-999> <0-999> <0-65535>",
1636 GTP_STR RAN_INFO_STR TAI_DOC)
1637{
1638 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1639 struct sgsn_mme_ctx *mme_tmp;
1640 struct osmo_eutran_tai tai;
1641
1642 const char *mcc = argv[0];
1643 const char *mnc = argv[1];
1644 const char *tac = argv[2];
1645
1646 if (osmo_mcc_from_str(mcc, &tai.mcc)) {
1647 vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
1648 return CMD_WARNING;
1649 }
1650 if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
1651 vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
1652 return CMD_WARNING;
1653 }
1654 tai.tac = atoi(tac);
1655
1656 if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
1657 if (mme_tmp != mme) {
1658 vty_out(vty, "%% Another MME %s already contains this route%s",
1659 mme_tmp->name, VTY_NEWLINE);
1660 return CMD_WARNING;
1661 }
1662 /* else: NO-OP, return */
1663 return CMD_SUCCESS;
1664 }
1665
1666 sgsn_mme_ctx_route_add(mme, &tai);
1667 return CMD_SUCCESS;
1668}
1669
1670DEFUN(cfg_mme_no_ran_info_relay_tai, cfg_mme_no_ran_info_relay_tai_cmd,
1671 "no gtp ran-info-relay <0-999> <0-999> <0-65535>",
1672 NO_STR GTP_STR RAN_INFO_STR TAI_DOC)
1673{
1674 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1675 struct sgsn_mme_ctx *mme_tmp;
1676 struct osmo_eutran_tai tai;
1677
1678 const char *mcc = argv[0];
1679 const char *mnc = argv[1];
1680 const char *tac = argv[2];
1681
1682 if (osmo_mcc_from_str(mcc, &tai.mcc)) {
1683 vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
1684 return CMD_WARNING;
1685 }
1686 if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
1687 vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
1688 return CMD_WARNING;
1689 }
1690 tai.tac = atoi(tac);
1691
1692 if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
1693 if (mme_tmp != mme) {
1694 vty_out(vty, "%% Another MME %s contains this route%s",
1695 mme_tmp->name, VTY_NEWLINE);
1696 return CMD_WARNING;
1697 }
1698 sgsn_mme_ctx_route_del(mme, &tai);
1699 return CMD_SUCCESS;
1700 } else {
1701 vty_out(vty, "%% This route doesn't exist in current MME %s%s",
1702 mme->name, VTY_NEWLINE);
1703 return CMD_WARNING;
1704 }
1705}
1706
1707DEFUN(cfg_mme_ran_info_relay_default, cfg_mme_ran_info_relay_default_cmd,
1708 "gtp ran-info-relay default",
1709 GTP_STR RAN_INFO_STR "Set as default route")
1710{
1711 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1712 struct sgsn_mme_ctx *default_mme;
1713
1714 if (mme->default_route)
1715 return CMD_SUCCESS; /* NO-OP */
1716
1717 if ((default_mme = sgsn_mme_ctx_by_default_route(sgsn))) {
1718 vty_out(vty, "%% Another MME %s is already set as default route, "
1719 "remove it before setting it here.%s",
1720 default_mme->name, VTY_NEWLINE);
1721 return CMD_WARNING;
1722 }
1723
1724 mme->default_route = true;
1725 return CMD_SUCCESS;
1726}
1727
1728DEFUN(cfg_mme_no_ran_info_relay_default, cfg_mme_no_ran_info_relay_default_cmd,
1729 "no gtp ran-info-relay default",
1730 NO_STR GTP_STR RAN_INFO_STR "Set as default route")
1731{
1732 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1733 mme->default_route = false;
1734 return CMD_SUCCESS;
1735}
1736
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001737int sgsn_vty_init(struct sgsn_config *cfg)
Harald Welte288be162010-05-01 16:48:27 +02001738{
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001739 g_cfg = cfg;
1740
Harald Welted193cb32010-05-17 22:58:03 +02001741 install_element_ve(&show_sgsn_cmd);
1742 //install_element_ve(&show_mmctx_tlli_cmd);
1743 install_element_ve(&show_mmctx_imsi_cmd);
1744 install_element_ve(&show_mmctx_all_cmd);
1745 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001746 install_element_ve(&show_subscr_cache_cmd);
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001747 install_element_ve(&show_timer_cmd);
Pau Espin Pedrol85011262022-11-02 20:23:09 +01001748 install_element_ve(&show_timer_gtp_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001749
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001750 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001751 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001752 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001753 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001754 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1755 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Oliver Smithab39b622021-07-05 15:41:05 +02001756 install_element(ENABLE_NODE, &page_subscr_info_cmd);
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001757 install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001758
1759 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1760 install_node(&sgsn_node, config_write_sgsn);
Keithc70e8382020-10-19 22:24:48 +02001761 install_element(SGSN_NODE, &cfg_sgsn_state_dir_cmd);
Harald Weltee300d002010-06-02 12:41:34 +02001762 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001763 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1764 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1765 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +02001766 install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +02001767 install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001768 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001769 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Vadim Yanitskiy794f4462019-05-27 05:39:06 +07001770 install_element(SGSN_NODE, &cfg_authentication_cmd);
Eric2f898262021-05-19 18:57:50 +02001771
1772 /* order matters here: ensure we attempt to parse our new command first! */
1773 install_element(SGSN_NODE, &cfg_encrypt2_cmd);
Max93408ae2016-06-28 14:10:16 +02001774 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +01001775 install_element(SGSN_NODE, &cfg_encryption_uea_cmd);
Eric2f898262021-05-19 18:57:50 +02001776
Stefan Sperling88220092018-12-11 14:42:00 +01001777 install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001778 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1779 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001780 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1781 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1782 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001783 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1784 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001785 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1786 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001787 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1788 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001789 install_element(SGSN_NODE, &cfg_cdr_trap_cmd);
1790 install_element(SGSN_NODE, &cfg_no_cdr_trap_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001791 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001792 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001793 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001794
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001795 install_element(SGSN_NODE, &cfg_sgsn_timer_cmd);
Pau Espin Pedrol85011262022-11-02 20:23:09 +01001796 install_element(SGSN_NODE, &cfg_sgsn_timer_gtp_cmd);
Harald Welte94508822015-08-15 19:08:21 +02001797
Philippf1f34362016-08-26 17:00:21 +02001798 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1799 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1800 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
Philipp73f83d52016-09-02 13:38:01 +02001801 install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd);
1802 install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
1803 install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001804
Pau Espin Pedrole5c89982021-05-03 18:16:42 +02001805 install_element(SGSN_NODE, &cfg_sgsn_mme_cmd);
1806 install_element(SGSN_NODE, &cfg_sgsn_no_mme_cmd);
1807 install_node(&mme_node, NULL);
1808 install_element(MME_NODE, &cfg_mme_remote_ip_cmd);
1809 install_element(MME_NODE, &cfg_mme_ran_info_relay_default_cmd);
1810 install_element(MME_NODE, &cfg_mme_no_ran_info_relay_default_cmd);
1811 install_element(MME_NODE, &cfg_mme_ran_info_relay_tai_cmd);
1812 install_element(MME_NODE, &cfg_mme_no_ran_info_relay_tai_cmd);
1813
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001814#ifdef BUILD_IU
Pau Espin Pedrol2c908992019-08-19 19:06:06 +02001815 install_element(SGSN_NODE, &cfg_sgsn_cs7_instance_iu_cmd);
Neels Hofmeyra7a39472017-07-05 15:19:52 +02001816 ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001817#endif
Harald Welte288be162010-05-01 16:48:27 +02001818 return 0;
1819}
1820
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001821int sgsn_parse_config(const char *config_file)
Harald Welte288be162010-05-01 16:48:27 +02001822{
1823 int rc;
1824
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001825 /* make sure sgsn_vty_init() was called before this */
1826 OSMO_ASSERT(g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +01001827
Neels Hofmeyr340a7e92022-03-07 15:37:24 +01001828 g_cfg->gea_encryption_mask = 0x1; /* support GEA0 by default unless specific encryption config exists */
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +01001829 g_cfg->uea_encryption_mask = (1 << OSMO_UTRAN_UEA0); /* support UEA0 by default unless specific encryption config exists */
Eric2f898262021-05-19 18:57:50 +02001830
Harald Weltedcccb182010-05-16 20:52:23 +02001831 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001832 if (rc < 0) {
1833 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1834 return rc;
1835 }
1836
Neels Hofmeyr27355c92017-02-24 06:28:31 +01001837 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE
1838 && !(g_cfg->gsup_server_addr.sin_addr.s_addr
1839 && g_cfg->gsup_server_port)) {
1840 fprintf(stderr, "Configuration error:"
1841 " 'auth-policy remote' requires both"
1842 " 'gsup remote-ip' and 'gsup remote-port'\n");
1843 return -EINVAL;
1844 }
1845
Harald Welte288be162010-05-01 16:48:27 +02001846 return 0;
1847}