blob: 0929f1fa4ddea6e5d97beffa9b7cf30956b8e9a7 [file] [log] [blame]
Harald Welte288be162010-05-01 16:48:27 +02001/*
Harald Welte89837d42016-05-06 23:28:11 +02002 * (C) 2010-2016 by Harald Welte <laforge@gnumonks.org>
Harald Welte288be162010-05-01 16:48:27 +02003 * (C) 2010 by On-Waves
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02004 * (C) 2015 by Holger Hans Peter Freyther
Harald Welte288be162010-05-01 16:48:27 +02005 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01008 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
Harald Welte288be162010-05-01 16:48:27 +020010 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010015 * GNU Affero General Public License for more details.
Harald Welte288be162010-05-01 16:48:27 +020016 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte288be162010-05-01 16:48:27 +020019 *
20 */
21
Harald Welte288be162010-05-01 16:48:27 +020022#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +010025#include <time.h>
Pau Espin Pedrolfa120102018-07-09 20:37:47 +020026#include <inttypes.h>
Harald Welte288be162010-05-01 16:48:27 +020027
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010028#include <osmocom/core/talloc.h>
29#include <osmocom/core/utils.h>
30#include <osmocom/core/rate_ctr.h>
Pau Espin Pedrola299d652019-08-14 19:11:10 +020031#include <osmocom/core/tdef.h>
Harald Welte53373bc2016-04-20 17:11:43 +020032#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
Harald Welte7e82b742017-08-12 13:43:54 +020033#include <osmocom/gsm/apn.h>
Harald Welte288be162010-05-01 16:48:27 +020034
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020035#include <osmocom/sgsn/debug.h>
36#include <osmocom/sgsn/sgsn.h>
Alexander Couzensf23e2db2020-07-27 22:39:58 +020037#include <osmocom/gprs/gprs_ns2.h>
Oliver Smithab39b622021-07-05 15:41:05 +020038#include <osmocom/sgsn/gprs_gb.h>
Alexander Couzensc503f0a2018-08-07 17:50:04 +020039#include <osmocom/sgsn/gprs_gmm.h>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020040#include <osmocom/sgsn/gprs_sgsn.h>
Pau Espin Pedrole5c89982021-05-03 18:16:42 +020041#include <osmocom/sgsn/gtp_mme.h>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020042#include <osmocom/sgsn/vty.h>
Harald Weltef4b2c4c2018-09-16 07:53:41 +020043#include <osmocom/gsupclient/gsup_client.h>
Harald Welte288be162010-05-01 16:48:27 +020044
Pau Espin Pedrola299d652019-08-14 19:11:10 +020045#include <osmocom/vty/tdef_vty.h>
Harald Welte4b037e42010-05-19 19:45:32 +020046#include <osmocom/vty/command.h>
47#include <osmocom/vty/vty.h>
Pablo Neira Ayuso6110a3f2011-03-28 19:35:00 +020048#include <osmocom/vty/misc.h>
Max93408ae2016-06-28 14:10:16 +020049#include <osmocom/crypt/gprs_cipher.h>
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +010050#include <osmocom/crypt/utran_cipher.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010051#include <osmocom/abis/ipa.h>
52
Alexander Couzensc503f0a2018-08-07 17:50:04 +020053#include <osmocom/gprs/gprs_bssgp.h>
54
Harald Welted193cb32010-05-17 22:58:03 +020055#include <pdp.h>
Maxbaabc682017-10-20 13:39:57 +020056#include <gtp.h>
Harald Welted193cb32010-05-17 22:58:03 +020057
Neels Hofmeyr2188a772016-05-20 21:59:55 +020058#include "../../bscconfig.h"
59
60#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +020061#include <osmocom/ranap/iu_client.h>
Neels Hofmeyr2188a772016-05-20 21:59:55 +020062#endif
63
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +010064extern void *tall_sgsn_ctx;
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020065
Harald Welte288be162010-05-01 16:48:27 +020066static struct sgsn_config *g_cfg = NULL;
67
Jacob Erlbeck106f5472014-11-04 10:08:37 +010068const struct value_string sgsn_auth_pol_strs[] = {
69 { SGSN_AUTH_POLICY_OPEN, "accept-all" },
70 { SGSN_AUTH_POLICY_CLOSED, "closed" },
71 { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" },
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +010072 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeck106f5472014-11-04 10:08:37 +010073 { 0, NULL }
74};
75
Harald Welte94508822015-08-15 19:08:21 +020076/* Section 11.2.2 / Table 11.3a GPRS Mobility management timers – MS side */
77#define GSM0408_T3312_SECS (10*60) /* periodic RAU interval, default 54min */
78
79/* Section 11.2.2 / Table 11.4 MM timers netwokr side */
80#define GSM0408_T3322_SECS 6 /* DETACH_REQ -> DETACH_ACC */
81#define GSM0408_T3350_SECS 6 /* waiting for ATT/RAU/TMSI COMPL */
82#define GSM0408_T3360_SECS 6 /* waiting for AUTH/CIPH RESP */
83#define GSM0408_T3370_SECS 6 /* waiting for ID RESP */
84
Alexander Couzens5ba6fb32017-01-31 18:04:27 +010085/* Section 11.2.2 / Table 11.4a MM timers network side */
Harald Welte94508822015-08-15 19:08:21 +020086#define GSM0408_T3313_SECS 30 /* waiting for paging response */
87#define GSM0408_T3314_SECS 44 /* force to STBY on expiry, Ready timer */
88#define GSM0408_T3316_SECS 44
89
90/* Section 11.3 / Table 11.2d Timers of Session Management - network side */
91#define GSM0408_T3385_SECS 8 /* wait for ACT PDP CTX REQ */
92#define GSM0408_T3386_SECS 8 /* wait for MODIFY PDP CTX ACK */
93#define GSM0408_T3395_SECS 8 /* wait for DEACT PDP CTX ACK */
94#define GSM0408_T3397_SECS 8 /* wait for DEACT AA PDP CTX ACK */
95
Alexander Couzensafadd102019-10-08 14:30:59 +020096/* Non spec timer */
97#define NONSPEC_X1001_SECS 5 /* wait for a RANAP Release Complete */
98
Pau Espin Pedrola299d652019-08-14 19:11:10 +020099
100static struct osmo_tdef sgsn_T_defs[] = {
101 { .T=3312, .default_val=GSM0408_T3312_SECS, .desc="Periodic RA Update timer (s)" },
102 { .T=3313, .default_val=GSM0408_T3313_SECS, .desc="Waiting for paging response timer (s)" },
Alexander Couzens39cbecd2017-02-03 22:16:05 +0100103 { .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 +0200104 { .T=3316, .default_val=GSM0408_T3316_SECS, .desc="AA-Ready timer (s)" },
105 { .T=3322, .default_val=GSM0408_T3322_SECS, .desc="Detach request -> accept timer (s)" },
106 { .T=3350, .default_val=GSM0408_T3350_SECS, .desc="Waiting for ATT/RAU/TMSI_COMPL timer (s)" },
107 { .T=3360, .default_val=GSM0408_T3360_SECS, .desc="Waiting for AUTH/CIPH response timer (s)" },
108 { .T=3370, .default_val=GSM0408_T3370_SECS, .desc="Waiting for IDENTITY response timer (s)" },
109 { .T=3385, .default_val=GSM0408_T3385_SECS, .desc="Wait for ACT PDP CTX REQ timer (s)" },
110 { .T=3386, .default_val=GSM0408_T3386_SECS, .desc="Wait for MODIFY PDP CTX ACK timer (s)" },
111 { .T=3395, .default_val=GSM0408_T3395_SECS, .desc="Wait for DEACT PDP CTX ACK timer (s)" },
112 { .T=3397, .default_val=GSM0408_T3397_SECS, .desc="Wait for DEACT AA PDP CTX ACK timer (s)" },
Alexander Couzens3bad31b2019-09-11 02:17:31 +0200113 /* non spec timers */
Alexander Couzensafadd102019-10-08 14:30:59 +0200114 { .T=-1001, .default_val=NONSPEC_X1001_SECS, .desc="RANAP Release timeout. Wait for RANAP Release Complete."
115 "On expiry release Iu connection (s)" },
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200116 {}
117};
118
119DEFUN(show_timer, show_timer_cmd,
120 "show timer " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
121 SHOW_STR "Show timers\n"
122 OSMO_TDEF_VTY_DOC_T)
123{
124 const char *T_arg = argc > 0 ? argv[0] : NULL;
125 return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs, T_arg, NULL);
Harald Welte94508822015-08-15 19:08:21 +0200126}
127
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200128DEFUN(cfg_sgsn_timer, cfg_sgsn_timer_cmd,
129 "timer " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
130 "Configure or show timers\n"
131 OSMO_TDEF_VTY_DOC_SET)
132{
133 /* If any arguments are missing, redirect to 'show' */
134 if (argc < 2)
135 return show_timer(self, vty, argc, argv);
136 return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs, argv);
137}
Harald Welte94508822015-08-15 19:08:21 +0200138
Pau Espin Pedrol85011262022-11-02 20:23:09 +0100139DEFUN(show_timer_gtp, show_timer_gtp_cmd,
140 "show timer gtp " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
141 SHOW_STR "Show timers\n" "GTP (libgtp) timers\n"
142 OSMO_TDEF_VTY_DOC_T)
143{
144 const char *T_arg = argc > 0 ? argv[0] : NULL;
145 return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs_gtp, T_arg, NULL);
146}
147
148DEFUN(cfg_sgsn_timer_gtp, cfg_sgsn_timer_gtp_cmd,
149 "timer gtp " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
150 "Configure or show timers\n" "GTP (libgtp) timers\n"
151 OSMO_TDEF_VTY_DOC_SET)
152{
153 /* If any arguments are missing, redirect to 'show' */
154 if (argc < 2)
155 return show_timer(self, vty, argc, argv);
156 return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs_gtp, argv);
157}
158
Keith6cee1a12021-09-29 21:00:04 +0200159char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6)
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200160{
161 static char str[INET6_ADDRSTRLEN + 10];
162
163 if (!pdpa || len < 2)
164 return "none";
165
166 switch (pdpa[0] & 0x0f) {
167 case PDP_TYPE_ORG_IETF:
168 switch (pdpa[1]) {
169 case PDP_TYPE_N_IETF_IPv4:
170 if (len < 2 + 4)
171 break;
Keith6cee1a12021-09-29 21:00:04 +0200172 osmo_strlcpy(str, "IPv4 ", sizeof(str));
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200173 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
174 return str;
175 case PDP_TYPE_N_IETF_IPv6:
176 if (len < 2 + 8)
177 break;
Keith6cee1a12021-09-29 21:00:04 +0200178 osmo_strlcpy(str, "IPv6 ", sizeof(str));
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200179 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
180 return str;
Keith6cee1a12021-09-29 21:00:04 +0200181 case PDP_TYPE_N_IETF_IPv4v6:
182 if (len < 2 + 20)
183 break;
184 if (return_ipv6) {
185 /* The IPv6 token, (rightmost four fields) is a duplicate of
186 * the site prefix + subnetID (leftmost fields) in pdpa here */
187 osmo_strlcpy(str, "IPv6 ", sizeof(str));
188 inet_ntop(AF_INET6, pdpa+6, str+5, sizeof(str)-5);
189 return str;
190 }
191 osmo_strlcpy(str, "IPv4 ", sizeof(str));
192 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
193 return str;
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200194 default:
195 break;
196 }
197 break;
198 case PDP_TYPE_ORG_ETSI:
199 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
200 return "PPP";
201 break;
202 default:
203 break;
204 }
205
206 return "invalid";
207}
208
Harald Welte288be162010-05-01 16:48:27 +0200209static struct cmd_node sgsn_node = {
210 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200211 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200212 1,
213};
214
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200215static struct cmd_node mme_node = {
216 MME_NODE,
217 "%s(config-sgsn-mme)# ",
218 1,
219};
220
221static void config_write_mme(struct vty *vty, const struct sgsn_mme_ctx *mme, const char *prefix)
222{
223 struct mme_rim_route *rt;
224
225 vty_out(vty, "%smme %s%s", prefix, mme->name, VTY_NEWLINE);
226
227 vty_out(vty, "%s gtp remote-ip %s%s", prefix, inet_ntoa(mme->remote_addr), VTY_NEWLINE);
228 if (mme->default_route)
229 vty_out(vty, "%s gtp ran-info-relay default%s", prefix, VTY_NEWLINE);
230 llist_for_each_entry(rt, &mme->routes, list) {
231 vty_out(vty, "%s gtp ran-info-relay %s %s %u%s", prefix,
232 osmo_mcc_name(rt->tai.mcc), osmo_mnc_name(rt->tai.mnc, rt->tai.mnc_3_digits),
233 rt->tai.tac, VTY_NEWLINE);
234 }
235}
236
Harald Welte288be162010-05-01 16:48:27 +0200237static int config_write_sgsn(struct vty *vty)
238{
Harald Welte77289c22010-05-18 14:32:29 +0200239 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100240 struct imsi_acl_entry *acl;
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100241 struct apn_ctx *actx;
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800242 struct ares_addr_node *server;
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200243 struct sgsn_mme_ctx *mme;
Eric2f898262021-05-19 18:57:50 +0200244 int i;
Harald Welte288be162010-05-01 16:48:27 +0200245
246 vty_out(vty, "sgsn%s", VTY_NEWLINE);
247
Keithc70e8382020-10-19 22:24:48 +0200248 vty_out(vty, " gtp state-dir %s%s",
249 g_cfg->gtp_statedir, VTY_NEWLINE);
Harald Weltee300d002010-06-02 12:41:34 +0200250 vty_out(vty, " gtp local-ip %s%s",
251 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
252
Harald Welted193cb32010-05-17 22:58:03 +0200253 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800254 if (gctx->id == UINT32_MAX)
255 continue;
256
Harald Welteff3bde82010-05-19 15:09:09 +0200257 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200258 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200259 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200260 gctx->gtp_version, VTY_NEWLINE);
Pau Espin Pedrolaa89f5d2019-08-28 16:08:45 +0200261 if (gctx->echo_interval)
262 vty_out(vty, " ggsn %u echo-interval %u%s",
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200263 gctx->id, gctx->echo_interval, VTY_NEWLINE);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200264 else
265 vty_out(vty, " ggsn %u no echo-interval%s",
266 gctx->id, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200267 }
268
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800269 if (sgsn->cfg.dynamic_lookup)
270 vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE);
271
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800272 for (server = sgsn->ares_servers; server; server = server->next)
273 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
274
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100275 if (g_cfg->gea_encryption_mask != 0) {
Eric2f898262021-05-19 18:57:50 +0200276 vty_out(vty, " encryption gea");
277
278 for (i = 0; i < _GPRS_ALGO_NUM; i++)
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100279 if (g_cfg->gea_encryption_mask >> i & 1)
Eric2f898262021-05-19 18:57:50 +0200280 vty_out(vty, " %u", i);
281
282 vty_out(vty, "%s", VTY_NEWLINE);
283 }
Stefan Sperling88220092018-12-11 14:42:00 +0100284 if (g_cfg->sgsn_ipa_name)
285 vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100286 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
287 vty_out(vty, " gsup remote-ip %s%s",
288 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
289 if (g_cfg->gsup_server_port)
290 vty_out(vty, " gsup remote-port %d%s",
291 g_cfg->gsup_server_port, VTY_NEWLINE);
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200292 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE && !g_cfg->require_authentication)
293 vty_out(vty, " authentication optional%s", VTY_NEWLINE);
Max176b62a2016-07-04 11:09:07 +0200294 vty_out(vty, " auth-policy %s%s",
295 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
296 VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200297
298 vty_out(vty, " gsup oap-id %d%s",
299 (int)g_cfg->oap.client_id, VTY_NEWLINE);
300 if (g_cfg->oap.secret_k_present != 0)
301 vty_out(vty, " gsup oap-k %s%s",
302 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
303 VTY_NEWLINE);
304 if (g_cfg->oap.secret_opc_present != 0)
305 vty_out(vty, " gsup oap-opc %s%s",
306 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
307 VTY_NEWLINE);
308
Harald Welte7f6da482013-03-19 11:00:13 +0100309 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
310 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
311
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100312 if (llist_empty(&sgsn_apn_ctxts))
313 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
314 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
315 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200316 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100317 actx->name, actx->imsi_prefix, actx->ggsn->id,
318 VTY_NEWLINE);
319 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200320 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100321 actx->ggsn->id, VTY_NEWLINE);
322 }
323
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200324 if (g_cfg->cdr.filename)
325 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
326 else
327 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +0100328 if (g_cfg->cdr.trap)
329 vty_out(vty, " cdr trap%s", VTY_NEWLINE);
330 else
331 vty_out(vty, " no cdr trap%s", VTY_NEWLINE);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200332 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
333
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200334 osmo_tdef_vty_write(vty, g_cfg->T_defs, " timer ");
Pau Espin Pedrol85011262022-11-02 20:23:09 +0100335 osmo_tdef_vty_write(vty, g_cfg->T_defs_gtp, " timer gtp ");
Harald Welte94508822015-08-15 19:08:21 +0200336
Philippf1f34362016-08-26 17:00:21 +0200337 if (g_cfg->pcomp_rfc1144.active) {
338 vty_out(vty, " compression rfc1144 active slots %d%s",
339 g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE);
340 } else if (g_cfg->pcomp_rfc1144.passive) {
341 vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE);
342 } else
343 vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE);
344
Philipp73f83d52016-09-02 13:38:01 +0200345 if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) {
346 vty_out(vty,
347 " compression v42bis active direction sgsn codewords %d strlen %d%s",
348 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
349 VTY_NEWLINE);
350 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) {
351 vty_out(vty,
352 " compression v42bis active direction ms codewords %d strlen %d%s",
353 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
354 VTY_NEWLINE);
355 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) {
356 vty_out(vty,
357 " compression v42bis active direction both codewords %d strlen %d%s",
358 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
359 VTY_NEWLINE);
360 } else if (g_cfg->dcomp_v42bis.passive) {
361 vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE);
362 } else
363 vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
364
Pau Espin Pedrole5c89982021-05-03 18:16:42 +0200365 llist_for_each_entry(mme, &sgsn->mme_list, list) {
366 config_write_mme(vty, mme, " ");
367 }
368
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200369#ifdef BUILD_IU
Pau Espin Pedrol2c908992019-08-19 19:06:06 +0200370 vty_out(vty, " cs7-instance-iu %u%s", g_cfg->iu.cs7_instance,
371 VTY_NEWLINE);
Neels Hofmeyra7a39472017-07-05 15:19:52 +0200372 ranap_iu_vty_config_write(vty, " ");
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200373#endif
374
Harald Welte288be162010-05-01 16:48:27 +0200375 return CMD_SUCCESS;
376}
377
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100378#define SGSN_STR "Configure the SGSN\n"
379#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200380
381DEFUN(cfg_sgsn, cfg_sgsn_cmd,
382 "sgsn",
383 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200384{
385 vty->node = SGSN_NODE;
386 return CMD_SUCCESS;
387}
388
Keithc70e8382020-10-19 22:24:48 +0200389DEFUN(cfg_sgsn_state_dir, cfg_sgsn_state_dir_cmd,
390 "gtp state-dir PATH",
391 "GTP Parameters\n"
392 "Set the directory for the GTP State file\n"
393 "Local Directory\n")
394{
395 osmo_talloc_replace_string(sgsn, &sgsn->cfg.gtp_statedir, argv[0]);
396
397 return CMD_SUCCESS;
398}
399
Harald Weltee300d002010-06-02 12:41:34 +0200400DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
401 "gtp local-ip A.B.C.D",
402 "GTP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100403 "Set the IP address for the local GTP bind for the Gp interface (towards the GGSNs)."
404 " Note: in case you would like to run the GGSN on the same machine as the SGSN, you can not run"
405 " both on the same IP address, since both sides are specified to use the same GTP port numbers"
406 " (" OSMO_STRINGIFY_VAL(GTP1C_PORT) " and " OSMO_STRINGIFY_VAL(GTP1U_PORT) ")."
407 " For example, you could use 127.0.0.1 for the SGSN and 127.0.0.2 for the GGSN in such"
408 " situations.\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100409 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200410{
411 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
412
413 return CMD_SUCCESS;
414}
415
Harald Welted193cb32010-05-17 22:58:03 +0200416DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
417 "ggsn <0-255> remote-ip A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100418 GGSN_STR "GGSN Number\n"
419 "Configure this static GGSN to use the specified remote IP address.\n"
420 "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200421{
422 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200423 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200424
Harald Welted193cb32010-05-17 22:58:03 +0200425 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200426
Harald Welted193cb32010-05-17 22:58:03 +0200427 return CMD_SUCCESS;
428}
429
430#if 0
431DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
432 "ggsn <0-255> remote-port <0-65535>",
433 "")
434{
435 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200436 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200437 uint16_t port = atoi(argv[1]);
438
439}
440#endif
441
442DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
443 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100444 GGSN_STR "GGSN Number\n" "GTP Version\n"
445 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200446{
447 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200448 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200449
450 if (atoi(argv[1]))
451 ggc->gtp_version = 1;
452 else
453 ggc->gtp_version = 0;
454
455 return CMD_SUCCESS;
456}
457
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200458/* Seee 3GPP TS 29.060 section 7.2.1 */
459DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
460 "ggsn <0-255> echo-interval <1-36000>",
461 GGSN_STR "GGSN Number\n"
462 "Send an echo request to this static GGSN every interval.\n"
463 "Interval between echo requests in seconds.\n")
464{
465 uint32_t id = atoi(argv[0]);
466 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
467
468 ggc->echo_interval = atoi(argv[1]);
469
470 if (ggc->echo_interval < 60)
Pau Espin Pedrolba2e5002019-05-27 17:35:32 +0200471 vty_out(vty, "%% 3GPP TS 29.060 section 7.2.1 states interval should " \
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200472 "not be lower than 60 seconds, use this value for " \
473 "testing purposes only!%s", VTY_NEWLINE);
474
Alexander Couzens176a4d22018-09-18 20:07:37 +0200475 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200476 return CMD_SUCCESS;
477}
478
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200479DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
480 "ggsn <0-255> no echo-interval",
481 GGSN_STR "GGSN Number\n"
482 NO_STR "Send an echo request to this static GGSN every interval.\n")
483{
484 uint32_t id = atoi(argv[0]);
485 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
486
Pau Espin Pedrolaa89f5d2019-08-28 16:08:45 +0200487 ggc->echo_interval = 0;
Alexander Couzens176a4d22018-09-18 20:07:37 +0200488 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200489
490 return CMD_SUCCESS;
491}
492
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800493DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
494 "ggsn dynamic",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100495 GGSN_STR
496 "Enable dynamic resolving of GGSNs based on DNS resolving the APN name like in a GRX-style setup."
497 " Changing this setting requires a restart.\n")
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800498{
499 sgsn->cfg.dynamic_lookup = 1;
500 return CMD_SUCCESS;
501}
502
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800503DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
504 "grx-dns-add A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100505 "Use the specified IP address for DNS-resolving the AP names to GGSN IP addresses\n"
506 "IPv4 address\n")
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800507{
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +0100508 struct ares_addr_node *node = talloc_zero(tall_sgsn_ctx, struct ares_addr_node);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800509 node->family = AF_INET;
510 inet_aton(argv[0], &node->addr.addr4);
511
512 node->next = sgsn->ares_servers;
513 sgsn->ares_servers = node;
514 return CMD_SUCCESS;
515}
516
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100517#define APN_STR "Configure the information per APN\n"
518#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
519
520static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
521 const char *imsi_prefix, int ggsn_id)
522{
523 struct apn_ctx *actx;
524 struct sgsn_ggsn_ctx *ggsn;
525
526 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
527 if (ggsn == NULL) {
528 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
529 ggsn_id, VTY_NEWLINE);
530 return CMD_WARNING;
531 }
532
533 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
534 if (!actx) {
535 vty_out(vty, "%% unable to create APN context for %s/%s%s",
536 apn_str, imsi_prefix, VTY_NEWLINE);
537 return CMD_WARNING;
538 }
539
540 actx->ggsn = ggsn;
541
542 return CMD_SUCCESS;
543}
544
Harald Welted193cb32010-05-17 22:58:03 +0200545DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
546 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100547 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100548 "Select the GGSN to use for the given APN gateway prefix\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100549 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200550{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100551
552 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200553}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100554
555DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
556 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
557 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100558 "Select the GGSN to use for the given APN gateway prefix if and only if the IMSI matches the"
559 " given prefix.\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100560 "An IMSI prefix\n"
561 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
562 "The GGSN id")
563{
564
565 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
566}
Harald Welted193cb32010-05-17 22:58:03 +0200567
Maxc005db72017-10-27 18:43:29 +0200568char *sgsn_gtp_ntoa(struct ul16_t *ul)
Harald Welte471ac7d2016-12-15 19:48:58 +0100569{
Max8492c202017-12-05 17:28:15 +0100570 struct in_addr ia;
571
572 if (gsna2in_addr(&ia, ul) != 0)
Harald Welte471ac7d2016-12-15 19:48:58 +0100573 return "UNKNOWN";
Max8492c202017-12-05 17:28:15 +0100574
575 return inet_ntoa(ia);
Harald Welte471ac7d2016-12-15 19:48:58 +0100576}
577
Harald Welted193cb32010-05-17 22:58:03 +0200578static void vty_dump_pdp(struct vty *vty, const char *pfx,
579 struct sgsn_pdp_ctx *pdp)
580{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200581 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welte471ac7d2016-12-15 19:48:58 +0100582 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s",
583 pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200584 if (pdp->lib) {
Max7933d962017-10-19 16:52:30 +0200585 char apnbuf[APN_MAXLEN + 1];
Harald Weltedfbd2c82017-08-13 00:56:45 +0200586 vty_out(vty, "%s APN: %s%s", pfx,
Max7933d962017-10-19 16:52:30 +0200587 osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200588 VTY_NEWLINE);
589 vty_out(vty, "%s PDP Address: %s%s", pfx,
Keith6cee1a12021-09-29 21:00:04 +0200590 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, false),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200591 VTY_NEWLINE);
Keith6cee1a12021-09-29 21:00:04 +0200592 if (pdp->lib->eua.v[1] == PDP_TYPE_N_IETF_IPv4v6) {
593 vty_out(vty, "%s PDP Address: %s%s", pfx,
594 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, true),
595 VTY_NEWLINE);
596 }
Maxb24af2b2017-12-05 17:54:42 +0100597 vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200598 sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200599 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200600 sgsn_gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100601 vty_out(vty, "%s GTPv%d Remote Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200602 sgsn_gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200603 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200604 sgsn_gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200605 }
Harald Welte471ac7d2016-12-15 19:48:58 +0100606
Harald Welteefbdee92010-06-10 00:20:12 +0200607 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200608}
609
610static void vty_dump_mmctx(struct vty *vty, const char *pfx,
611 struct sgsn_mm_ctx *mm, int pdp)
612{
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200613 uint32_t id = 0;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200614 const char *mm_state_name = NULL;
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200615
616 switch(mm->ran_type) {
617 case MM_CTX_T_UTRAN_Iu:
618#if BUILD_IU
619 id = mm->iu.ue_ctx->conn_id;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200620 mm_state_name = osmo_fsm_inst_state_name(mm->iu.mm_state_fsm);
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200621#endif
622 break;
623 case MM_CTX_T_GERAN_Gb:
624 id = mm->gb.tlli;
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200625 mm_state_name = osmo_fsm_inst_state_name(mm->gb.mm_state_fsm);
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200626 break;
627 }
628
Harald Welted193cb32010-05-17 22:58:03 +0200629 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
630 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200631 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Pau Espin Pedrol9119d502019-08-30 17:48:10 +0200632 pfx, mm->msisdn, id, mm->hlr, VTY_NEWLINE);
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200633 vty_out(vty, "%s GMM State: %s, Routeing Area: %s, Cell ID: %u%s",
Pau Espin Pedrol31c46572019-09-02 16:45:27 +0200634 pfx, osmo_fsm_inst_state_name(mm->gmm_fsm),
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100635 osmo_rai_name(&mm->ra), mm->gb.cell_id, VTY_NEWLINE);
Pau Espin Pedrolfd815bb2019-08-30 18:32:42 +0200636 vty_out(vty, "%s MM State: %s, RAN Type: %s%s", pfx, mm_state_name,
637 get_value_string(sgsn_ran_type_names, mm->ran_type), VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200638
Pau Espin Pedrol3b848bd2019-08-30 18:06:35 +0200639 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
Harald Welte8acd88f2010-05-18 10:57:45 +0200640
Harald Welted193cb32010-05-17 22:58:03 +0200641 if (pdp) {
642 struct sgsn_pdp_ctx *pdp;
643
644 llist_for_each_entry(pdp, &mm->pdp_list, list)
645 vty_dump_pdp(vty, " ", pdp);
646 }
647}
648
649DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
650 SHOW_STR "Display information about the SGSN")
651{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100652 if (sgsn->gsup_client) {
653 struct ipa_client_conn *link = sgsn->gsup_client->link;
654 vty_out(vty,
655 " Remote authorization: %sconnected to %s:%d via GSUP%s",
656 sgsn->gsup_client->is_connected ? "" : "not ",
657 link->addr, link->port,
658 VTY_NEWLINE);
659 }
Maxbaabc682017-10-20 13:39:57 +0200660 if (sgsn->gsn)
661 vty_out(vty, " GSN: signalling %s, user traffic %s%s",
662 inet_ntoa(sgsn->gsn->gsnc), inet_ntoa(sgsn->gsn->gsnu), VTY_NEWLINE);
663
Harald Welted193cb32010-05-17 22:58:03 +0200664 /* FIXME: statistics */
665 return CMD_SUCCESS;
666}
667
668#define MMCTX_STR "MM Context\n"
669#define INCLUDE_PDP_STR "Include PDP Context Information\n"
670
671#if 0
672DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
673 "show mm-context tlli HEX [pdp]",
674 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
675{
676 uint32_t tlli;
677 struct sgsn_mm_ctx *mm;
678
679 tlli = strtoul(argv[0], NULL, 16);
680 mm = sgsn_mm_ctx_by_tlli(tlli);
681 if (!mm) {
682 vty_out(vty, "No MM context for TLLI %08x%s",
683 tlli, VTY_NEWLINE);
684 return CMD_WARNING;
685 }
686 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
687 return CMD_SUCCESS;
688}
689#endif
690
691DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
692 "show mm-context imsi IMSI [pdp]",
693 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
694 INCLUDE_PDP_STR)
695{
696 struct sgsn_mm_ctx *mm;
697
698 mm = sgsn_mm_ctx_by_imsi(argv[0]);
699 if (!mm) {
700 vty_out(vty, "No MM context for IMSI %s%s",
701 argv[0], VTY_NEWLINE);
702 return CMD_WARNING;
703 }
Keithc12c1a62021-05-20 04:41:01 +0200704 vty_dump_mmctx(vty, "", mm, (argc > 1) ? 1 : 0);
Harald Welted193cb32010-05-17 22:58:03 +0200705 return CMD_SUCCESS;
706}
707
708DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
709 "show mm-context all [pdp]",
710 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
711{
712 struct sgsn_mm_ctx *mm;
Harald Welted193cb32010-05-17 22:58:03 +0200713 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
Keithc12c1a62021-05-20 04:41:01 +0200714 vty_dump_mmctx(vty, "", mm, (argc > 0) ? 1 : 0);
Harald Welted193cb32010-05-17 22:58:03 +0200715
716 return CMD_SUCCESS;
717}
718
Harald Welted193cb32010-05-17 22:58:03 +0200719DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
720 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100721 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200722{
723 struct sgsn_pdp_ctx *pdp;
724
725 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
726 vty_dump_pdp(vty, "", pdp);
727
728 return CMD_SUCCESS;
729}
Harald Welte288be162010-05-01 16:48:27 +0200730
Harald Welte7f6da482013-03-19 11:00:13 +0100731
732DEFUN(imsi_acl, cfg_imsi_acl_cmd,
733 "imsi-acl (add|del) IMSI",
734 "Access Control List of foreign IMSIs\n"
735 "Add IMSI to ACL\n"
736 "Remove IMSI from ACL\n"
737 "IMSI of subscriber\n")
738{
Maxef38b4c2018-11-20 10:25:53 +0100739 char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS + 1];
Harald Welte7f6da482013-03-19 11:00:13 +0100740 const char *op = argv[0];
Philipp Maier6ee49d82017-02-28 16:53:07 +0100741 const char *imsi = imsi_sanitized;
Maxf4fa6952018-01-15 12:12:51 +0100742 size_t len = strnlen(argv[1], GSM23003_IMSI_MAX_DIGITS + 1);
Harald Welte7f6da482013-03-19 11:00:13 +0100743 int rc;
744
Maxef38b4c2018-11-20 10:25:53 +0100745 memset(imsi_sanitized, '0', GSM23003_IMSI_MAX_DIGITS);
746 imsi_sanitized[GSM23003_IMSI_MAX_DIGITS] = '\0';
747
Philipp Maier6ee49d82017-02-28 16:53:07 +0100748 /* Sanitize IMSI */
Maxf4fa6952018-01-15 12:12:51 +0100749 if (len > GSM23003_IMSI_MAX_DIGITS) {
750 vty_out(vty, "%% IMSI (%s) too long (max %u digits) -- ignored!%s",
751 argv[1], GSM23003_IMSI_MAX_DIGITS, VTY_NEWLINE);
Philipp Maier6ee49d82017-02-28 16:53:07 +0100752 return CMD_WARNING;
753 }
Maxf4fa6952018-01-15 12:12:51 +0100754
755 osmo_strlcpy(imsi_sanitized + GSM23003_IMSI_MAX_DIGITS - len, argv[1],
756 sizeof(imsi_sanitized) - (GSM23003_IMSI_MAX_DIGITS - len));
Philipp Maier6ee49d82017-02-28 16:53:07 +0100757
Harald Welte7f6da482013-03-19 11:00:13 +0100758 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200759 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100760 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200761 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100762
763 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100764 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100765 return CMD_WARNING;
766 }
767
768 return CMD_SUCCESS;
769}
770
Eric2f898262021-05-19 18:57:50 +0200771DEFUN_DEPRECATED(cfg_encrypt, cfg_encrypt_cmd,
Max93408ae2016-06-28 14:10:16 +0200772 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
773 "Set encryption algorithm for SGSN\n"
774 "Use GEA0 (no encryption)\n"
775 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
776{
Max93408ae2016-06-28 14:10:16 +0200777 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
Eric2f898262021-05-19 18:57:50 +0200778
779 if (strcmp(argv[0], "gea") == 0)
780 return CMD_SUCCESS;
781
Max086067f2017-05-02 13:03:28 +0200782 if (c != GPRS_ALGO_GEA0) {
Eric2f898262021-05-19 18:57:50 +0200783 if (gprs_cipher_supported(c) <= 0) {
Max086067f2017-05-02 13:03:28 +0200784 vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
785 return CMD_WARNING;
786 }
787
788 if (!g_cfg->require_authentication) {
789 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
790 argv[0], VTY_NEWLINE);
791 return CMD_WARNING;
792 }
Max93408ae2016-06-28 14:10:16 +0200793 }
794
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100795 g_cfg->gea_encryption_mask |= (1 << c);
Eric2f898262021-05-19 18:57:50 +0200796
797 return CMD_SUCCESS;
798}
799
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +0100800#define ENCRYPTION_STR "Set encryption algorithms for SGSN\n"
801
Eric2f898262021-05-19 18:57:50 +0200802DEFUN(cfg_encrypt2, cfg_encrypt2_cmd,
803 "encryption gea <0-4> [<0-4>] [<0-4>] [<0-4>] [<0-4>]",
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +0100804 ENCRYPTION_STR
Eric2f898262021-05-19 18:57:50 +0200805 "GPRS Encryption Algorithm\n"
806 "GEAn Algorithm Number\n"
807 "GEAn Algorithm Number\n"
808 "GEAn Algorithm Number\n"
809 "GEAn Algorithm Number\n"
810 "GEAn Algorithm Number\n")
811{
812 int i = 0;
813
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100814 g_cfg->gea_encryption_mask = 0;
Eric2f898262021-05-19 18:57:50 +0200815 for (i = 0; i < argc; i++)
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100816 g_cfg->gea_encryption_mask |= (1 << atoi(argv[i]));
Eric2f898262021-05-19 18:57:50 +0200817
818 for (i = 0; i < _GPRS_ALGO_NUM; i++) {
Neels Hofmeyr340a7e92022-03-07 15:37:24 +0100819 if (g_cfg->gea_encryption_mask >> i & 1) {
Eric2f898262021-05-19 18:57:50 +0200820
821 if (i == GPRS_ALGO_GEA0)
822 continue;
823
824 if (gprs_cipher_supported(i) <= 0) {
825 vty_out(vty, "%% cipher %d is unsupported in current version%s", i, VTY_NEWLINE);
826 return CMD_ERR_INCOMPLETE;
827 }
828
829 if (!g_cfg->require_authentication) {
830 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
831 argv[i], VTY_NEWLINE);
832 return CMD_ERR_INCOMPLETE;
833 }
834
835 }
836 }
Max93408ae2016-06-28 14:10:16 +0200837
838 return CMD_SUCCESS;
839}
840
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700841DEFUN(cfg_authentication, cfg_authentication_cmd,
842 "authentication (optional|required)",
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200843 "Whether to enforce MS authentication in GERAN (only with auth-policy remote)\n"
844 "Allow MS to attach via GERAN without authentication (default and only possible value for non-remote auth-policy)\n"
845 "Always require authentication (only available for auth-policy remote, default with that auth-policy)\n")
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700846{
847 int required = (argv[0][0] == 'r');
848
849 if (vty->type != VTY_FILE) {
850 if (g_cfg->auth_policy != SGSN_AUTH_POLICY_REMOTE && required) {
851 vty_out(vty, "%% Authentication is not possible without HLR, "
852 "consider setting 'auth-policy' to 'remote'%s",
853 VTY_NEWLINE);
854 return CMD_WARNING;
855 }
856 }
857
858 g_cfg->require_authentication = required;
859 return CMD_SUCCESS;
860}
861
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +0100862DEFUN(cfg_encryption_uea, cfg_encryption_uea_cmd,
863 "encryption uea <0-2> [<0-2>] [<0-2>]",
864 ENCRYPTION_STR
865 "UTRAN (3G) encryption algorithms to allow: 0 = UEA0 (no encryption), 1 = UEA1, 2 = UEA2.\n"
866 "UEAn Algorithm Number\n"
867 "UEAn Algorithm Number\n"
868 "UEAn Algorithm Number\n")
869{
870 unsigned int i;
871
872 g_cfg->uea_encryption_mask = 0;
873 for (i = 0; i < argc; i++)
874 g_cfg->uea_encryption_mask |= (1 << atoi(argv[i]));
875
876 return CMD_SUCCESS;
877}
878
Harald Welte3dfb5492013-03-19 11:48:54 +0100879DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100880 "auth-policy (accept-all|closed|acl-only|remote)",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100881 "Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
882 " permitted to register to the network.\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100883 "Accept all IMSIs (DANGEROUS)\n"
884 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100885 "Accept only subscribers in the ACL\n"
886 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100887{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100888 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100889 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100890 g_cfg->auth_policy = val;
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100891 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100892
893 return CMD_SUCCESS;
894}
895
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100896/* Subscriber */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +0200897#include <osmocom/sgsn/gprs_subscriber.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100898
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100899static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100900{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100901#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100902 char expire_time[200];
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100903#endif
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100904 struct gsm_auth_tuple *at;
905 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100906 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100907
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100908 vty_out(vty, " Authorized: %d%s",
909 gsub->authorized, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100910 vty_out(vty, " LAC: %d/0x%x%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100911 gsub->lac, gsub->lac, VTY_NEWLINE);
912 vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
913 if (gsub->tmsi != GSM_RESERVED_TMSI)
914 vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100915 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100916 if (gsub->sgsn_data->msisdn_len > 0)
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400917 vty_out(vty, " MSISDN (BCD): %s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100918 osmo_hexdump(gsub->sgsn_data->msisdn,
919 gsub->sgsn_data->msisdn_len),
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400920 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100921
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100922 if (strlen(gsub->imei) > 0)
923 vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100924
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100925 for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100926 at_idx++) {
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100927 at = &gsub->sgsn_data->auth_triplets[at_idx];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100928 if (at->key_seq == GSM_KEY_SEQ_INVAL)
929 continue;
930
931 vty_out(vty, " A3A8 tuple (used %d times): ",
932 at->use_count);
Harald Welte89837d42016-05-06 23:28:11 +0200933 vty_out(vty, " CKSN: %d, ",
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100934 at->key_seq);
Harald Welte89837d42016-05-06 23:28:11 +0200935 if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
936 vty_out(vty, "RAND: %s, ",
Max34604c22019-02-13 14:11:29 +0100937 osmo_hexdump_nospc(at->vec.rand,
Harald Welte89837d42016-05-06 23:28:11 +0200938 sizeof(at->vec.rand)));
939 vty_out(vty, "SRES: %s, ",
Max34604c22019-02-13 14:11:29 +0100940 osmo_hexdump_nospc(at->vec.sres,
Harald Welte89837d42016-05-06 23:28:11 +0200941 sizeof(at->vec.sres)));
942 vty_out(vty, "Kc: %s%s",
Max34604c22019-02-13 14:11:29 +0100943 osmo_hexdump_nospc(at->vec.kc,
Harald Welte89837d42016-05-06 23:28:11 +0200944 sizeof(at->vec.kc)), VTY_NEWLINE);
945 }
946 if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
947 vty_out(vty, " AUTN: %s, ",
948 osmo_hexdump(at->vec.autn,
949 sizeof(at->vec.autn)));
950 vty_out(vty, "RES: %s, ",
Max34604c22019-02-13 14:11:29 +0100951 osmo_hexdump_nospc(at->vec.res, at->vec.res_len));
Harald Welte89837d42016-05-06 23:28:11 +0200952 vty_out(vty, "IK: %s, ",
Max34604c22019-02-13 14:11:29 +0100953 osmo_hexdump_nospc(at->vec.ik, sizeof(at->vec.ik)));
Harald Welte89837d42016-05-06 23:28:11 +0200954 vty_out(vty, "CK: %s, ",
Max34604c22019-02-13 14:11:29 +0100955 osmo_hexdump_nospc(at->vec.ck, sizeof(at->vec.ck)));
Harald Welte89837d42016-05-06 23:28:11 +0200956 }
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100957 }
958
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100959 llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
Max34604c22019-02-13 14:11:29 +0100960 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'",
961 pdp->context_id, pdp->pdp_type, pdp->apn_str);
962
963 if (pdp->qos_subscribed_len)
964 vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len));
965
966 vty_out(vty, "%s", VTY_NEWLINE);
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100967 }
968
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100969#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100970 /* print the expiration time of a subscriber */
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100971 if (gsub->expire_lu) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100972 strftime(expire_time, sizeof(expire_time),
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100973 "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100974 expire_time[sizeof(expire_time) - 1] = '\0';
975 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
976 }
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100977#endif
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100978
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100979 if (gsub->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100980 vty_out(vty, " Flags: %s%s%s%s%s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100981 gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100982 "FIRST_CONTACT " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100983 gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100984 "CANCELLED " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100985 gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100986 "UPDATE_LOCATION_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100987 gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100988 "AUTH_INFO_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100989 gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100990 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100991 VTY_NEWLINE);
992
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100993 vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100994}
995
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200996#define RESET_SGSN_STATE_STR \
997 "Remove all known subscribers, MM contexts and flush BSSGP queues." \
998 " Useful only when running tests against the SGSN\n"
999
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001000DEFUN_HIDDEN(reset_sgsn_state,
1001 reset_sgsn_state_cmd,
1002 "reset sgsn state",
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +02001003 RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR)
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001004{
1005 struct gprs_subscr *subscr, *tmp_subscr;
1006 struct sgsn_mm_ctx *mm, *tmp_mm;
1007
1008 llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
1009 {
1010 gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
1011 }
1012 vty_out(vty, "Cancelled MM Ctx. %s", VTY_NEWLINE);
1013
1014 llist_for_each_entry_safe(subscr, tmp_subscr, gprs_subscribers, entry) {
1015 gprs_subscr_get(subscr);
1016 gprs_subscr_cancel(subscr);
1017 gprs_subscr_put(subscr);
1018 }
1019 vty_out(vty, "Removed all gprs subscribers.%s", VTY_NEWLINE);
1020
1021 bssgp_flush_all_queues();
1022 vty_out(vty, "Flushed all BSSGPs queues.%s", VTY_NEWLINE);
1023
Alexander Couzens35c34942018-09-17 04:39:14 +02001024 gtp_clear_queues(sgsn->gsn);
Alexander Couzensa66f0f22018-09-18 16:09:18 +02001025 vty_out(vty, "Flushed rx & tx queus towards the GGSN.%s", VTY_NEWLINE);
Alexander Couzens35c34942018-09-17 04:39:14 +02001026
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001027 /* remove all queues to bssgp */
1028 return CMD_SUCCESS;
1029}
1030
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001031DEFUN(show_subscr_cache,
1032 show_subscr_cache_cmd,
1033 "show subscriber cache",
1034 SHOW_STR "Show information about subscribers\n"
1035 "Display contents of subscriber cache\n")
1036{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001037 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001038
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001039 llist_for_each_entry(subscr, gprs_subscribers, entry) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001040 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
1041 subscr_dump_full_vty(vty, subscr, 0);
1042 }
1043
1044 return CMD_SUCCESS;
1045}
1046
1047#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
1048#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
1049 "Use the IMSI to select the subscriber\n" \
1050 "The IMSI\n"
1051
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001052#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
1053
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001054DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
1055 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
1056 UPDATE_SUBSCR_HELP
1057 UPDATE_SUBSCR_INSERT_HELP
1058 "Update authentication triplet\n"
1059 "Triplet index\n"
1060 "Set SRES value\nSRES value (4 byte) in hex\n"
1061 "Set RAND value\nRAND value (16 byte) in hex\n"
1062 "Set Kc value\nKc value (8 byte) in hex\n")
1063{
1064 const char *imsi = argv[0];
1065 const int cksn = atoi(argv[1]) - 1;
1066 const char *sres_str = argv[2];
1067 const char *rand_str = argv[3];
1068 const char *kc_str = argv[4];
1069 struct gsm_auth_tuple at = {0,};
1070
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001071 struct gprs_subscr *subscr;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001072
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001073 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001074 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001075 vty_out(vty, "%% unable get subscriber record for %s%s",
1076 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001077 return CMD_WARNING;
1078 }
1079
1080 OSMO_ASSERT(subscr->sgsn_data);
1081
Harald Welte121e9a42016-04-20 13:13:19 +02001082 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001083 vty_out(vty, "%% invalid SRES value '%s'%s",
1084 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001085 goto failed;
1086 }
Harald Welte121e9a42016-04-20 13:13:19 +02001087 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001088 vty_out(vty, "%% invalid RAND value '%s'%s",
1089 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001090 goto failed;
1091 }
Harald Welte121e9a42016-04-20 13:13:19 +02001092 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001093 vty_out(vty, "%% invalid Kc value '%s'%s",
1094 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001095 goto failed;
1096 }
1097 at.key_seq = cksn;
1098
1099 subscr->sgsn_data->auth_triplets[cksn] = at;
1100 subscr->sgsn_data->auth_triplets_updated = 1;
1101
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001102 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001103
1104 return CMD_SUCCESS;
1105
1106failed:
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001107 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001108 return CMD_SUCCESS;
1109}
1110
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001111DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001112 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001113 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001114 "Cancel (remove) subscriber record\n"
1115 "The MS moved to another SGSN\n"
1116 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001117{
1118 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001119 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001120
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001121 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001122
1123 subscr = gprs_subscr_get_by_imsi(imsi);
1124 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001125 vty_out(vty, "%% no subscriber record for %s%s",
1126 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001127 return CMD_WARNING;
1128 }
1129
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001130 if (strcmp(cancel_type, "update-procedure") == 0)
1131 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
1132 else
1133 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
1134
Jacob Erlbeck37139e52015-01-23 13:52:55 +01001135 gprs_subscr_cancel(subscr);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001136 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001137
1138 return CMD_SUCCESS;
1139}
1140
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001141DEFUN(update_subscr_create, update_subscr_create_cmd,
1142 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001143 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001144 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001145{
1146 const char *imsi = argv[0];
1147
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001148 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001149
1150 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001151 if (subscr) {
1152 vty_out(vty, "%% subscriber record already exists for %s%s",
1153 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001154 return CMD_WARNING;
1155 }
1156
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001157 subscr = gprs_subscr_get_or_create(imsi);
Alexander Couzens3326ba72020-12-09 22:02:55 +01001158 if (!subscr) {
1159 vty_out(vty, "Can not create subscriber. Out of memory.%s", imsi);
1160 return CMD_WARNING;
1161 }
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001162 subscr->keep_in_ram = 1;
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001163 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001164
1165 return CMD_SUCCESS;
1166}
1167
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001168DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
1169 UPDATE_SUBSCR_STR "destroy",
1170 UPDATE_SUBSCR_HELP
1171 "Destroy a subscriber entry\n")
1172{
1173 const char *imsi = argv[0];
1174
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001175 struct gprs_subscr *subscr;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001176
1177 subscr = gprs_subscr_get_by_imsi(imsi);
1178 if (!subscr) {
1179 vty_out(vty, "%% subscriber record does not exist for %s%s",
1180 imsi, VTY_NEWLINE);
1181 return CMD_WARNING;
1182 }
1183
1184 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001185 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001186 gprs_subscr_cancel(subscr);
1187 if (subscr->use_count > 1)
1188 vty_out(vty, "%% subscriber is still in use%s",
1189 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001190 gprs_subscr_put(subscr);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001191
1192 return CMD_SUCCESS;
1193}
1194
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001195#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
1196 "unknown-subscriber|roaming-not-allowed"
1197
1198#define UL_ERR_HELP \
1199 "Force error code SystemFailure\n" \
1200 "Force error code DataMissing\n" \
1201 "Force error code UnexpectedDataValue\n" \
1202 "Force error code UnknownSubscriber\n" \
1203 "Force error code RoamingNotAllowed\n"
1204
1205DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
1206 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
1207 UPDATE_SUBSCR_HELP
1208 "Complete the update location procedure\n"
1209 "The update location request succeeded\n"
1210 UL_ERR_HELP)
1211{
1212 const char *imsi = argv[0];
1213 const char *ret_code_str = argv[1];
1214
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001215 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001216
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001217 const struct value_string cause_mapping[] = {
1218 { GMM_CAUSE_NET_FAIL, "system-failure" },
1219 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
1220 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
1221 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
1222 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
1223 { 0, NULL }
1224 };
1225
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001226 subscr = gprs_subscr_get_by_imsi(imsi);
1227 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001228 vty_out(vty, "%% unable to get subscriber record for %s%s",
1229 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001230 return CMD_WARNING;
1231 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001232
1233 if (strcmp(ret_code_str, "ok") == 0) {
1234 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001235 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001236 } else {
1237 subscr->sgsn_data->error_cause =
1238 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001239 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001240 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001241
1242 gprs_subscr_update(subscr);
1243
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001244 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001245
1246 return CMD_SUCCESS;
1247}
1248
1249DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
1250 UPDATE_SUBSCR_STR "update-auth-info",
1251 UPDATE_SUBSCR_HELP
1252 "Complete the send authentication info procedure\n")
1253{
1254 const char *imsi = argv[0];
1255
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001256 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001257
1258 subscr = gprs_subscr_get_by_imsi(imsi);
1259 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001260 vty_out(vty, "%% unable to get subscriber record for %s%s",
1261 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001262 return CMD_WARNING;
1263 }
1264
1265 gprs_subscr_update_auth_info(subscr);
1266
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001267 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001268
1269 return CMD_SUCCESS;
1270}
1271
Oliver Smithab39b622021-07-05 15:41:05 +02001272DEFUN(page_subscr, page_subscr_info_cmd,
1273 "page imsi IMSI",
1274 "Send a PS paging request to subscriber\n"
1275 "Use the IMSI to select the subscriber\n"
1276 "The IMSI\n")
1277{
1278 const char *imsi = argv[0];
1279 struct sgsn_mm_ctx *mm;
1280
1281 mm = sgsn_mm_ctx_by_imsi(imsi);
1282 if (!mm) {
1283 vty_out(vty, "No MM context for IMSI %s%s", imsi, VTY_NEWLINE);
1284 return CMD_WARNING;
1285 }
1286
1287 gprs_gb_page_ps_ra(mm);
1288 return CMD_SUCCESS;
1289}
1290
Stefan Sperling88220092018-12-11 14:42:00 +01001291DEFUN(cfg_gsup_ipa_name,
1292 cfg_gsup_ipa_name_cmd,
1293 "gsup ipa-name NAME",
1294 "GSUP Parameters\n"
1295 "Set the IPA name of this SGSN\n"
1296 "A unique name for this SGSN. For example: PLMN + redundancy server number: SGSN-901-70-0. "
1297 "This name is used for GSUP routing and must be set if more than one SGSN is connected to the network. "
1298 "The default is 'SGSN-00-00-00-00-00-00'.\n")
1299{
1300 if (vty->type != VTY_FILE) {
1301 vty_out(vty, "The IPA name cannot be changed at run-time; "
1302 "It can only be set in the configuraton file.%s", VTY_NEWLINE);
1303 return CMD_WARNING;
1304 }
1305
1306 g_cfg->sgsn_ipa_name = talloc_strdup(tall_vty_ctx, argv[0]);
1307 return CMD_SUCCESS;
1308}
1309
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001310DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
1311 "gsup remote-ip A.B.C.D",
1312 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001313 "Set the IP address of the remote GSUP server (e.g. OsmoHLR)."
1314 " This setting only applies if 'auth-policy remote' is used.\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001315 "IPv4 Address\n")
1316{
1317 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
1318
1319 return CMD_SUCCESS;
1320}
1321
1322DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
1323 "gsup remote-port <0-65535>",
1324 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001325 "Set the TCP port of the remote GSUP server, see also 'gsup remote-ip'\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001326 "Remote TCP port\n")
1327{
1328 g_cfg->gsup_server_port = atoi(argv[0]);
1329
1330 return CMD_SUCCESS;
1331}
1332
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001333DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
1334 "gsup oap-id <0-65535>",
1335 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001336 "Set the OAP client ID for authentication on the GSUP protocol."
1337 " This setting only applies if 'auth-policy remote' is used.\n"
1338 "OAP client ID (0 == disabled)\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001339{
1340 /* VTY ensures range */
1341 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
1342 return CMD_SUCCESS;
1343}
1344
1345DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
1346 "gsup oap-k K",
1347 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001348 "Set the OAP shared secret key K for authentication on the GSUP protocol."
1349 " This setting only applies if auth-policy remote is used.\n"
1350 "K value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001351{
1352 const char *k = argv[0];
1353
1354 g_cfg->oap.secret_k_present = 0;
1355
1356 if ((!k) || (strlen(k) == 0))
1357 goto disable;
1358
1359 int k_len = osmo_hexparse(k,
1360 g_cfg->oap.secret_k,
1361 sizeof(g_cfg->oap.secret_k));
1362 if (k_len != 16) {
1363 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
1364 k_len, VTY_NEWLINE);
1365 goto disable;
1366 }
1367
1368 g_cfg->oap.secret_k_present = 1;
1369 return CMD_SUCCESS;
1370
1371disable:
1372 if (g_cfg->oap.client_id > 0) {
1373 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
1374 VTY_NEWLINE);
1375 return CMD_WARNING;
1376 }
1377 return CMD_SUCCESS;
1378}
1379
1380DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1381 "gsup oap-opc OPC",
1382 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001383 "Set the OAP shared secret OPC for authentication on the GSUP protocol."
1384 " This setting only applies if auth-policy remote is used.\n"
1385 "OPC value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001386{
1387 const char *opc = argv[0];
1388
1389 g_cfg->oap.secret_opc_present = 0;
1390
1391 if ((!opc) || (strlen(opc) == 0))
1392 goto disable;
1393
1394 int opc_len = osmo_hexparse(opc,
1395 g_cfg->oap.secret_opc,
1396 sizeof(g_cfg->oap.secret_opc));
1397 if (opc_len != 16) {
1398 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1399 opc_len, VTY_NEWLINE);
1400 goto disable;
1401 }
1402
1403 g_cfg->oap.secret_opc_present = 1;
1404 return CMD_SUCCESS;
1405
1406disable:
1407 if (g_cfg->oap.client_id > 0) {
1408 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1409 VTY_NEWLINE);
1410 return CMD_WARNING;
1411 }
1412 return CMD_SUCCESS;
1413}
1414
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001415DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1416 "access-point-name NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001417 "Globally allow the given APN name for all subscribers.\n"
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001418 "Add this NAME to the list\n")
1419{
1420 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1421}
1422
1423DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1424 "no access-point-name NAME",
1425 NO_STR "Configure a global list of allowed APNs\n"
1426 "Remove entry with NAME\n")
1427{
1428 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1429 if (!apn_ctx)
1430 return CMD_SUCCESS;
1431
1432 sgsn_apn_ctx_free(apn_ctx);
1433 return CMD_SUCCESS;
1434}
1435
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001436DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1437 "cdr filename NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001438 "CDR\n"
1439 "Set the file name for the call-data-record file, logging the data usage of each subscriber.\n"
1440 "filename\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001441{
1442 talloc_free(g_cfg->cdr.filename);
1443 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1444 return CMD_SUCCESS;
1445}
1446
1447DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1448 "no cdr filename",
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001449 NO_STR "CDR\nDisable saving CDR to file\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001450{
1451 talloc_free(g_cfg->cdr.filename);
1452 g_cfg->cdr.filename = NULL;
1453 return CMD_SUCCESS;
1454}
1455
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001456DEFUN(cfg_cdr_trap, cfg_cdr_trap_cmd,
1457 "cdr trap",
1458 "CDR\nEnable sending CDR via TRAP CTRL messages\n")
1459{
1460 g_cfg->cdr.trap = true;
1461 return CMD_SUCCESS;
1462}
1463
1464DEFUN(cfg_no_cdr_trap, cfg_no_cdr_trap_cmd,
1465 "no cdr trap",
1466 NO_STR "CDR\nDisable sending CDR via TRAP CTRL messages\n")
1467{
1468 g_cfg->cdr.trap = false;
1469 return CMD_SUCCESS;
1470}
1471
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001472DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1473 "cdr interval <1-2147483647>",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001474 "CDR\n"
1475 "Set the interval for the call-data-record file\n"
1476 "interval in seconds\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001477{
1478 g_cfg->cdr.interval = atoi(argv[0]);
1479 return CMD_SUCCESS;
1480}
1481
Philippf1f34362016-08-26 17:00:21 +02001482#define COMPRESSION_STR "Configure compression\n"
1483DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1484 "no compression rfc1144",
1485 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1486{
1487 g_cfg->pcomp_rfc1144.active = 0;
1488 g_cfg->pcomp_rfc1144.passive = 0;
1489 return CMD_SUCCESS;
1490}
1491
1492DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1493 "compression rfc1144 active slots <1-256>",
1494 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001495 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001496 "Compression is actively proposed\n"
1497 "Number of compression state slots\n"
1498 "Number of compression state slots\n")
1499{
1500 g_cfg->pcomp_rfc1144.active = 1;
1501 g_cfg->pcomp_rfc1144.passive = 1;
1502 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1503 return CMD_SUCCESS;
1504}
1505
1506DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1507 "compression rfc1144 passive",
1508 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001509 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001510 "Compression is available on request\n")
1511{
1512 g_cfg->pcomp_rfc1144.active = 0;
1513 g_cfg->pcomp_rfc1144.passive = 1;
1514 return CMD_SUCCESS;
1515}
1516
Philipp73f83d52016-09-02 13:38:01 +02001517DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
1518 "no compression v42bis",
1519 NO_STR COMPRESSION_STR "disable V.42bis data compression\n")
1520{
1521 g_cfg->dcomp_v42bis.active = 0;
1522 g_cfg->dcomp_v42bis.passive = 0;
1523 return CMD_SUCCESS;
1524}
1525
1526DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
1527 "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
1528 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001529 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001530 "Compression is actively proposed\n"
1531 "Direction in which the compression shall be active (p0)\n"
1532 "Compress ms->sgsn direction only\n"
1533 "Compress sgsn->ms direction only\n"
1534 "Both directions\n"
1535 "Number of codewords (p1)\n"
1536 "Number of codewords\n"
1537 "Maximum string length (p2)\n" "Maximum string length\n")
1538{
1539 g_cfg->dcomp_v42bis.active = 1;
1540 g_cfg->dcomp_v42bis.passive = 1;
1541
1542 switch (argv[0][0]) {
1543 case 'm':
1544 g_cfg->dcomp_v42bis.p0 = 1;
1545 break;
1546 case 's':
1547 g_cfg->dcomp_v42bis.p0 = 2;
1548 break;
1549 case 'b':
1550 g_cfg->dcomp_v42bis.p0 = 3;
1551 break;
1552 }
1553
1554 g_cfg->dcomp_v42bis.p1 = atoi(argv[1]);
1555 g_cfg->dcomp_v42bis.p2 = atoi(argv[2]);
1556 return CMD_SUCCESS;
1557}
1558
1559DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
1560 "compression v42bis passive",
1561 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001562 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001563 "Compression is available on request\n")
1564{
1565 g_cfg->dcomp_v42bis.active = 0;
1566 g_cfg->dcomp_v42bis.passive = 1;
1567 return CMD_SUCCESS;
1568}
1569
Pau Espin Pedrol2c908992019-08-19 19:06:06 +02001570#if BUILD_IU
1571DEFUN(cfg_sgsn_cs7_instance_iu,
1572 cfg_sgsn_cs7_instance_iu_cmd,
1573 "cs7-instance-iu <0-15>",
1574 "Set SS7 to be used by the Iu-Interface.\n" "SS7 instance reference number (default: 0)\n")
1575{
1576 g_cfg->iu.cs7_instance = atoi(argv[0]);
1577 return CMD_SUCCESS;
1578}
1579#endif
1580
Pau Espin Pedrole5c89982021-05-03 18:16:42 +02001581DEFUN(cfg_sgsn_mme, cfg_sgsn_mme_cmd,
1582 "mme NAME",
1583 "Configure an MME peer\n"
1584 "Name identifying the MME peer\n")
1585{
1586 struct sgsn_mme_ctx *mme;
1587
1588 mme = sgsn_mme_ctx_find_alloc(sgsn, argv[0]);
1589 if (!mme)
1590 return CMD_WARNING;
1591
1592 vty->node = MME_NODE;
1593 vty->index = mme;
1594
1595 return CMD_SUCCESS;
1596}
1597
1598DEFUN(cfg_sgsn_no_mme, cfg_sgsn_no_mme_cmd,
1599 "no mme NAME",
1600 NO_STR "Delete an MME peer configuration\n"
1601 "Name identifying the MME peer\n")
1602{
1603 struct sgsn_mme_ctx *mme;
1604
1605 mme = sgsn_mme_ctx_by_name(sgsn, argv[0]);
1606 if (!mme) {
1607 vty_out(vty, "%% MME %s doesn't exist.%s",
1608 argv[0], VTY_NEWLINE);
1609 return CMD_WARNING;
1610 }
1611
1612 sgsn_mme_ctx_free(mme);
1613
1614 return CMD_SUCCESS;
1615}
1616
1617#define GTP_STR "Configure GTP connection\n"
1618
1619DEFUN(cfg_mme_remote_ip, cfg_mme_remote_ip_cmd,
1620 "gtp remote-ip A.B.C.D",
1621 GTP_STR "Set Remote GTP IP address\n" IP_STR)
1622{
1623 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1624
1625 inet_aton(argv[0], &mme->remote_addr);
1626
1627 return CMD_SUCCESS;
1628}
1629
1630#define RAN_INFO_STR "Configure RAN Information Relay routing\n"
1631#define TAI_DOC "MCC\n" "MNC\n" "TAC\n"
1632
1633DEFUN(cfg_mme_ran_info_relay_tai, cfg_mme_ran_info_relay_tai_cmd,
1634 "gtp ran-info-relay <0-999> <0-999> <0-65535>",
1635 GTP_STR RAN_INFO_STR TAI_DOC)
1636{
1637 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1638 struct sgsn_mme_ctx *mme_tmp;
1639 struct osmo_eutran_tai tai;
1640
1641 const char *mcc = argv[0];
1642 const char *mnc = argv[1];
1643 const char *tac = argv[2];
1644
1645 if (osmo_mcc_from_str(mcc, &tai.mcc)) {
1646 vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
1647 return CMD_WARNING;
1648 }
1649 if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
1650 vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
1651 return CMD_WARNING;
1652 }
1653 tai.tac = atoi(tac);
1654
1655 if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
1656 if (mme_tmp != mme) {
1657 vty_out(vty, "%% Another MME %s already contains this route%s",
1658 mme_tmp->name, VTY_NEWLINE);
1659 return CMD_WARNING;
1660 }
1661 /* else: NO-OP, return */
1662 return CMD_SUCCESS;
1663 }
1664
1665 sgsn_mme_ctx_route_add(mme, &tai);
1666 return CMD_SUCCESS;
1667}
1668
1669DEFUN(cfg_mme_no_ran_info_relay_tai, cfg_mme_no_ran_info_relay_tai_cmd,
1670 "no gtp ran-info-relay <0-999> <0-999> <0-65535>",
1671 NO_STR GTP_STR RAN_INFO_STR TAI_DOC)
1672{
1673 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1674 struct sgsn_mme_ctx *mme_tmp;
1675 struct osmo_eutran_tai tai;
1676
1677 const char *mcc = argv[0];
1678 const char *mnc = argv[1];
1679 const char *tac = argv[2];
1680
1681 if (osmo_mcc_from_str(mcc, &tai.mcc)) {
1682 vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
1683 return CMD_WARNING;
1684 }
1685 if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
1686 vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
1687 return CMD_WARNING;
1688 }
1689 tai.tac = atoi(tac);
1690
1691 if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
1692 if (mme_tmp != mme) {
1693 vty_out(vty, "%% Another MME %s contains this route%s",
1694 mme_tmp->name, VTY_NEWLINE);
1695 return CMD_WARNING;
1696 }
1697 sgsn_mme_ctx_route_del(mme, &tai);
1698 return CMD_SUCCESS;
1699 } else {
1700 vty_out(vty, "%% This route doesn't exist in current MME %s%s",
1701 mme->name, VTY_NEWLINE);
1702 return CMD_WARNING;
1703 }
1704}
1705
1706DEFUN(cfg_mme_ran_info_relay_default, cfg_mme_ran_info_relay_default_cmd,
1707 "gtp ran-info-relay default",
1708 GTP_STR RAN_INFO_STR "Set as default route")
1709{
1710 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1711 struct sgsn_mme_ctx *default_mme;
1712
1713 if (mme->default_route)
1714 return CMD_SUCCESS; /* NO-OP */
1715
1716 if ((default_mme = sgsn_mme_ctx_by_default_route(sgsn))) {
1717 vty_out(vty, "%% Another MME %s is already set as default route, "
1718 "remove it before setting it here.%s",
1719 default_mme->name, VTY_NEWLINE);
1720 return CMD_WARNING;
1721 }
1722
1723 mme->default_route = true;
1724 return CMD_SUCCESS;
1725}
1726
1727DEFUN(cfg_mme_no_ran_info_relay_default, cfg_mme_no_ran_info_relay_default_cmd,
1728 "no gtp ran-info-relay default",
1729 NO_STR GTP_STR RAN_INFO_STR "Set as default route")
1730{
1731 struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
1732 mme->default_route = false;
1733 return CMD_SUCCESS;
1734}
1735
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001736int sgsn_vty_init(struct sgsn_config *cfg)
Harald Welte288be162010-05-01 16:48:27 +02001737{
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001738 g_cfg = cfg;
1739
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001740 g_cfg->T_defs = sgsn_T_defs;
1741 osmo_tdefs_reset(g_cfg->T_defs);
1742
Pau Espin Pedrol85011262022-11-02 20:23:09 +01001743 g_cfg->T_defs_gtp = gtp_T_defs;
1744 osmo_tdefs_reset(g_cfg->T_defs_gtp);
1745
Harald Welted193cb32010-05-17 22:58:03 +02001746 install_element_ve(&show_sgsn_cmd);
1747 //install_element_ve(&show_mmctx_tlli_cmd);
1748 install_element_ve(&show_mmctx_imsi_cmd);
1749 install_element_ve(&show_mmctx_all_cmd);
1750 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001751 install_element_ve(&show_subscr_cache_cmd);
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001752 install_element_ve(&show_timer_cmd);
Pau Espin Pedrol85011262022-11-02 20:23:09 +01001753 install_element_ve(&show_timer_gtp_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001754
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001755 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001756 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001757 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001758 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001759 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1760 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Oliver Smithab39b622021-07-05 15:41:05 +02001761 install_element(ENABLE_NODE, &page_subscr_info_cmd);
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001762 install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001763
1764 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1765 install_node(&sgsn_node, config_write_sgsn);
Keithc70e8382020-10-19 22:24:48 +02001766 install_element(SGSN_NODE, &cfg_sgsn_state_dir_cmd);
Harald Weltee300d002010-06-02 12:41:34 +02001767 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001768 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1769 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1770 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +02001771 install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +02001772 install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001773 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001774 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Vadim Yanitskiy794f4462019-05-27 05:39:06 +07001775 install_element(SGSN_NODE, &cfg_authentication_cmd);
Eric2f898262021-05-19 18:57:50 +02001776
1777 /* order matters here: ensure we attempt to parse our new command first! */
1778 install_element(SGSN_NODE, &cfg_encrypt2_cmd);
Max93408ae2016-06-28 14:10:16 +02001779 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +01001780 install_element(SGSN_NODE, &cfg_encryption_uea_cmd);
Eric2f898262021-05-19 18:57:50 +02001781
Stefan Sperling88220092018-12-11 14:42:00 +01001782 install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001783 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1784 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001785 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1786 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1787 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001788 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1789 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001790 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1791 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001792 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1793 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001794 install_element(SGSN_NODE, &cfg_cdr_trap_cmd);
1795 install_element(SGSN_NODE, &cfg_no_cdr_trap_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001796 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001797 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001798 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001799
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001800 install_element(SGSN_NODE, &cfg_sgsn_timer_cmd);
Pau Espin Pedrol85011262022-11-02 20:23:09 +01001801 install_element(SGSN_NODE, &cfg_sgsn_timer_gtp_cmd);
Harald Welte94508822015-08-15 19:08:21 +02001802
Philippf1f34362016-08-26 17:00:21 +02001803 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1804 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1805 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
Philipp73f83d52016-09-02 13:38:01 +02001806 install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd);
1807 install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
1808 install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001809
Pau Espin Pedrole5c89982021-05-03 18:16:42 +02001810 install_element(SGSN_NODE, &cfg_sgsn_mme_cmd);
1811 install_element(SGSN_NODE, &cfg_sgsn_no_mme_cmd);
1812 install_node(&mme_node, NULL);
1813 install_element(MME_NODE, &cfg_mme_remote_ip_cmd);
1814 install_element(MME_NODE, &cfg_mme_ran_info_relay_default_cmd);
1815 install_element(MME_NODE, &cfg_mme_no_ran_info_relay_default_cmd);
1816 install_element(MME_NODE, &cfg_mme_ran_info_relay_tai_cmd);
1817 install_element(MME_NODE, &cfg_mme_no_ran_info_relay_tai_cmd);
1818
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001819#ifdef BUILD_IU
Pau Espin Pedrol2c908992019-08-19 19:06:06 +02001820 install_element(SGSN_NODE, &cfg_sgsn_cs7_instance_iu_cmd);
Neels Hofmeyra7a39472017-07-05 15:19:52 +02001821 ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001822#endif
Harald Welte288be162010-05-01 16:48:27 +02001823 return 0;
1824}
1825
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001826int sgsn_parse_config(const char *config_file)
Harald Welte288be162010-05-01 16:48:27 +02001827{
1828 int rc;
1829
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001830 /* make sure sgsn_vty_init() was called before this */
1831 OSMO_ASSERT(g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +01001832
Neels Hofmeyr340a7e92022-03-07 15:37:24 +01001833 g_cfg->gea_encryption_mask = 0x1; /* support GEA0 by default unless specific encryption config exists */
Neels Hofmeyr3c7656a2022-03-07 15:38:59 +01001834 g_cfg->uea_encryption_mask = (1 << OSMO_UTRAN_UEA0); /* support UEA0 by default unless specific encryption config exists */
Eric2f898262021-05-19 18:57:50 +02001835
Harald Weltedcccb182010-05-16 20:52:23 +02001836 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001837 if (rc < 0) {
1838 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1839 return rc;
1840 }
1841
Neels Hofmeyr27355c92017-02-24 06:28:31 +01001842 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE
1843 && !(g_cfg->gsup_server_addr.sin_addr.s_addr
1844 && g_cfg->gsup_server_port)) {
1845 fprintf(stderr, "Configuration error:"
1846 " 'auth-policy remote' requires both"
1847 " 'gsup remote-ip' and 'gsup remote-port'\n");
1848 return -EINVAL;
1849 }
1850
Harald Welte288be162010-05-01 16:48:27 +02001851 return 0;
1852}