blob: 66986911cb9dc18bec4d7d229769234460cac2f9 [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>
Harald Welteea34a4e2012-06-16 14:59:56 +080037#include <osmocom/gprs/gprs_ns.h>
Alexander Couzensc503f0a2018-08-07 17:50:04 +020038#include <osmocom/sgsn/gprs_gmm.h>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020039#include <osmocom/sgsn/gprs_sgsn.h>
40#include <osmocom/sgsn/vty.h>
Harald Weltef4b2c4c2018-09-16 07:53:41 +020041#include <osmocom/gsupclient/gsup_client.h>
Harald Welte288be162010-05-01 16:48:27 +020042
Pau Espin Pedrola299d652019-08-14 19:11:10 +020043#include <osmocom/vty/tdef_vty.h>
Harald Welte4b037e42010-05-19 19:45:32 +020044#include <osmocom/vty/command.h>
45#include <osmocom/vty/vty.h>
Pablo Neira Ayuso6110a3f2011-03-28 19:35:00 +020046#include <osmocom/vty/misc.h>
Max93408ae2016-06-28 14:10:16 +020047#include <osmocom/crypt/gprs_cipher.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010048#include <osmocom/abis/ipa.h>
49
Alexander Couzensc503f0a2018-08-07 17:50:04 +020050#include <osmocom/gprs/gprs_bssgp.h>
51
Harald Welted193cb32010-05-17 22:58:03 +020052#include <pdp.h>
Maxbaabc682017-10-20 13:39:57 +020053#include <gtp.h>
Harald Welted193cb32010-05-17 22:58:03 +020054
Neels Hofmeyr2188a772016-05-20 21:59:55 +020055#include "../../bscconfig.h"
56
57#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +020058#include <osmocom/ranap/iu_client.h>
Neels Hofmeyr2188a772016-05-20 21:59:55 +020059#endif
60
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +010061extern void *tall_sgsn_ctx;
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020062
Harald Welte288be162010-05-01 16:48:27 +020063static struct sgsn_config *g_cfg = NULL;
64
Jacob Erlbeck106f5472014-11-04 10:08:37 +010065const struct value_string sgsn_auth_pol_strs[] = {
66 { SGSN_AUTH_POLICY_OPEN, "accept-all" },
67 { SGSN_AUTH_POLICY_CLOSED, "closed" },
68 { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" },
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +010069 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeck106f5472014-11-04 10:08:37 +010070 { 0, NULL }
71};
72
Harald Welte94508822015-08-15 19:08:21 +020073/* Section 11.2.2 / Table 11.3a GPRS Mobility management timers – MS side */
74#define GSM0408_T3312_SECS (10*60) /* periodic RAU interval, default 54min */
75
76/* Section 11.2.2 / Table 11.4 MM timers netwokr side */
77#define GSM0408_T3322_SECS 6 /* DETACH_REQ -> DETACH_ACC */
78#define GSM0408_T3350_SECS 6 /* waiting for ATT/RAU/TMSI COMPL */
79#define GSM0408_T3360_SECS 6 /* waiting for AUTH/CIPH RESP */
80#define GSM0408_T3370_SECS 6 /* waiting for ID RESP */
81
Alexander Couzens5ba6fb32017-01-31 18:04:27 +010082/* Section 11.2.2 / Table 11.4a MM timers network side */
Harald Welte94508822015-08-15 19:08:21 +020083#define GSM0408_T3313_SECS 30 /* waiting for paging response */
84#define GSM0408_T3314_SECS 44 /* force to STBY on expiry, Ready timer */
85#define GSM0408_T3316_SECS 44
86
87/* Section 11.3 / Table 11.2d Timers of Session Management - network side */
88#define GSM0408_T3385_SECS 8 /* wait for ACT PDP CTX REQ */
89#define GSM0408_T3386_SECS 8 /* wait for MODIFY PDP CTX ACK */
90#define GSM0408_T3395_SECS 8 /* wait for DEACT PDP CTX ACK */
91#define GSM0408_T3397_SECS 8 /* wait for DEACT AA PDP CTX ACK */
92
Pau Espin Pedrola299d652019-08-14 19:11:10 +020093
94static struct osmo_tdef sgsn_T_defs[] = {
95 { .T=3312, .default_val=GSM0408_T3312_SECS, .desc="Periodic RA Update timer (s)" },
96 { .T=3313, .default_val=GSM0408_T3313_SECS, .desc="Waiting for paging response timer (s)" },
Alexander Couzens39cbecd2017-02-03 22:16:05 +010097 { .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 +020098 { .T=3316, .default_val=GSM0408_T3316_SECS, .desc="AA-Ready timer (s)" },
99 { .T=3322, .default_val=GSM0408_T3322_SECS, .desc="Detach request -> accept timer (s)" },
100 { .T=3350, .default_val=GSM0408_T3350_SECS, .desc="Waiting for ATT/RAU/TMSI_COMPL timer (s)" },
101 { .T=3360, .default_val=GSM0408_T3360_SECS, .desc="Waiting for AUTH/CIPH response timer (s)" },
102 { .T=3370, .default_val=GSM0408_T3370_SECS, .desc="Waiting for IDENTITY response timer (s)" },
103 { .T=3385, .default_val=GSM0408_T3385_SECS, .desc="Wait for ACT PDP CTX REQ timer (s)" },
104 { .T=3386, .default_val=GSM0408_T3386_SECS, .desc="Wait for MODIFY PDP CTX ACK timer (s)" },
105 { .T=3395, .default_val=GSM0408_T3395_SECS, .desc="Wait for DEACT PDP CTX ACK timer (s)" },
106 { .T=3397, .default_val=GSM0408_T3397_SECS, .desc="Wait for DEACT AA PDP CTX ACK timer (s)" },
107 {}
108};
109
110DEFUN(show_timer, show_timer_cmd,
111 "show timer " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
112 SHOW_STR "Show timers\n"
113 OSMO_TDEF_VTY_DOC_T)
114{
115 const char *T_arg = argc > 0 ? argv[0] : NULL;
116 return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs, T_arg, NULL);
Harald Welte94508822015-08-15 19:08:21 +0200117}
118
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200119DEFUN(cfg_sgsn_timer, cfg_sgsn_timer_cmd,
120 "timer " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
121 "Configure or show timers\n"
122 OSMO_TDEF_VTY_DOC_SET)
123{
124 /* If any arguments are missing, redirect to 'show' */
125 if (argc < 2)
126 return show_timer(self, vty, argc, argv);
127 return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs, argv);
128}
Harald Welte94508822015-08-15 19:08:21 +0200129
Holger Hans Peter Freythera2730302014-03-23 18:08:26 +0100130char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200131{
132 static char str[INET6_ADDRSTRLEN + 10];
133
134 if (!pdpa || len < 2)
135 return "none";
136
137 switch (pdpa[0] & 0x0f) {
138 case PDP_TYPE_ORG_IETF:
139 switch (pdpa[1]) {
140 case PDP_TYPE_N_IETF_IPv4:
141 if (len < 2 + 4)
142 break;
143 strcpy(str, "IPv4 ");
144 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
145 return str;
146 case PDP_TYPE_N_IETF_IPv6:
147 if (len < 2 + 8)
148 break;
149 strcpy(str, "IPv6 ");
150 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
151 return str;
152 default:
153 break;
154 }
155 break;
156 case PDP_TYPE_ORG_ETSI:
157 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
158 return "PPP";
159 break;
160 default:
161 break;
162 }
163
164 return "invalid";
165}
166
Harald Welte288be162010-05-01 16:48:27 +0200167static struct cmd_node sgsn_node = {
168 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200169 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200170 1,
171};
172
173static int config_write_sgsn(struct vty *vty)
174{
Harald Welte77289c22010-05-18 14:32:29 +0200175 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100176 struct imsi_acl_entry *acl;
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100177 struct apn_ctx *actx;
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800178 struct ares_addr_node *server;
Harald Welte288be162010-05-01 16:48:27 +0200179
180 vty_out(vty, "sgsn%s", VTY_NEWLINE);
181
Harald Weltee300d002010-06-02 12:41:34 +0200182 vty_out(vty, " gtp local-ip %s%s",
183 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
184
Harald Welted193cb32010-05-17 22:58:03 +0200185 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800186 if (gctx->id == UINT32_MAX)
187 continue;
188
Harald Welteff3bde82010-05-19 15:09:09 +0200189 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200190 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200191 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200192 gctx->gtp_version, VTY_NEWLINE);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200193 if (gctx->echo_interval != -1)
194 vty_out(vty, " ggsn %u echo-interval %"PRId32"%s",
195 gctx->id, gctx->echo_interval, VTY_NEWLINE);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200196 else
197 vty_out(vty, " ggsn %u no echo-interval%s",
198 gctx->id, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200199 }
200
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800201 if (sgsn->cfg.dynamic_lookup)
202 vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE);
203
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800204 for (server = sgsn->ares_servers; server; server = server->next)
205 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
206
Max93408ae2016-06-28 14:10:16 +0200207 if (g_cfg->cipher != GPRS_ALGO_GEA0)
208 vty_out(vty, " encryption %s%s",
209 get_value_string(gprs_cipher_names, g_cfg->cipher),
210 VTY_NEWLINE);
Stefan Sperling88220092018-12-11 14:42:00 +0100211 if (g_cfg->sgsn_ipa_name)
212 vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100213 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
214 vty_out(vty, " gsup remote-ip %s%s",
215 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
216 if (g_cfg->gsup_server_port)
217 vty_out(vty, " gsup remote-port %d%s",
218 g_cfg->gsup_server_port, VTY_NEWLINE);
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200219 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE && !g_cfg->require_authentication)
220 vty_out(vty, " authentication optional%s", VTY_NEWLINE);
Max176b62a2016-07-04 11:09:07 +0200221 vty_out(vty, " auth-policy %s%s",
222 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
223 VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200224
225 vty_out(vty, " gsup oap-id %d%s",
226 (int)g_cfg->oap.client_id, VTY_NEWLINE);
227 if (g_cfg->oap.secret_k_present != 0)
228 vty_out(vty, " gsup oap-k %s%s",
229 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
230 VTY_NEWLINE);
231 if (g_cfg->oap.secret_opc_present != 0)
232 vty_out(vty, " gsup oap-opc %s%s",
233 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
234 VTY_NEWLINE);
235
Harald Welte7f6da482013-03-19 11:00:13 +0100236 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
237 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
238
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100239 if (llist_empty(&sgsn_apn_ctxts))
240 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
241 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
242 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200243 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100244 actx->name, actx->imsi_prefix, actx->ggsn->id,
245 VTY_NEWLINE);
246 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200247 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100248 actx->ggsn->id, VTY_NEWLINE);
249 }
250
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200251 if (g_cfg->cdr.filename)
252 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
253 else
254 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +0100255 if (g_cfg->cdr.trap)
256 vty_out(vty, " cdr trap%s", VTY_NEWLINE);
257 else
258 vty_out(vty, " no cdr trap%s", VTY_NEWLINE);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200259 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
260
Pau Espin Pedrola299d652019-08-14 19:11:10 +0200261 osmo_tdef_vty_write(vty, g_cfg->T_defs, " timer ");
Harald Welte94508822015-08-15 19:08:21 +0200262
Philippf1f34362016-08-26 17:00:21 +0200263 if (g_cfg->pcomp_rfc1144.active) {
264 vty_out(vty, " compression rfc1144 active slots %d%s",
265 g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE);
266 } else if (g_cfg->pcomp_rfc1144.passive) {
267 vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE);
268 } else
269 vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE);
270
Philipp73f83d52016-09-02 13:38:01 +0200271 if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) {
272 vty_out(vty,
273 " compression v42bis active direction sgsn codewords %d strlen %d%s",
274 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
275 VTY_NEWLINE);
276 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) {
277 vty_out(vty,
278 " compression v42bis active direction ms codewords %d strlen %d%s",
279 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
280 VTY_NEWLINE);
281 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) {
282 vty_out(vty,
283 " compression v42bis active direction both codewords %d strlen %d%s",
284 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
285 VTY_NEWLINE);
286 } else if (g_cfg->dcomp_v42bis.passive) {
287 vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE);
288 } else
289 vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
290
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200291#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +0200292 ranap_iu_vty_config_write(vty, " ");
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200293#endif
294
Harald Welte288be162010-05-01 16:48:27 +0200295 return CMD_SUCCESS;
296}
297
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100298#define SGSN_STR "Configure the SGSN\n"
299#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200300
301DEFUN(cfg_sgsn, cfg_sgsn_cmd,
302 "sgsn",
303 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200304{
305 vty->node = SGSN_NODE;
306 return CMD_SUCCESS;
307}
308
Harald Weltee300d002010-06-02 12:41:34 +0200309DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
310 "gtp local-ip A.B.C.D",
311 "GTP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100312 "Set the IP address for the local GTP bind for the Gp interface (towards the GGSNs)."
313 " Note: in case you would like to run the GGSN on the same machine as the SGSN, you can not run"
314 " both on the same IP address, since both sides are specified to use the same GTP port numbers"
315 " (" OSMO_STRINGIFY_VAL(GTP1C_PORT) " and " OSMO_STRINGIFY_VAL(GTP1U_PORT) ")."
316 " For example, you could use 127.0.0.1 for the SGSN and 127.0.0.2 for the GGSN in such"
317 " situations.\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100318 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200319{
320 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
321
322 return CMD_SUCCESS;
323}
324
Harald Welted193cb32010-05-17 22:58:03 +0200325DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
326 "ggsn <0-255> remote-ip A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100327 GGSN_STR "GGSN Number\n"
328 "Configure this static GGSN to use the specified remote IP address.\n"
329 "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200330{
331 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200332 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200333
Harald Welted193cb32010-05-17 22:58:03 +0200334 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200335
Harald Welted193cb32010-05-17 22:58:03 +0200336 return CMD_SUCCESS;
337}
338
339#if 0
340DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
341 "ggsn <0-255> remote-port <0-65535>",
342 "")
343{
344 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200345 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200346 uint16_t port = atoi(argv[1]);
347
348}
349#endif
350
351DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
352 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100353 GGSN_STR "GGSN Number\n" "GTP Version\n"
354 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200355{
356 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200357 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200358
359 if (atoi(argv[1]))
360 ggc->gtp_version = 1;
361 else
362 ggc->gtp_version = 0;
363
364 return CMD_SUCCESS;
365}
366
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200367/* Seee 3GPP TS 29.060 section 7.2.1 */
368DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
369 "ggsn <0-255> echo-interval <1-36000>",
370 GGSN_STR "GGSN Number\n"
371 "Send an echo request to this static GGSN every interval.\n"
372 "Interval between echo requests in seconds.\n")
373{
374 uint32_t id = atoi(argv[0]);
375 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
376
377 ggc->echo_interval = atoi(argv[1]);
378
379 if (ggc->echo_interval < 60)
Pau Espin Pedrolba2e5002019-05-27 17:35:32 +0200380 vty_out(vty, "%% 3GPP TS 29.060 section 7.2.1 states interval should " \
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200381 "not be lower than 60 seconds, use this value for " \
382 "testing purposes only!%s", VTY_NEWLINE);
383
Alexander Couzens176a4d22018-09-18 20:07:37 +0200384 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200385 return CMD_SUCCESS;
386}
387
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200388DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
389 "ggsn <0-255> no echo-interval",
390 GGSN_STR "GGSN Number\n"
391 NO_STR "Send an echo request to this static GGSN every interval.\n")
392{
393 uint32_t id = atoi(argv[0]);
394 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
395
396 ggc->echo_interval = -1;
Alexander Couzens176a4d22018-09-18 20:07:37 +0200397 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200398
399 return CMD_SUCCESS;
400}
401
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800402DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
403 "ggsn dynamic",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100404 GGSN_STR
405 "Enable dynamic resolving of GGSNs based on DNS resolving the APN name like in a GRX-style setup."
406 " Changing this setting requires a restart.\n")
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800407{
408 sgsn->cfg.dynamic_lookup = 1;
409 return CMD_SUCCESS;
410}
411
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800412DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
413 "grx-dns-add A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100414 "Use the specified IP address for DNS-resolving the AP names to GGSN IP addresses\n"
415 "IPv4 address\n")
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800416{
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +0100417 struct ares_addr_node *node = talloc_zero(tall_sgsn_ctx, struct ares_addr_node);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800418 node->family = AF_INET;
419 inet_aton(argv[0], &node->addr.addr4);
420
421 node->next = sgsn->ares_servers;
422 sgsn->ares_servers = node;
423 return CMD_SUCCESS;
424}
425
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100426#define APN_STR "Configure the information per APN\n"
427#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
428
429static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
430 const char *imsi_prefix, int ggsn_id)
431{
432 struct apn_ctx *actx;
433 struct sgsn_ggsn_ctx *ggsn;
434
435 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
436 if (ggsn == NULL) {
437 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
438 ggsn_id, VTY_NEWLINE);
439 return CMD_WARNING;
440 }
441
442 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
443 if (!actx) {
444 vty_out(vty, "%% unable to create APN context for %s/%s%s",
445 apn_str, imsi_prefix, VTY_NEWLINE);
446 return CMD_WARNING;
447 }
448
449 actx->ggsn = ggsn;
450
451 return CMD_SUCCESS;
452}
453
Harald Welted193cb32010-05-17 22:58:03 +0200454DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
455 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100456 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100457 "Select the GGSN to use for the given APN gateway prefix\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100458 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200459{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100460
461 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200462}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100463
464DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
465 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
466 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100467 "Select the GGSN to use for the given APN gateway prefix if and only if the IMSI matches the"
468 " given prefix.\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100469 "An IMSI prefix\n"
470 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
471 "The GGSN id")
472{
473
474 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
475}
Harald Welted193cb32010-05-17 22:58:03 +0200476
477const struct value_string gprs_mm_st_strs[] = {
478 { GMM_DEREGISTERED, "DEREGISTERED" },
479 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
480 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200481 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200482 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
483 { 0, NULL }
484};
485
Maxc005db72017-10-27 18:43:29 +0200486char *sgsn_gtp_ntoa(struct ul16_t *ul)
Harald Welte471ac7d2016-12-15 19:48:58 +0100487{
Max8492c202017-12-05 17:28:15 +0100488 struct in_addr ia;
489
490 if (gsna2in_addr(&ia, ul) != 0)
Harald Welte471ac7d2016-12-15 19:48:58 +0100491 return "UNKNOWN";
Max8492c202017-12-05 17:28:15 +0100492
493 return inet_ntoa(ia);
Harald Welte471ac7d2016-12-15 19:48:58 +0100494}
495
Harald Welted193cb32010-05-17 22:58:03 +0200496static void vty_dump_pdp(struct vty *vty, const char *pfx,
497 struct sgsn_pdp_ctx *pdp)
498{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200499 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welte471ac7d2016-12-15 19:48:58 +0100500 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s",
501 pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200502 if (pdp->lib) {
Max7933d962017-10-19 16:52:30 +0200503 char apnbuf[APN_MAXLEN + 1];
Harald Weltedfbd2c82017-08-13 00:56:45 +0200504 vty_out(vty, "%s APN: %s%s", pfx,
Max7933d962017-10-19 16:52:30 +0200505 osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200506 VTY_NEWLINE);
507 vty_out(vty, "%s PDP Address: %s%s", pfx,
508 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
509 VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100510 vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200511 sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200512 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200513 sgsn_gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100514 vty_out(vty, "%s GTPv%d Remote Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200515 sgsn_gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200516 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200517 sgsn_gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200518 }
Harald Welte471ac7d2016-12-15 19:48:58 +0100519
Harald Welteefbdee92010-06-10 00:20:12 +0200520 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200521}
522
523static void vty_dump_mmctx(struct vty *vty, const char *pfx,
524 struct sgsn_mm_ctx *mm, int pdp)
525{
526 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
527 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200528 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Harald Weltef97ee042015-12-25 19:12:21 +0100529 pfx, mm->msisdn, mm->gb.tlli, mm->hlr, VTY_NEWLINE);
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100530 vty_out(vty, "%s MM State: %s, Routeing Area: %s, Cell ID: %u%s",
531 pfx, get_value_string(gprs_mm_st_strs, mm->gmm_state),
532 osmo_rai_name(&mm->ra), mm->gb.cell_id, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200533
Harald Welte8acd88f2010-05-18 10:57:45 +0200534 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
535
Harald Welted193cb32010-05-17 22:58:03 +0200536 if (pdp) {
537 struct sgsn_pdp_ctx *pdp;
538
539 llist_for_each_entry(pdp, &mm->pdp_list, list)
540 vty_dump_pdp(vty, " ", pdp);
541 }
542}
543
544DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
545 SHOW_STR "Display information about the SGSN")
546{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100547 if (sgsn->gsup_client) {
548 struct ipa_client_conn *link = sgsn->gsup_client->link;
549 vty_out(vty,
550 " Remote authorization: %sconnected to %s:%d via GSUP%s",
551 sgsn->gsup_client->is_connected ? "" : "not ",
552 link->addr, link->port,
553 VTY_NEWLINE);
554 }
Maxbaabc682017-10-20 13:39:57 +0200555 if (sgsn->gsn)
556 vty_out(vty, " GSN: signalling %s, user traffic %s%s",
557 inet_ntoa(sgsn->gsn->gsnc), inet_ntoa(sgsn->gsn->gsnu), VTY_NEWLINE);
558
Harald Welted193cb32010-05-17 22:58:03 +0200559 /* FIXME: statistics */
560 return CMD_SUCCESS;
561}
562
563#define MMCTX_STR "MM Context\n"
564#define INCLUDE_PDP_STR "Include PDP Context Information\n"
565
566#if 0
567DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
568 "show mm-context tlli HEX [pdp]",
569 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
570{
571 uint32_t tlli;
572 struct sgsn_mm_ctx *mm;
573
574 tlli = strtoul(argv[0], NULL, 16);
575 mm = sgsn_mm_ctx_by_tlli(tlli);
576 if (!mm) {
577 vty_out(vty, "No MM context for TLLI %08x%s",
578 tlli, VTY_NEWLINE);
579 return CMD_WARNING;
580 }
581 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
582 return CMD_SUCCESS;
583}
584#endif
585
586DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
587 "show mm-context imsi IMSI [pdp]",
588 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
589 INCLUDE_PDP_STR)
590{
591 struct sgsn_mm_ctx *mm;
592
593 mm = sgsn_mm_ctx_by_imsi(argv[0]);
594 if (!mm) {
595 vty_out(vty, "No MM context for IMSI %s%s",
596 argv[0], VTY_NEWLINE);
597 return CMD_WARNING;
598 }
599 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
600 return CMD_SUCCESS;
601}
602
603DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
604 "show mm-context all [pdp]",
605 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
606{
607 struct sgsn_mm_ctx *mm;
608
609 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
610 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
611
612 return CMD_SUCCESS;
613}
614
Harald Welted193cb32010-05-17 22:58:03 +0200615DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
616 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100617 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200618{
619 struct sgsn_pdp_ctx *pdp;
620
621 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
622 vty_dump_pdp(vty, "", pdp);
623
624 return CMD_SUCCESS;
625}
Harald Welte288be162010-05-01 16:48:27 +0200626
Harald Welte7f6da482013-03-19 11:00:13 +0100627
628DEFUN(imsi_acl, cfg_imsi_acl_cmd,
629 "imsi-acl (add|del) IMSI",
630 "Access Control List of foreign IMSIs\n"
631 "Add IMSI to ACL\n"
632 "Remove IMSI from ACL\n"
633 "IMSI of subscriber\n")
634{
Maxef38b4c2018-11-20 10:25:53 +0100635 char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS + 1];
Harald Welte7f6da482013-03-19 11:00:13 +0100636 const char *op = argv[0];
Philipp Maier6ee49d82017-02-28 16:53:07 +0100637 const char *imsi = imsi_sanitized;
Maxf4fa6952018-01-15 12:12:51 +0100638 size_t len = strnlen(argv[1], GSM23003_IMSI_MAX_DIGITS + 1);
Harald Welte7f6da482013-03-19 11:00:13 +0100639 int rc;
640
Maxef38b4c2018-11-20 10:25:53 +0100641 memset(imsi_sanitized, '0', GSM23003_IMSI_MAX_DIGITS);
642 imsi_sanitized[GSM23003_IMSI_MAX_DIGITS] = '\0';
643
Philipp Maier6ee49d82017-02-28 16:53:07 +0100644 /* Sanitize IMSI */
Maxf4fa6952018-01-15 12:12:51 +0100645 if (len > GSM23003_IMSI_MAX_DIGITS) {
646 vty_out(vty, "%% IMSI (%s) too long (max %u digits) -- ignored!%s",
647 argv[1], GSM23003_IMSI_MAX_DIGITS, VTY_NEWLINE);
Philipp Maier6ee49d82017-02-28 16:53:07 +0100648 return CMD_WARNING;
649 }
Maxf4fa6952018-01-15 12:12:51 +0100650
651 osmo_strlcpy(imsi_sanitized + GSM23003_IMSI_MAX_DIGITS - len, argv[1],
652 sizeof(imsi_sanitized) - (GSM23003_IMSI_MAX_DIGITS - len));
Philipp Maier6ee49d82017-02-28 16:53:07 +0100653
Harald Welte7f6da482013-03-19 11:00:13 +0100654 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200655 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100656 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200657 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100658
659 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100660 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100661 return CMD_WARNING;
662 }
663
664 return CMD_SUCCESS;
665}
666
Max93408ae2016-06-28 14:10:16 +0200667DEFUN(cfg_encrypt, cfg_encrypt_cmd,
668 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
669 "Set encryption algorithm for SGSN\n"
670 "Use GEA0 (no encryption)\n"
671 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
672{
Max93408ae2016-06-28 14:10:16 +0200673 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
Max086067f2017-05-02 13:03:28 +0200674 if (c != GPRS_ALGO_GEA0) {
675 if (!gprs_cipher_supported(c)) {
676 vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
677 return CMD_WARNING;
678 }
679
680 if (!g_cfg->require_authentication) {
681 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
682 argv[0], VTY_NEWLINE);
683 return CMD_WARNING;
684 }
Max93408ae2016-06-28 14:10:16 +0200685 }
686
687 g_cfg->cipher = c;
688
689 return CMD_SUCCESS;
690}
691
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700692DEFUN(cfg_authentication, cfg_authentication_cmd,
693 "authentication (optional|required)",
Pau Espin Pedrold1463bc2019-06-13 19:03:25 +0200694 "Whether to enforce MS authentication in GERAN (only with auth-policy remote)\n"
695 "Allow MS to attach via GERAN without authentication (default and only possible value for non-remote auth-policy)\n"
696 "Always require authentication (only available for auth-policy remote, default with that auth-policy)\n")
Vadim Yanitskiy794f4462019-05-27 05:39:06 +0700697{
698 int required = (argv[0][0] == 'r');
699
700 if (vty->type != VTY_FILE) {
701 if (g_cfg->auth_policy != SGSN_AUTH_POLICY_REMOTE && required) {
702 vty_out(vty, "%% Authentication is not possible without HLR, "
703 "consider setting 'auth-policy' to 'remote'%s",
704 VTY_NEWLINE);
705 return CMD_WARNING;
706 }
707 }
708
709 g_cfg->require_authentication = required;
710 return CMD_SUCCESS;
711}
712
Harald Welte3dfb5492013-03-19 11:48:54 +0100713DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100714 "auth-policy (accept-all|closed|acl-only|remote)",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100715 "Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
716 " permitted to register to the network.\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100717 "Accept all IMSIs (DANGEROUS)\n"
718 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100719 "Accept only subscribers in the ACL\n"
720 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100721{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100722 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100723 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100724 g_cfg->auth_policy = val;
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100725 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100726
727 return CMD_SUCCESS;
728}
729
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100730/* Subscriber */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +0200731#include <osmocom/sgsn/gprs_subscriber.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100732
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100733static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100734{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100735#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100736 char expire_time[200];
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100737#endif
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100738 struct gsm_auth_tuple *at;
739 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100740 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100741
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100742 vty_out(vty, " Authorized: %d%s",
743 gsub->authorized, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100744 vty_out(vty, " LAC: %d/0x%x%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100745 gsub->lac, gsub->lac, VTY_NEWLINE);
746 vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
747 if (gsub->tmsi != GSM_RESERVED_TMSI)
748 vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100749 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100750 if (gsub->sgsn_data->msisdn_len > 0)
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400751 vty_out(vty, " MSISDN (BCD): %s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100752 osmo_hexdump(gsub->sgsn_data->msisdn,
753 gsub->sgsn_data->msisdn_len),
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400754 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100755
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100756 if (strlen(gsub->imei) > 0)
757 vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100758
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100759 for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100760 at_idx++) {
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100761 at = &gsub->sgsn_data->auth_triplets[at_idx];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100762 if (at->key_seq == GSM_KEY_SEQ_INVAL)
763 continue;
764
765 vty_out(vty, " A3A8 tuple (used %d times): ",
766 at->use_count);
Harald Welte89837d42016-05-06 23:28:11 +0200767 vty_out(vty, " CKSN: %d, ",
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100768 at->key_seq);
Harald Welte89837d42016-05-06 23:28:11 +0200769 if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
770 vty_out(vty, "RAND: %s, ",
Max34604c22019-02-13 14:11:29 +0100771 osmo_hexdump_nospc(at->vec.rand,
Harald Welte89837d42016-05-06 23:28:11 +0200772 sizeof(at->vec.rand)));
773 vty_out(vty, "SRES: %s, ",
Max34604c22019-02-13 14:11:29 +0100774 osmo_hexdump_nospc(at->vec.sres,
Harald Welte89837d42016-05-06 23:28:11 +0200775 sizeof(at->vec.sres)));
776 vty_out(vty, "Kc: %s%s",
Max34604c22019-02-13 14:11:29 +0100777 osmo_hexdump_nospc(at->vec.kc,
Harald Welte89837d42016-05-06 23:28:11 +0200778 sizeof(at->vec.kc)), VTY_NEWLINE);
779 }
780 if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
781 vty_out(vty, " AUTN: %s, ",
782 osmo_hexdump(at->vec.autn,
783 sizeof(at->vec.autn)));
784 vty_out(vty, "RES: %s, ",
Max34604c22019-02-13 14:11:29 +0100785 osmo_hexdump_nospc(at->vec.res, at->vec.res_len));
Harald Welte89837d42016-05-06 23:28:11 +0200786 vty_out(vty, "IK: %s, ",
Max34604c22019-02-13 14:11:29 +0100787 osmo_hexdump_nospc(at->vec.ik, sizeof(at->vec.ik)));
Harald Welte89837d42016-05-06 23:28:11 +0200788 vty_out(vty, "CK: %s, ",
Max34604c22019-02-13 14:11:29 +0100789 osmo_hexdump_nospc(at->vec.ck, sizeof(at->vec.ck)));
Harald Welte89837d42016-05-06 23:28:11 +0200790 }
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100791 }
792
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100793 llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
Max34604c22019-02-13 14:11:29 +0100794 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'",
795 pdp->context_id, pdp->pdp_type, pdp->apn_str);
796
797 if (pdp->qos_subscribed_len)
798 vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len));
799
800 vty_out(vty, "%s", VTY_NEWLINE);
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100801 }
802
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100803#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100804 /* print the expiration time of a subscriber */
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100805 if (gsub->expire_lu) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100806 strftime(expire_time, sizeof(expire_time),
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100807 "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100808 expire_time[sizeof(expire_time) - 1] = '\0';
809 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
810 }
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100811#endif
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100812
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100813 if (gsub->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100814 vty_out(vty, " Flags: %s%s%s%s%s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100815 gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100816 "FIRST_CONTACT " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100817 gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100818 "CANCELLED " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100819 gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100820 "UPDATE_LOCATION_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100821 gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100822 "AUTH_INFO_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100823 gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100824 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100825 VTY_NEWLINE);
826
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100827 vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100828}
829
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200830#define RESET_SGSN_STATE_STR \
831 "Remove all known subscribers, MM contexts and flush BSSGP queues." \
832 " Useful only when running tests against the SGSN\n"
833
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200834DEFUN_HIDDEN(reset_sgsn_state,
835 reset_sgsn_state_cmd,
836 "reset sgsn state",
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200837 RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR)
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200838{
839 struct gprs_subscr *subscr, *tmp_subscr;
840 struct sgsn_mm_ctx *mm, *tmp_mm;
841
842 llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
843 {
844 gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
845 }
846 vty_out(vty, "Cancelled MM Ctx. %s", VTY_NEWLINE);
847
848 llist_for_each_entry_safe(subscr, tmp_subscr, gprs_subscribers, entry) {
849 gprs_subscr_get(subscr);
850 gprs_subscr_cancel(subscr);
851 gprs_subscr_put(subscr);
852 }
853 vty_out(vty, "Removed all gprs subscribers.%s", VTY_NEWLINE);
854
855 bssgp_flush_all_queues();
856 vty_out(vty, "Flushed all BSSGPs queues.%s", VTY_NEWLINE);
857
Alexander Couzens35c34942018-09-17 04:39:14 +0200858 gtp_clear_queues(sgsn->gsn);
Alexander Couzensa66f0f22018-09-18 16:09:18 +0200859 vty_out(vty, "Flushed rx & tx queus towards the GGSN.%s", VTY_NEWLINE);
Alexander Couzens35c34942018-09-17 04:39:14 +0200860
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200861 /* remove all queues to bssgp */
862 return CMD_SUCCESS;
863}
864
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100865DEFUN(show_subscr_cache,
866 show_subscr_cache_cmd,
867 "show subscriber cache",
868 SHOW_STR "Show information about subscribers\n"
869 "Display contents of subscriber cache\n")
870{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100871 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100872
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100873 llist_for_each_entry(subscr, gprs_subscribers, entry) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100874 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
875 subscr_dump_full_vty(vty, subscr, 0);
876 }
877
878 return CMD_SUCCESS;
879}
880
881#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
882#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
883 "Use the IMSI to select the subscriber\n" \
884 "The IMSI\n"
885
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100886#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
887
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100888DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
889 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
890 UPDATE_SUBSCR_HELP
891 UPDATE_SUBSCR_INSERT_HELP
892 "Update authentication triplet\n"
893 "Triplet index\n"
894 "Set SRES value\nSRES value (4 byte) in hex\n"
895 "Set RAND value\nRAND value (16 byte) in hex\n"
896 "Set Kc value\nKc value (8 byte) in hex\n")
897{
898 const char *imsi = argv[0];
899 const int cksn = atoi(argv[1]) - 1;
900 const char *sres_str = argv[2];
901 const char *rand_str = argv[3];
902 const char *kc_str = argv[4];
903 struct gsm_auth_tuple at = {0,};
904
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100905 struct gprs_subscr *subscr;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100906
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100907 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100908 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100909 vty_out(vty, "%% unable get subscriber record for %s%s",
910 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100911 return CMD_WARNING;
912 }
913
914 OSMO_ASSERT(subscr->sgsn_data);
915
Harald Welte121e9a42016-04-20 13:13:19 +0200916 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100917 vty_out(vty, "%% invalid SRES value '%s'%s",
918 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100919 goto failed;
920 }
Harald Welte121e9a42016-04-20 13:13:19 +0200921 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100922 vty_out(vty, "%% invalid RAND value '%s'%s",
923 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100924 goto failed;
925 }
Harald Welte121e9a42016-04-20 13:13:19 +0200926 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100927 vty_out(vty, "%% invalid Kc value '%s'%s",
928 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100929 goto failed;
930 }
931 at.key_seq = cksn;
932
933 subscr->sgsn_data->auth_triplets[cksn] = at;
934 subscr->sgsn_data->auth_triplets_updated = 1;
935
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100936 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100937
938 return CMD_SUCCESS;
939
940failed:
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100941 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100942 return CMD_SUCCESS;
943}
944
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100945DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100946 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100947 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100948 "Cancel (remove) subscriber record\n"
949 "The MS moved to another SGSN\n"
950 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100951{
952 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100953 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100954
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100955 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100956
957 subscr = gprs_subscr_get_by_imsi(imsi);
958 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100959 vty_out(vty, "%% no subscriber record for %s%s",
960 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100961 return CMD_WARNING;
962 }
963
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100964 if (strcmp(cancel_type, "update-procedure") == 0)
965 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
966 else
967 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
968
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100969 gprs_subscr_cancel(subscr);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100970 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100971
972 return CMD_SUCCESS;
973}
974
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100975DEFUN(update_subscr_create, update_subscr_create_cmd,
976 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100977 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100978 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100979{
980 const char *imsi = argv[0];
981
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100982 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100983
984 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100985 if (subscr) {
986 vty_out(vty, "%% subscriber record already exists for %s%s",
987 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100988 return CMD_WARNING;
989 }
990
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100991 subscr = gprs_subscr_get_or_create(imsi);
992 subscr->keep_in_ram = 1;
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100993 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100994
995 return CMD_SUCCESS;
996}
997
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100998DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
999 UPDATE_SUBSCR_STR "destroy",
1000 UPDATE_SUBSCR_HELP
1001 "Destroy a subscriber entry\n")
1002{
1003 const char *imsi = argv[0];
1004
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001005 struct gprs_subscr *subscr;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001006
1007 subscr = gprs_subscr_get_by_imsi(imsi);
1008 if (!subscr) {
1009 vty_out(vty, "%% subscriber record does not exist for %s%s",
1010 imsi, VTY_NEWLINE);
1011 return CMD_WARNING;
1012 }
1013
1014 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +01001015 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001016 gprs_subscr_cancel(subscr);
1017 if (subscr->use_count > 1)
1018 vty_out(vty, "%% subscriber is still in use%s",
1019 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001020 gprs_subscr_put(subscr);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001021
1022 return CMD_SUCCESS;
1023}
1024
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001025#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
1026 "unknown-subscriber|roaming-not-allowed"
1027
1028#define UL_ERR_HELP \
1029 "Force error code SystemFailure\n" \
1030 "Force error code DataMissing\n" \
1031 "Force error code UnexpectedDataValue\n" \
1032 "Force error code UnknownSubscriber\n" \
1033 "Force error code RoamingNotAllowed\n"
1034
1035DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
1036 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
1037 UPDATE_SUBSCR_HELP
1038 "Complete the update location procedure\n"
1039 "The update location request succeeded\n"
1040 UL_ERR_HELP)
1041{
1042 const char *imsi = argv[0];
1043 const char *ret_code_str = argv[1];
1044
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001045 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001046
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001047 const struct value_string cause_mapping[] = {
1048 { GMM_CAUSE_NET_FAIL, "system-failure" },
1049 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
1050 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
1051 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
1052 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
1053 { 0, NULL }
1054 };
1055
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001056 subscr = gprs_subscr_get_by_imsi(imsi);
1057 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001058 vty_out(vty, "%% unable to get subscriber record for %s%s",
1059 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001060 return CMD_WARNING;
1061 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001062
1063 if (strcmp(ret_code_str, "ok") == 0) {
1064 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001065 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001066 } else {
1067 subscr->sgsn_data->error_cause =
1068 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001069 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001070 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001071
1072 gprs_subscr_update(subscr);
1073
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001074 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001075
1076 return CMD_SUCCESS;
1077}
1078
1079DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
1080 UPDATE_SUBSCR_STR "update-auth-info",
1081 UPDATE_SUBSCR_HELP
1082 "Complete the send authentication info procedure\n")
1083{
1084 const char *imsi = argv[0];
1085
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001086 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001087
1088 subscr = gprs_subscr_get_by_imsi(imsi);
1089 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001090 vty_out(vty, "%% unable to get subscriber record for %s%s",
1091 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001092 return CMD_WARNING;
1093 }
1094
1095 gprs_subscr_update_auth_info(subscr);
1096
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001097 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001098
1099 return CMD_SUCCESS;
1100}
1101
Stefan Sperling88220092018-12-11 14:42:00 +01001102DEFUN(cfg_gsup_ipa_name,
1103 cfg_gsup_ipa_name_cmd,
1104 "gsup ipa-name NAME",
1105 "GSUP Parameters\n"
1106 "Set the IPA name of this SGSN\n"
1107 "A unique name for this SGSN. For example: PLMN + redundancy server number: SGSN-901-70-0. "
1108 "This name is used for GSUP routing and must be set if more than one SGSN is connected to the network. "
1109 "The default is 'SGSN-00-00-00-00-00-00'.\n")
1110{
1111 if (vty->type != VTY_FILE) {
1112 vty_out(vty, "The IPA name cannot be changed at run-time; "
1113 "It can only be set in the configuraton file.%s", VTY_NEWLINE);
1114 return CMD_WARNING;
1115 }
1116
1117 g_cfg->sgsn_ipa_name = talloc_strdup(tall_vty_ctx, argv[0]);
1118 return CMD_SUCCESS;
1119}
1120
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001121DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
1122 "gsup remote-ip A.B.C.D",
1123 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001124 "Set the IP address of the remote GSUP server (e.g. OsmoHLR)."
1125 " This setting only applies if 'auth-policy remote' is used.\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001126 "IPv4 Address\n")
1127{
1128 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
1129
1130 return CMD_SUCCESS;
1131}
1132
1133DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
1134 "gsup remote-port <0-65535>",
1135 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001136 "Set the TCP port of the remote GSUP server, see also 'gsup remote-ip'\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001137 "Remote TCP port\n")
1138{
1139 g_cfg->gsup_server_port = atoi(argv[0]);
1140
1141 return CMD_SUCCESS;
1142}
1143
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001144DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
1145 "gsup oap-id <0-65535>",
1146 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001147 "Set the OAP client ID for authentication on the GSUP protocol."
1148 " This setting only applies if 'auth-policy remote' is used.\n"
1149 "OAP client ID (0 == disabled)\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001150{
1151 /* VTY ensures range */
1152 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
1153 return CMD_SUCCESS;
1154}
1155
1156DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
1157 "gsup oap-k K",
1158 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001159 "Set the OAP shared secret key K for authentication on the GSUP protocol."
1160 " This setting only applies if auth-policy remote is used.\n"
1161 "K value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001162{
1163 const char *k = argv[0];
1164
1165 g_cfg->oap.secret_k_present = 0;
1166
1167 if ((!k) || (strlen(k) == 0))
1168 goto disable;
1169
1170 int k_len = osmo_hexparse(k,
1171 g_cfg->oap.secret_k,
1172 sizeof(g_cfg->oap.secret_k));
1173 if (k_len != 16) {
1174 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
1175 k_len, VTY_NEWLINE);
1176 goto disable;
1177 }
1178
1179 g_cfg->oap.secret_k_present = 1;
1180 return CMD_SUCCESS;
1181
1182disable:
1183 if (g_cfg->oap.client_id > 0) {
1184 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
1185 VTY_NEWLINE);
1186 return CMD_WARNING;
1187 }
1188 return CMD_SUCCESS;
1189}
1190
1191DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1192 "gsup oap-opc OPC",
1193 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001194 "Set the OAP shared secret OPC for authentication on the GSUP protocol."
1195 " This setting only applies if auth-policy remote is used.\n"
1196 "OPC value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001197{
1198 const char *opc = argv[0];
1199
1200 g_cfg->oap.secret_opc_present = 0;
1201
1202 if ((!opc) || (strlen(opc) == 0))
1203 goto disable;
1204
1205 int opc_len = osmo_hexparse(opc,
1206 g_cfg->oap.secret_opc,
1207 sizeof(g_cfg->oap.secret_opc));
1208 if (opc_len != 16) {
1209 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1210 opc_len, VTY_NEWLINE);
1211 goto disable;
1212 }
1213
1214 g_cfg->oap.secret_opc_present = 1;
1215 return CMD_SUCCESS;
1216
1217disable:
1218 if (g_cfg->oap.client_id > 0) {
1219 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1220 VTY_NEWLINE);
1221 return CMD_WARNING;
1222 }
1223 return CMD_SUCCESS;
1224}
1225
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001226DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1227 "access-point-name NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001228 "Globally allow the given APN name for all subscribers.\n"
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001229 "Add this NAME to the list\n")
1230{
1231 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1232}
1233
1234DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1235 "no access-point-name NAME",
1236 NO_STR "Configure a global list of allowed APNs\n"
1237 "Remove entry with NAME\n")
1238{
1239 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1240 if (!apn_ctx)
1241 return CMD_SUCCESS;
1242
1243 sgsn_apn_ctx_free(apn_ctx);
1244 return CMD_SUCCESS;
1245}
1246
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001247DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1248 "cdr filename NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001249 "CDR\n"
1250 "Set the file name for the call-data-record file, logging the data usage of each subscriber.\n"
1251 "filename\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001252{
1253 talloc_free(g_cfg->cdr.filename);
1254 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1255 return CMD_SUCCESS;
1256}
1257
1258DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1259 "no cdr filename",
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001260 NO_STR "CDR\nDisable saving CDR to file\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001261{
1262 talloc_free(g_cfg->cdr.filename);
1263 g_cfg->cdr.filename = NULL;
1264 return CMD_SUCCESS;
1265}
1266
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001267DEFUN(cfg_cdr_trap, cfg_cdr_trap_cmd,
1268 "cdr trap",
1269 "CDR\nEnable sending CDR via TRAP CTRL messages\n")
1270{
1271 g_cfg->cdr.trap = true;
1272 return CMD_SUCCESS;
1273}
1274
1275DEFUN(cfg_no_cdr_trap, cfg_no_cdr_trap_cmd,
1276 "no cdr trap",
1277 NO_STR "CDR\nDisable sending CDR via TRAP CTRL messages\n")
1278{
1279 g_cfg->cdr.trap = false;
1280 return CMD_SUCCESS;
1281}
1282
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001283DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1284 "cdr interval <1-2147483647>",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001285 "CDR\n"
1286 "Set the interval for the call-data-record file\n"
1287 "interval in seconds\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001288{
1289 g_cfg->cdr.interval = atoi(argv[0]);
1290 return CMD_SUCCESS;
1291}
1292
Philippf1f34362016-08-26 17:00:21 +02001293#define COMPRESSION_STR "Configure compression\n"
1294DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1295 "no compression rfc1144",
1296 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1297{
1298 g_cfg->pcomp_rfc1144.active = 0;
1299 g_cfg->pcomp_rfc1144.passive = 0;
1300 return CMD_SUCCESS;
1301}
1302
1303DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1304 "compression rfc1144 active slots <1-256>",
1305 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001306 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001307 "Compression is actively proposed\n"
1308 "Number of compression state slots\n"
1309 "Number of compression state slots\n")
1310{
1311 g_cfg->pcomp_rfc1144.active = 1;
1312 g_cfg->pcomp_rfc1144.passive = 1;
1313 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1314 return CMD_SUCCESS;
1315}
1316
1317DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1318 "compression rfc1144 passive",
1319 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001320 "RFC1144 Header compression scheme\n"
Philippf1f34362016-08-26 17:00:21 +02001321 "Compression is available on request\n")
1322{
1323 g_cfg->pcomp_rfc1144.active = 0;
1324 g_cfg->pcomp_rfc1144.passive = 1;
1325 return CMD_SUCCESS;
1326}
1327
Philipp73f83d52016-09-02 13:38:01 +02001328DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
1329 "no compression v42bis",
1330 NO_STR COMPRESSION_STR "disable V.42bis data compression\n")
1331{
1332 g_cfg->dcomp_v42bis.active = 0;
1333 g_cfg->dcomp_v42bis.passive = 0;
1334 return CMD_SUCCESS;
1335}
1336
1337DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
1338 "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
1339 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001340 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001341 "Compression is actively proposed\n"
1342 "Direction in which the compression shall be active (p0)\n"
1343 "Compress ms->sgsn direction only\n"
1344 "Compress sgsn->ms direction only\n"
1345 "Both directions\n"
1346 "Number of codewords (p1)\n"
1347 "Number of codewords\n"
1348 "Maximum string length (p2)\n" "Maximum string length\n")
1349{
1350 g_cfg->dcomp_v42bis.active = 1;
1351 g_cfg->dcomp_v42bis.passive = 1;
1352
1353 switch (argv[0][0]) {
1354 case 'm':
1355 g_cfg->dcomp_v42bis.p0 = 1;
1356 break;
1357 case 's':
1358 g_cfg->dcomp_v42bis.p0 = 2;
1359 break;
1360 case 'b':
1361 g_cfg->dcomp_v42bis.p0 = 3;
1362 break;
1363 }
1364
1365 g_cfg->dcomp_v42bis.p1 = atoi(argv[1]);
1366 g_cfg->dcomp_v42bis.p2 = atoi(argv[2]);
1367 return CMD_SUCCESS;
1368}
1369
1370DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
1371 "compression v42bis passive",
1372 COMPRESSION_STR
Ruben Undheim55fcf112018-09-25 22:59:34 +02001373 "V.42bis data compression scheme\n"
Philipp73f83d52016-09-02 13:38:01 +02001374 "Compression is available on request\n")
1375{
1376 g_cfg->dcomp_v42bis.active = 0;
1377 g_cfg->dcomp_v42bis.passive = 1;
1378 return CMD_SUCCESS;
1379}
1380
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001381int sgsn_vty_init(struct sgsn_config *cfg)
Harald Welte288be162010-05-01 16:48:27 +02001382{
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001383 g_cfg = cfg;
1384
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001385 g_cfg->T_defs = sgsn_T_defs;
1386 osmo_tdefs_reset(g_cfg->T_defs);
1387
Harald Welted193cb32010-05-17 22:58:03 +02001388 install_element_ve(&show_sgsn_cmd);
1389 //install_element_ve(&show_mmctx_tlli_cmd);
1390 install_element_ve(&show_mmctx_imsi_cmd);
1391 install_element_ve(&show_mmctx_all_cmd);
1392 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001393 install_element_ve(&show_subscr_cache_cmd);
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001394 install_element_ve(&show_timer_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001395
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001396 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001397 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001398 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001399 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001400 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1401 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001402 install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001403
1404 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1405 install_node(&sgsn_node, config_write_sgsn);
Harald Weltee300d002010-06-02 12:41:34 +02001406 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001407 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1408 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1409 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +02001410 install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +02001411 install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001412 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001413 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Vadim Yanitskiy794f4462019-05-27 05:39:06 +07001414 install_element(SGSN_NODE, &cfg_authentication_cmd);
Max93408ae2016-06-28 14:10:16 +02001415 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Stefan Sperling88220092018-12-11 14:42:00 +01001416 install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001417 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1418 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001419 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1420 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1421 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001422 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1423 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001424 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1425 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001426 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1427 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001428 install_element(SGSN_NODE, &cfg_cdr_trap_cmd);
1429 install_element(SGSN_NODE, &cfg_no_cdr_trap_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001430 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001431 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001432 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001433
Pau Espin Pedrola299d652019-08-14 19:11:10 +02001434 install_element(SGSN_NODE, &cfg_sgsn_timer_cmd);
Harald Welte94508822015-08-15 19:08:21 +02001435
Philippf1f34362016-08-26 17:00:21 +02001436 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1437 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1438 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
Philipp73f83d52016-09-02 13:38:01 +02001439 install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd);
1440 install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
1441 install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001442
1443#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +02001444 ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001445#endif
Harald Welte288be162010-05-01 16:48:27 +02001446 return 0;
1447}
1448
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001449int sgsn_parse_config(const char *config_file)
Harald Welte288be162010-05-01 16:48:27 +02001450{
1451 int rc;
1452
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001453 /* make sure sgsn_vty_init() was called before this */
1454 OSMO_ASSERT(g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +01001455
Harald Weltedcccb182010-05-16 20:52:23 +02001456 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001457 if (rc < 0) {
1458 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1459 return rc;
1460 }
1461
Neels Hofmeyr27355c92017-02-24 06:28:31 +01001462 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE
1463 && !(g_cfg->gsup_server_addr.sin_addr.s_addr
1464 && g_cfg->gsup_server_port)) {
1465 fprintf(stderr, "Configuration error:"
1466 " 'auth-policy remote' requires both"
1467 " 'gsup remote-ip' and 'gsup remote-port'\n");
1468 return -EINVAL;
1469 }
1470
Harald Welte288be162010-05-01 16:48:27 +02001471 return 0;
1472}