blob: 3757c07376b786ec26fde035368db4a5b21fff44 [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>
Harald Welte53373bc2016-04-20 17:11:43 +020031#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
Harald Welte7e82b742017-08-12 13:43:54 +020032#include <osmocom/gsm/apn.h>
Harald Welte288be162010-05-01 16:48:27 +020033
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020034#include <osmocom/sgsn/debug.h>
35#include <osmocom/sgsn/sgsn.h>
Harald Welteea34a4e2012-06-16 14:59:56 +080036#include <osmocom/gprs/gprs_ns.h>
Alexander Couzensc503f0a2018-08-07 17:50:04 +020037#include <osmocom/sgsn/gprs_gmm.h>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020038#include <osmocom/sgsn/gprs_sgsn.h>
39#include <osmocom/sgsn/vty.h>
Harald Weltef4b2c4c2018-09-16 07:53:41 +020040#include <osmocom/gsupclient/gsup_client.h>
Harald Welte288be162010-05-01 16:48:27 +020041
Harald Welte4b037e42010-05-19 19:45:32 +020042#include <osmocom/vty/command.h>
43#include <osmocom/vty/vty.h>
Pablo Neira Ayuso6110a3f2011-03-28 19:35:00 +020044#include <osmocom/vty/misc.h>
Max93408ae2016-06-28 14:10:16 +020045#include <osmocom/crypt/gprs_cipher.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010046#include <osmocom/abis/ipa.h>
47
Alexander Couzensc503f0a2018-08-07 17:50:04 +020048#include <osmocom/gprs/gprs_bssgp.h>
49
Harald Welted193cb32010-05-17 22:58:03 +020050#include <pdp.h>
Maxbaabc682017-10-20 13:39:57 +020051#include <gtp.h>
Harald Welted193cb32010-05-17 22:58:03 +020052
Neels Hofmeyr2188a772016-05-20 21:59:55 +020053#include "../../bscconfig.h"
54
55#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +020056#include <osmocom/ranap/iu_client.h>
Neels Hofmeyr2188a772016-05-20 21:59:55 +020057#endif
58
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +010059extern void *tall_sgsn_ctx;
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020060
Harald Welte288be162010-05-01 16:48:27 +020061static struct sgsn_config *g_cfg = NULL;
62
Jacob Erlbeck106f5472014-11-04 10:08:37 +010063const struct value_string sgsn_auth_pol_strs[] = {
64 { SGSN_AUTH_POLICY_OPEN, "accept-all" },
65 { SGSN_AUTH_POLICY_CLOSED, "closed" },
66 { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" },
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +010067 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeck106f5472014-11-04 10:08:37 +010068 { 0, NULL }
69};
70
Harald Welte94508822015-08-15 19:08:21 +020071/* Section 11.2.2 / Table 11.3a GPRS Mobility management timers – MS side */
72#define GSM0408_T3312_SECS (10*60) /* periodic RAU interval, default 54min */
73
74/* Section 11.2.2 / Table 11.4 MM timers netwokr side */
75#define GSM0408_T3322_SECS 6 /* DETACH_REQ -> DETACH_ACC */
76#define GSM0408_T3350_SECS 6 /* waiting for ATT/RAU/TMSI COMPL */
77#define GSM0408_T3360_SECS 6 /* waiting for AUTH/CIPH RESP */
78#define GSM0408_T3370_SECS 6 /* waiting for ID RESP */
79
Alexander Couzens5ba6fb32017-01-31 18:04:27 +010080/* Section 11.2.2 / Table 11.4a MM timers network side */
Harald Welte94508822015-08-15 19:08:21 +020081#define GSM0408_T3313_SECS 30 /* waiting for paging response */
82#define GSM0408_T3314_SECS 44 /* force to STBY on expiry, Ready timer */
83#define GSM0408_T3316_SECS 44
84
85/* Section 11.3 / Table 11.2d Timers of Session Management - network side */
86#define GSM0408_T3385_SECS 8 /* wait for ACT PDP CTX REQ */
87#define GSM0408_T3386_SECS 8 /* wait for MODIFY PDP CTX ACK */
88#define GSM0408_T3395_SECS 8 /* wait for DEACT PDP CTX ACK */
89#define GSM0408_T3397_SECS 8 /* wait for DEACT AA PDP CTX ACK */
90
91#define DECLARE_TIMER(number, doc) \
92 DEFUN(cfg_sgsn_T##number, \
93 cfg_sgsn_T##number##_cmd, \
94 "timer t" #number " <0-65535>", \
95 "Configure GPRS Timers\n" \
Holger Hans Peter Freytherfe60cfb2015-11-02 12:55:07 +010096 doc "\nTimer Value in seconds\n") \
Harald Welte94508822015-08-15 19:08:21 +020097{ \
98 int value = atoi(argv[0]); \
99 \
100 if (value < 0 || value > 65535) { \
101 vty_out(vty, "Timer value %s out of range.%s", \
102 argv[0], VTY_NEWLINE); \
103 return CMD_WARNING; \
104 } \
105 \
106 g_cfg->timers.T##number = value; \
107 return CMD_SUCCESS; \
108}
109
110DECLARE_TIMER(3312, "Periodic RA Update timer (s)")
Neels Hofmeyr65482c92015-10-19 14:37:12 +0200111DECLARE_TIMER(3322, "Detach request -> accept timer (s)")
Harald Welte94508822015-08-15 19:08:21 +0200112DECLARE_TIMER(3350, "Waiting for ATT/RAU/TMSI_COMPL timer (s)")
113DECLARE_TIMER(3360, "Waiting for AUTH/CIPH response timer (s)")
114DECLARE_TIMER(3370, "Waiting for IDENTITY response timer (s)")
115
116DECLARE_TIMER(3313, "Waiting for paging response timer (s)")
117DECLARE_TIMER(3314, "Force to STANDBY on expiry timer (s)")
Holger Hans Peter Freytherfe60cfb2015-11-02 12:55:07 +0100118DECLARE_TIMER(3316, "AA-Ready timer (s)")
Harald Welte94508822015-08-15 19:08:21 +0200119
120DECLARE_TIMER(3385, "Wait for ACT PDP CTX REQ timer (s)")
121DECLARE_TIMER(3386, "Wait for MODIFY PDP CTX ACK timer (s)")
122DECLARE_TIMER(3395, "Wait for DEACT PDP CTX ACK timer (s)")
123DECLARE_TIMER(3397, "Wait for DEACT AA PDP CTX ACK timer (s)")
124
Holger Hans Peter Freythera2730302014-03-23 18:08:26 +0100125char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200126{
127 static char str[INET6_ADDRSTRLEN + 10];
128
129 if (!pdpa || len < 2)
130 return "none";
131
132 switch (pdpa[0] & 0x0f) {
133 case PDP_TYPE_ORG_IETF:
134 switch (pdpa[1]) {
135 case PDP_TYPE_N_IETF_IPv4:
136 if (len < 2 + 4)
137 break;
138 strcpy(str, "IPv4 ");
139 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
140 return str;
141 case PDP_TYPE_N_IETF_IPv6:
142 if (len < 2 + 8)
143 break;
144 strcpy(str, "IPv6 ");
145 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
146 return str;
147 default:
148 break;
149 }
150 break;
151 case PDP_TYPE_ORG_ETSI:
152 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
153 return "PPP";
154 break;
155 default:
156 break;
157 }
158
159 return "invalid";
160}
161
Harald Welte288be162010-05-01 16:48:27 +0200162static struct cmd_node sgsn_node = {
163 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200164 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200165 1,
166};
167
168static int config_write_sgsn(struct vty *vty)
169{
Harald Welte77289c22010-05-18 14:32:29 +0200170 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100171 struct imsi_acl_entry *acl;
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100172 struct apn_ctx *actx;
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800173 struct ares_addr_node *server;
Harald Welte288be162010-05-01 16:48:27 +0200174
175 vty_out(vty, "sgsn%s", VTY_NEWLINE);
176
Harald Weltee300d002010-06-02 12:41:34 +0200177 vty_out(vty, " gtp local-ip %s%s",
178 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
179
Harald Welted193cb32010-05-17 22:58:03 +0200180 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800181 if (gctx->id == UINT32_MAX)
182 continue;
183
Harald Welteff3bde82010-05-19 15:09:09 +0200184 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200185 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200186 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200187 gctx->gtp_version, VTY_NEWLINE);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200188 if (gctx->echo_interval != -1)
189 vty_out(vty, " ggsn %u echo-interval %"PRId32"%s",
190 gctx->id, gctx->echo_interval, VTY_NEWLINE);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200191 else
192 vty_out(vty, " ggsn %u no echo-interval%s",
193 gctx->id, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200194 }
195
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800196 if (sgsn->cfg.dynamic_lookup)
197 vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE);
198
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800199 for (server = sgsn->ares_servers; server; server = server->next)
200 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
201
Max93408ae2016-06-28 14:10:16 +0200202 if (g_cfg->cipher != GPRS_ALGO_GEA0)
203 vty_out(vty, " encryption %s%s",
204 get_value_string(gprs_cipher_names, g_cfg->cipher),
205 VTY_NEWLINE);
Stefan Sperling88220092018-12-11 14:42:00 +0100206 if (g_cfg->sgsn_ipa_name)
207 vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100208 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
209 vty_out(vty, " gsup remote-ip %s%s",
210 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
211 if (g_cfg->gsup_server_port)
212 vty_out(vty, " gsup remote-port %d%s",
213 g_cfg->gsup_server_port, VTY_NEWLINE);
Max176b62a2016-07-04 11:09:07 +0200214 vty_out(vty, " auth-policy %s%s",
215 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
216 VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200217
218 vty_out(vty, " gsup oap-id %d%s",
219 (int)g_cfg->oap.client_id, VTY_NEWLINE);
220 if (g_cfg->oap.secret_k_present != 0)
221 vty_out(vty, " gsup oap-k %s%s",
222 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
223 VTY_NEWLINE);
224 if (g_cfg->oap.secret_opc_present != 0)
225 vty_out(vty, " gsup oap-opc %s%s",
226 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
227 VTY_NEWLINE);
228
Harald Welte7f6da482013-03-19 11:00:13 +0100229 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
230 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
231
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100232 if (llist_empty(&sgsn_apn_ctxts))
233 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
234 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
235 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200236 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100237 actx->name, actx->imsi_prefix, actx->ggsn->id,
238 VTY_NEWLINE);
239 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200240 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100241 actx->ggsn->id, VTY_NEWLINE);
242 }
243
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200244 if (g_cfg->cdr.filename)
245 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
246 else
247 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +0100248 if (g_cfg->cdr.trap)
249 vty_out(vty, " cdr trap%s", VTY_NEWLINE);
250 else
251 vty_out(vty, " no cdr trap%s", VTY_NEWLINE);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200252 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
253
Harald Welte94508822015-08-15 19:08:21 +0200254 vty_out(vty, " timer t3312 %d%s", g_cfg->timers.T3312, VTY_NEWLINE);
255 vty_out(vty, " timer t3322 %d%s", g_cfg->timers.T3322, VTY_NEWLINE);
256 vty_out(vty, " timer t3350 %d%s", g_cfg->timers.T3350, VTY_NEWLINE);
257 vty_out(vty, " timer t3360 %d%s", g_cfg->timers.T3360, VTY_NEWLINE);
258 vty_out(vty, " timer t3370 %d%s", g_cfg->timers.T3370, VTY_NEWLINE);
259 vty_out(vty, " timer t3313 %d%s", g_cfg->timers.T3313, VTY_NEWLINE);
260 vty_out(vty, " timer t3314 %d%s", g_cfg->timers.T3314, VTY_NEWLINE);
261 vty_out(vty, " timer t3316 %d%s", g_cfg->timers.T3316, VTY_NEWLINE);
262 vty_out(vty, " timer t3385 %d%s", g_cfg->timers.T3385, VTY_NEWLINE);
263 vty_out(vty, " timer t3386 %d%s", g_cfg->timers.T3386, VTY_NEWLINE);
264 vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE);
265 vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE);
266
Philippf1f34362016-08-26 17:00:21 +0200267 if (g_cfg->pcomp_rfc1144.active) {
268 vty_out(vty, " compression rfc1144 active slots %d%s",
269 g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE);
270 } else if (g_cfg->pcomp_rfc1144.passive) {
271 vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE);
272 } else
273 vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE);
274
Philipp73f83d52016-09-02 13:38:01 +0200275 if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) {
276 vty_out(vty,
277 " compression v42bis active direction sgsn codewords %d strlen %d%s",
278 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
279 VTY_NEWLINE);
280 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) {
281 vty_out(vty,
282 " compression v42bis active direction ms codewords %d strlen %d%s",
283 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
284 VTY_NEWLINE);
285 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) {
286 vty_out(vty,
287 " compression v42bis active direction both codewords %d strlen %d%s",
288 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
289 VTY_NEWLINE);
290 } else if (g_cfg->dcomp_v42bis.passive) {
291 vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE);
292 } else
293 vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
294
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200295#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +0200296 ranap_iu_vty_config_write(vty, " ");
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200297#endif
298
Harald Welte288be162010-05-01 16:48:27 +0200299 return CMD_SUCCESS;
300}
301
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100302#define SGSN_STR "Configure the SGSN\n"
303#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200304
305DEFUN(cfg_sgsn, cfg_sgsn_cmd,
306 "sgsn",
307 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200308{
309 vty->node = SGSN_NODE;
310 return CMD_SUCCESS;
311}
312
Harald Weltee300d002010-06-02 12:41:34 +0200313DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
314 "gtp local-ip A.B.C.D",
315 "GTP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100316 "Set the IP address for the local GTP bind for the Gp interface (towards the GGSNs)."
317 " Note: in case you would like to run the GGSN on the same machine as the SGSN, you can not run"
318 " both on the same IP address, since both sides are specified to use the same GTP port numbers"
319 " (" OSMO_STRINGIFY_VAL(GTP1C_PORT) " and " OSMO_STRINGIFY_VAL(GTP1U_PORT) ")."
320 " For example, you could use 127.0.0.1 for the SGSN and 127.0.0.2 for the GGSN in such"
321 " situations.\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100322 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200323{
324 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
325
326 return CMD_SUCCESS;
327}
328
Harald Welted193cb32010-05-17 22:58:03 +0200329DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
330 "ggsn <0-255> remote-ip A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100331 GGSN_STR "GGSN Number\n"
332 "Configure this static GGSN to use the specified remote IP address.\n"
333 "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200334{
335 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200336 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200337
Harald Welted193cb32010-05-17 22:58:03 +0200338 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200339
Harald Welted193cb32010-05-17 22:58:03 +0200340 return CMD_SUCCESS;
341}
342
343#if 0
344DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
345 "ggsn <0-255> remote-port <0-65535>",
346 "")
347{
348 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200349 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200350 uint16_t port = atoi(argv[1]);
351
352}
353#endif
354
355DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
356 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100357 GGSN_STR "GGSN Number\n" "GTP Version\n"
358 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200359{
360 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200361 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200362
363 if (atoi(argv[1]))
364 ggc->gtp_version = 1;
365 else
366 ggc->gtp_version = 0;
367
368 return CMD_SUCCESS;
369}
370
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200371/* Seee 3GPP TS 29.060 section 7.2.1 */
372DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
373 "ggsn <0-255> echo-interval <1-36000>",
374 GGSN_STR "GGSN Number\n"
375 "Send an echo request to this static GGSN every interval.\n"
376 "Interval between echo requests in seconds.\n")
377{
378 uint32_t id = atoi(argv[0]);
379 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
380
381 ggc->echo_interval = atoi(argv[1]);
382
383 if (ggc->echo_interval < 60)
384 vty_out(vty, "%% 3GPP TS 29.060 section states inteval should " \
385 "not be lower than 60 seconds, use this value for " \
386 "testing purposes only!%s", VTY_NEWLINE);
387
Alexander Couzens176a4d22018-09-18 20:07:37 +0200388 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200389 return CMD_SUCCESS;
390}
391
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200392DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
393 "ggsn <0-255> no echo-interval",
394 GGSN_STR "GGSN Number\n"
395 NO_STR "Send an echo request to this static GGSN every interval.\n")
396{
397 uint32_t id = atoi(argv[0]);
398 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
399
400 ggc->echo_interval = -1;
Alexander Couzens176a4d22018-09-18 20:07:37 +0200401 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200402
403 return CMD_SUCCESS;
404}
405
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800406DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
407 "ggsn dynamic",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100408 GGSN_STR
409 "Enable dynamic resolving of GGSNs based on DNS resolving the APN name like in a GRX-style setup."
410 " Changing this setting requires a restart.\n")
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800411{
412 sgsn->cfg.dynamic_lookup = 1;
413 return CMD_SUCCESS;
414}
415
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800416DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
417 "grx-dns-add A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100418 "Use the specified IP address for DNS-resolving the AP names to GGSN IP addresses\n"
419 "IPv4 address\n")
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800420{
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +0100421 struct ares_addr_node *node = talloc_zero(tall_sgsn_ctx, struct ares_addr_node);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800422 node->family = AF_INET;
423 inet_aton(argv[0], &node->addr.addr4);
424
425 node->next = sgsn->ares_servers;
426 sgsn->ares_servers = node;
427 return CMD_SUCCESS;
428}
429
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100430#define APN_STR "Configure the information per APN\n"
431#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
432
433static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
434 const char *imsi_prefix, int ggsn_id)
435{
436 struct apn_ctx *actx;
437 struct sgsn_ggsn_ctx *ggsn;
438
439 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
440 if (ggsn == NULL) {
441 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
442 ggsn_id, VTY_NEWLINE);
443 return CMD_WARNING;
444 }
445
446 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
447 if (!actx) {
448 vty_out(vty, "%% unable to create APN context for %s/%s%s",
449 apn_str, imsi_prefix, VTY_NEWLINE);
450 return CMD_WARNING;
451 }
452
453 actx->ggsn = ggsn;
454
455 return CMD_SUCCESS;
456}
457
Harald Welted193cb32010-05-17 22:58:03 +0200458DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
459 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100460 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100461 "Select the GGSN to use for the given APN gateway prefix\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100462 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200463{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100464
465 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200466}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100467
468DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
469 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
470 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100471 "Select the GGSN to use for the given APN gateway prefix if and only if the IMSI matches the"
472 " given prefix.\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100473 "An IMSI prefix\n"
474 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
475 "The GGSN id")
476{
477
478 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
479}
Harald Welted193cb32010-05-17 22:58:03 +0200480
481const struct value_string gprs_mm_st_strs[] = {
482 { GMM_DEREGISTERED, "DEREGISTERED" },
483 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
484 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200485 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200486 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
487 { 0, NULL }
488};
489
Maxc005db72017-10-27 18:43:29 +0200490char *sgsn_gtp_ntoa(struct ul16_t *ul)
Harald Welte471ac7d2016-12-15 19:48:58 +0100491{
Max8492c202017-12-05 17:28:15 +0100492 struct in_addr ia;
493
494 if (gsna2in_addr(&ia, ul) != 0)
Harald Welte471ac7d2016-12-15 19:48:58 +0100495 return "UNKNOWN";
Max8492c202017-12-05 17:28:15 +0100496
497 return inet_ntoa(ia);
Harald Welte471ac7d2016-12-15 19:48:58 +0100498}
499
Harald Welted193cb32010-05-17 22:58:03 +0200500static void vty_dump_pdp(struct vty *vty, const char *pfx,
501 struct sgsn_pdp_ctx *pdp)
502{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200503 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welte471ac7d2016-12-15 19:48:58 +0100504 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s",
505 pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200506 if (pdp->lib) {
Max7933d962017-10-19 16:52:30 +0200507 char apnbuf[APN_MAXLEN + 1];
Harald Weltedfbd2c82017-08-13 00:56:45 +0200508 vty_out(vty, "%s APN: %s%s", pfx,
Max7933d962017-10-19 16:52:30 +0200509 osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200510 VTY_NEWLINE);
511 vty_out(vty, "%s PDP Address: %s%s", pfx,
512 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
513 VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100514 vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200515 sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
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->gsnlu), pdp->lib->teid_own, VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100518 vty_out(vty, "%s GTPv%d Remote Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200519 sgsn_gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200520 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200521 sgsn_gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200522 }
Harald Welte471ac7d2016-12-15 19:48:58 +0100523
Harald Welteefbdee92010-06-10 00:20:12 +0200524 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200525}
526
527static void vty_dump_mmctx(struct vty *vty, const char *pfx,
528 struct sgsn_mm_ctx *mm, int pdp)
529{
530 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
531 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200532 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Harald Weltef97ee042015-12-25 19:12:21 +0100533 pfx, mm->msisdn, mm->gb.tlli, mm->hlr, VTY_NEWLINE);
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100534 vty_out(vty, "%s MM State: %s, Routeing Area: %s, Cell ID: %u%s",
535 pfx, get_value_string(gprs_mm_st_strs, mm->gmm_state),
536 osmo_rai_name(&mm->ra), mm->gb.cell_id, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200537
Harald Welte8acd88f2010-05-18 10:57:45 +0200538 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
539
Harald Welted193cb32010-05-17 22:58:03 +0200540 if (pdp) {
541 struct sgsn_pdp_ctx *pdp;
542
543 llist_for_each_entry(pdp, &mm->pdp_list, list)
544 vty_dump_pdp(vty, " ", pdp);
545 }
546}
547
548DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
549 SHOW_STR "Display information about the SGSN")
550{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100551 if (sgsn->gsup_client) {
552 struct ipa_client_conn *link = sgsn->gsup_client->link;
553 vty_out(vty,
554 " Remote authorization: %sconnected to %s:%d via GSUP%s",
555 sgsn->gsup_client->is_connected ? "" : "not ",
556 link->addr, link->port,
557 VTY_NEWLINE);
558 }
Maxbaabc682017-10-20 13:39:57 +0200559 if (sgsn->gsn)
560 vty_out(vty, " GSN: signalling %s, user traffic %s%s",
561 inet_ntoa(sgsn->gsn->gsnc), inet_ntoa(sgsn->gsn->gsnu), VTY_NEWLINE);
562
Harald Welted193cb32010-05-17 22:58:03 +0200563 /* FIXME: statistics */
564 return CMD_SUCCESS;
565}
566
567#define MMCTX_STR "MM Context\n"
568#define INCLUDE_PDP_STR "Include PDP Context Information\n"
569
570#if 0
571DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
572 "show mm-context tlli HEX [pdp]",
573 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
574{
575 uint32_t tlli;
576 struct sgsn_mm_ctx *mm;
577
578 tlli = strtoul(argv[0], NULL, 16);
579 mm = sgsn_mm_ctx_by_tlli(tlli);
580 if (!mm) {
581 vty_out(vty, "No MM context for TLLI %08x%s",
582 tlli, VTY_NEWLINE);
583 return CMD_WARNING;
584 }
585 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
586 return CMD_SUCCESS;
587}
588#endif
589
590DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
591 "show mm-context imsi IMSI [pdp]",
592 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
593 INCLUDE_PDP_STR)
594{
595 struct sgsn_mm_ctx *mm;
596
597 mm = sgsn_mm_ctx_by_imsi(argv[0]);
598 if (!mm) {
599 vty_out(vty, "No MM context for IMSI %s%s",
600 argv[0], VTY_NEWLINE);
601 return CMD_WARNING;
602 }
603 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
604 return CMD_SUCCESS;
605}
606
607DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
608 "show mm-context all [pdp]",
609 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
610{
611 struct sgsn_mm_ctx *mm;
612
613 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
614 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
615
616 return CMD_SUCCESS;
617}
618
Harald Welted193cb32010-05-17 22:58:03 +0200619DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
620 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100621 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200622{
623 struct sgsn_pdp_ctx *pdp;
624
625 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
626 vty_dump_pdp(vty, "", pdp);
627
628 return CMD_SUCCESS;
629}
Harald Welte288be162010-05-01 16:48:27 +0200630
Harald Welte7f6da482013-03-19 11:00:13 +0100631
632DEFUN(imsi_acl, cfg_imsi_acl_cmd,
633 "imsi-acl (add|del) IMSI",
634 "Access Control List of foreign IMSIs\n"
635 "Add IMSI to ACL\n"
636 "Remove IMSI from ACL\n"
637 "IMSI of subscriber\n")
638{
Maxf4fa6952018-01-15 12:12:51 +0100639 char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS + 1] = { '0' };
Harald Welte7f6da482013-03-19 11:00:13 +0100640 const char *op = argv[0];
Philipp Maier6ee49d82017-02-28 16:53:07 +0100641 const char *imsi = imsi_sanitized;
Maxf4fa6952018-01-15 12:12:51 +0100642 size_t len = strnlen(argv[1], GSM23003_IMSI_MAX_DIGITS + 1);
Harald Welte7f6da482013-03-19 11:00:13 +0100643 int rc;
644
Philipp Maier6ee49d82017-02-28 16:53:07 +0100645 /* Sanitize IMSI */
Maxf4fa6952018-01-15 12:12:51 +0100646 if (len > GSM23003_IMSI_MAX_DIGITS) {
647 vty_out(vty, "%% IMSI (%s) too long (max %u digits) -- ignored!%s",
648 argv[1], GSM23003_IMSI_MAX_DIGITS, VTY_NEWLINE);
Philipp Maier6ee49d82017-02-28 16:53:07 +0100649 return CMD_WARNING;
650 }
Maxf4fa6952018-01-15 12:12:51 +0100651
652 osmo_strlcpy(imsi_sanitized + GSM23003_IMSI_MAX_DIGITS - len, argv[1],
653 sizeof(imsi_sanitized) - (GSM23003_IMSI_MAX_DIGITS - len));
Philipp Maier6ee49d82017-02-28 16:53:07 +0100654
Harald Welte7f6da482013-03-19 11:00:13 +0100655 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200656 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100657 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200658 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100659
660 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100661 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100662 return CMD_WARNING;
663 }
664
665 return CMD_SUCCESS;
666}
667
Max93408ae2016-06-28 14:10:16 +0200668DEFUN(cfg_encrypt, cfg_encrypt_cmd,
669 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
670 "Set encryption algorithm for SGSN\n"
671 "Use GEA0 (no encryption)\n"
672 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
673{
Max93408ae2016-06-28 14:10:16 +0200674 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
Max086067f2017-05-02 13:03:28 +0200675 if (c != GPRS_ALGO_GEA0) {
676 if (!gprs_cipher_supported(c)) {
677 vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
678 return CMD_WARNING;
679 }
680
681 if (!g_cfg->require_authentication) {
682 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
683 argv[0], VTY_NEWLINE);
684 return CMD_WARNING;
685 }
Max93408ae2016-06-28 14:10:16 +0200686 }
687
688 g_cfg->cipher = c;
689
690 return CMD_SUCCESS;
691}
692
Harald Welte3dfb5492013-03-19 11:48:54 +0100693DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100694 "auth-policy (accept-all|closed|acl-only|remote)",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100695 "Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
696 " permitted to register to the network.\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100697 "Accept all IMSIs (DANGEROUS)\n"
698 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100699 "Accept only subscribers in the ACL\n"
700 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100701{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100702 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100703 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100704 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100705 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100706 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100707
708 return CMD_SUCCESS;
709}
710
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100711/* Subscriber */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +0200712#include <osmocom/sgsn/gprs_subscriber.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100713
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100714static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100715{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100716#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100717 char expire_time[200];
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100718#endif
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100719 struct gsm_auth_tuple *at;
720 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100721 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100722
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100723 vty_out(vty, " Authorized: %d%s",
724 gsub->authorized, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100725 vty_out(vty, " LAC: %d/0x%x%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100726 gsub->lac, gsub->lac, VTY_NEWLINE);
727 vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
728 if (gsub->tmsi != GSM_RESERVED_TMSI)
729 vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100730 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100731 if (gsub->sgsn_data->msisdn_len > 0)
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400732 vty_out(vty, " MSISDN (BCD): %s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100733 osmo_hexdump(gsub->sgsn_data->msisdn,
734 gsub->sgsn_data->msisdn_len),
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400735 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100736
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100737 if (strlen(gsub->imei) > 0)
738 vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100739
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100740 for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100741 at_idx++) {
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100742 at = &gsub->sgsn_data->auth_triplets[at_idx];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100743 if (at->key_seq == GSM_KEY_SEQ_INVAL)
744 continue;
745
746 vty_out(vty, " A3A8 tuple (used %d times): ",
747 at->use_count);
Harald Welte89837d42016-05-06 23:28:11 +0200748 vty_out(vty, " CKSN: %d, ",
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100749 at->key_seq);
Harald Welte89837d42016-05-06 23:28:11 +0200750 if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
751 vty_out(vty, "RAND: %s, ",
752 osmo_hexdump(at->vec.rand,
753 sizeof(at->vec.rand)));
754 vty_out(vty, "SRES: %s, ",
755 osmo_hexdump(at->vec.sres,
756 sizeof(at->vec.sres)));
757 vty_out(vty, "Kc: %s%s",
758 osmo_hexdump(at->vec.kc,
759 sizeof(at->vec.kc)), VTY_NEWLINE);
760 }
761 if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
762 vty_out(vty, " AUTN: %s, ",
763 osmo_hexdump(at->vec.autn,
764 sizeof(at->vec.autn)));
765 vty_out(vty, "RES: %s, ",
766 osmo_hexdump(at->vec.res, at->vec.res_len));
767 vty_out(vty, "IK: %s, ",
768 osmo_hexdump(at->vec.ik, sizeof(at->vec.ik)));
769 vty_out(vty, "CK: %s, ",
770 osmo_hexdump(at->vec.ck, sizeof(at->vec.ck)));
771 }
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100772 }
773
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100774 llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400775 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s' QoS: %s%s",
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100776 pdp->context_id, pdp->pdp_type, pdp->apn_str,
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400777 osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len),
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100778 VTY_NEWLINE);
779 }
780
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100781#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100782 /* print the expiration time of a subscriber */
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100783 if (gsub->expire_lu) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100784 strftime(expire_time, sizeof(expire_time),
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100785 "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100786 expire_time[sizeof(expire_time) - 1] = '\0';
787 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
788 }
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100789#endif
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100790
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100791 if (gsub->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100792 vty_out(vty, " Flags: %s%s%s%s%s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100793 gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100794 "FIRST_CONTACT " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100795 gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100796 "CANCELLED " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100797 gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100798 "UPDATE_LOCATION_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100799 gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100800 "AUTH_INFO_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100801 gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100802 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100803 VTY_NEWLINE);
804
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100805 vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100806}
807
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200808#define RESET_SGSN_STATE_STR \
809 "Remove all known subscribers, MM contexts and flush BSSGP queues." \
810 " Useful only when running tests against the SGSN\n"
811
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200812DEFUN_HIDDEN(reset_sgsn_state,
813 reset_sgsn_state_cmd,
814 "reset sgsn state",
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200815 RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR)
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200816{
817 struct gprs_subscr *subscr, *tmp_subscr;
818 struct sgsn_mm_ctx *mm, *tmp_mm;
819
820 llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
821 {
822 gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
823 }
824 vty_out(vty, "Cancelled MM Ctx. %s", VTY_NEWLINE);
825
826 llist_for_each_entry_safe(subscr, tmp_subscr, gprs_subscribers, entry) {
827 gprs_subscr_get(subscr);
828 gprs_subscr_cancel(subscr);
829 gprs_subscr_put(subscr);
830 }
831 vty_out(vty, "Removed all gprs subscribers.%s", VTY_NEWLINE);
832
833 bssgp_flush_all_queues();
834 vty_out(vty, "Flushed all BSSGPs queues.%s", VTY_NEWLINE);
835
Alexander Couzens35c34942018-09-17 04:39:14 +0200836 gtp_clear_queues(sgsn->gsn);
Alexander Couzensa66f0f22018-09-18 16:09:18 +0200837 vty_out(vty, "Flushed rx & tx queus towards the GGSN.%s", VTY_NEWLINE);
Alexander Couzens35c34942018-09-17 04:39:14 +0200838
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200839 /* remove all queues to bssgp */
840 return CMD_SUCCESS;
841}
842
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100843DEFUN(show_subscr_cache,
844 show_subscr_cache_cmd,
845 "show subscriber cache",
846 SHOW_STR "Show information about subscribers\n"
847 "Display contents of subscriber cache\n")
848{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100849 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100850
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100851 llist_for_each_entry(subscr, gprs_subscribers, entry) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100852 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
853 subscr_dump_full_vty(vty, subscr, 0);
854 }
855
856 return CMD_SUCCESS;
857}
858
859#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
860#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
861 "Use the IMSI to select the subscriber\n" \
862 "The IMSI\n"
863
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100864#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
865
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100866DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
867 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
868 UPDATE_SUBSCR_HELP
869 UPDATE_SUBSCR_INSERT_HELP
870 "Update authentication triplet\n"
871 "Triplet index\n"
872 "Set SRES value\nSRES value (4 byte) in hex\n"
873 "Set RAND value\nRAND value (16 byte) in hex\n"
874 "Set Kc value\nKc value (8 byte) in hex\n")
875{
876 const char *imsi = argv[0];
877 const int cksn = atoi(argv[1]) - 1;
878 const char *sres_str = argv[2];
879 const char *rand_str = argv[3];
880 const char *kc_str = argv[4];
881 struct gsm_auth_tuple at = {0,};
882
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100883 struct gprs_subscr *subscr;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100884
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100885 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100886 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100887 vty_out(vty, "%% unable get subscriber record for %s%s",
888 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100889 return CMD_WARNING;
890 }
891
892 OSMO_ASSERT(subscr->sgsn_data);
893
Harald Welte121e9a42016-04-20 13:13:19 +0200894 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100895 vty_out(vty, "%% invalid SRES value '%s'%s",
896 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100897 goto failed;
898 }
Harald Welte121e9a42016-04-20 13:13:19 +0200899 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100900 vty_out(vty, "%% invalid RAND value '%s'%s",
901 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100902 goto failed;
903 }
Harald Welte121e9a42016-04-20 13:13:19 +0200904 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100905 vty_out(vty, "%% invalid Kc value '%s'%s",
906 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100907 goto failed;
908 }
909 at.key_seq = cksn;
910
911 subscr->sgsn_data->auth_triplets[cksn] = at;
912 subscr->sgsn_data->auth_triplets_updated = 1;
913
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100914 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100915
916 return CMD_SUCCESS;
917
918failed:
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100919 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100920 return CMD_SUCCESS;
921}
922
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100923DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100924 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100925 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100926 "Cancel (remove) subscriber record\n"
927 "The MS moved to another SGSN\n"
928 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100929{
930 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100931 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100932
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100933 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100934
935 subscr = gprs_subscr_get_by_imsi(imsi);
936 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100937 vty_out(vty, "%% no subscriber record for %s%s",
938 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100939 return CMD_WARNING;
940 }
941
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100942 if (strcmp(cancel_type, "update-procedure") == 0)
943 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
944 else
945 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
946
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100947 gprs_subscr_cancel(subscr);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100948 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100949
950 return CMD_SUCCESS;
951}
952
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100953DEFUN(update_subscr_create, update_subscr_create_cmd,
954 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100955 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100956 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100957{
958 const char *imsi = argv[0];
959
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100960 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100961
962 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100963 if (subscr) {
964 vty_out(vty, "%% subscriber record already exists for %s%s",
965 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100966 return CMD_WARNING;
967 }
968
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100969 subscr = gprs_subscr_get_or_create(imsi);
970 subscr->keep_in_ram = 1;
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100971 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100972
973 return CMD_SUCCESS;
974}
975
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100976DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
977 UPDATE_SUBSCR_STR "destroy",
978 UPDATE_SUBSCR_HELP
979 "Destroy a subscriber entry\n")
980{
981 const char *imsi = argv[0];
982
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100983 struct gprs_subscr *subscr;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100984
985 subscr = gprs_subscr_get_by_imsi(imsi);
986 if (!subscr) {
987 vty_out(vty, "%% subscriber record does not exist for %s%s",
988 imsi, VTY_NEWLINE);
989 return CMD_WARNING;
990 }
991
992 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100993 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100994 gprs_subscr_cancel(subscr);
995 if (subscr->use_count > 1)
996 vty_out(vty, "%% subscriber is still in use%s",
997 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100998 gprs_subscr_put(subscr);
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100999
1000 return CMD_SUCCESS;
1001}
1002
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001003#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
1004 "unknown-subscriber|roaming-not-allowed"
1005
1006#define UL_ERR_HELP \
1007 "Force error code SystemFailure\n" \
1008 "Force error code DataMissing\n" \
1009 "Force error code UnexpectedDataValue\n" \
1010 "Force error code UnknownSubscriber\n" \
1011 "Force error code RoamingNotAllowed\n"
1012
1013DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
1014 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
1015 UPDATE_SUBSCR_HELP
1016 "Complete the update location procedure\n"
1017 "The update location request succeeded\n"
1018 UL_ERR_HELP)
1019{
1020 const char *imsi = argv[0];
1021 const char *ret_code_str = argv[1];
1022
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001023 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001024
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001025 const struct value_string cause_mapping[] = {
1026 { GMM_CAUSE_NET_FAIL, "system-failure" },
1027 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
1028 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
1029 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
1030 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
1031 { 0, NULL }
1032 };
1033
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001034 subscr = gprs_subscr_get_by_imsi(imsi);
1035 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001036 vty_out(vty, "%% unable to get subscriber record for %s%s",
1037 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001038 return CMD_WARNING;
1039 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001040
1041 if (strcmp(ret_code_str, "ok") == 0) {
1042 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001043 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001044 } else {
1045 subscr->sgsn_data->error_cause =
1046 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001047 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001048 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001049
1050 gprs_subscr_update(subscr);
1051
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001052 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001053
1054 return CMD_SUCCESS;
1055}
1056
1057DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
1058 UPDATE_SUBSCR_STR "update-auth-info",
1059 UPDATE_SUBSCR_HELP
1060 "Complete the send authentication info procedure\n")
1061{
1062 const char *imsi = argv[0];
1063
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001064 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001065
1066 subscr = gprs_subscr_get_by_imsi(imsi);
1067 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001068 vty_out(vty, "%% unable to get subscriber record for %s%s",
1069 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001070 return CMD_WARNING;
1071 }
1072
1073 gprs_subscr_update_auth_info(subscr);
1074
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001075 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001076
1077 return CMD_SUCCESS;
1078}
1079
Stefan Sperling88220092018-12-11 14:42:00 +01001080DEFUN(cfg_gsup_ipa_name,
1081 cfg_gsup_ipa_name_cmd,
1082 "gsup ipa-name NAME",
1083 "GSUP Parameters\n"
1084 "Set the IPA name of this SGSN\n"
1085 "A unique name for this SGSN. For example: PLMN + redundancy server number: SGSN-901-70-0. "
1086 "This name is used for GSUP routing and must be set if more than one SGSN is connected to the network. "
1087 "The default is 'SGSN-00-00-00-00-00-00'.\n")
1088{
1089 if (vty->type != VTY_FILE) {
1090 vty_out(vty, "The IPA name cannot be changed at run-time; "
1091 "It can only be set in the configuraton file.%s", VTY_NEWLINE);
1092 return CMD_WARNING;
1093 }
1094
1095 g_cfg->sgsn_ipa_name = talloc_strdup(tall_vty_ctx, argv[0]);
1096 return CMD_SUCCESS;
1097}
1098
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001099DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
1100 "gsup remote-ip A.B.C.D",
1101 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001102 "Set the IP address of the remote GSUP server (e.g. OsmoHLR)."
1103 " This setting only applies if 'auth-policy remote' is used.\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001104 "IPv4 Address\n")
1105{
1106 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
1107
1108 return CMD_SUCCESS;
1109}
1110
1111DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
1112 "gsup remote-port <0-65535>",
1113 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001114 "Set the TCP port of the remote GSUP server, see also 'gsup remote-ip'\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001115 "Remote TCP port\n")
1116{
1117 g_cfg->gsup_server_port = atoi(argv[0]);
1118
1119 return CMD_SUCCESS;
1120}
1121
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001122DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
1123 "gsup oap-id <0-65535>",
1124 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001125 "Set the OAP client ID for authentication on the GSUP protocol."
1126 " This setting only applies if 'auth-policy remote' is used.\n"
1127 "OAP client ID (0 == disabled)\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001128{
1129 /* VTY ensures range */
1130 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
1131 return CMD_SUCCESS;
1132}
1133
1134DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
1135 "gsup oap-k K",
1136 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001137 "Set the OAP shared secret key K for authentication on the GSUP protocol."
1138 " This setting only applies if auth-policy remote is used.\n"
1139 "K value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001140{
1141 const char *k = argv[0];
1142
1143 g_cfg->oap.secret_k_present = 0;
1144
1145 if ((!k) || (strlen(k) == 0))
1146 goto disable;
1147
1148 int k_len = osmo_hexparse(k,
1149 g_cfg->oap.secret_k,
1150 sizeof(g_cfg->oap.secret_k));
1151 if (k_len != 16) {
1152 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
1153 k_len, VTY_NEWLINE);
1154 goto disable;
1155 }
1156
1157 g_cfg->oap.secret_k_present = 1;
1158 return CMD_SUCCESS;
1159
1160disable:
1161 if (g_cfg->oap.client_id > 0) {
1162 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
1163 VTY_NEWLINE);
1164 return CMD_WARNING;
1165 }
1166 return CMD_SUCCESS;
1167}
1168
1169DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1170 "gsup oap-opc OPC",
1171 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001172 "Set the OAP shared secret OPC for authentication on the GSUP protocol."
1173 " This setting only applies if auth-policy remote is used.\n"
1174 "OPC value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001175{
1176 const char *opc = argv[0];
1177
1178 g_cfg->oap.secret_opc_present = 0;
1179
1180 if ((!opc) || (strlen(opc) == 0))
1181 goto disable;
1182
1183 int opc_len = osmo_hexparse(opc,
1184 g_cfg->oap.secret_opc,
1185 sizeof(g_cfg->oap.secret_opc));
1186 if (opc_len != 16) {
1187 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1188 opc_len, VTY_NEWLINE);
1189 goto disable;
1190 }
1191
1192 g_cfg->oap.secret_opc_present = 1;
1193 return CMD_SUCCESS;
1194
1195disable:
1196 if (g_cfg->oap.client_id > 0) {
1197 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1198 VTY_NEWLINE);
1199 return CMD_WARNING;
1200 }
1201 return CMD_SUCCESS;
1202}
1203
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001204DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1205 "access-point-name NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001206 "Globally allow the given APN name for all subscribers.\n"
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001207 "Add this NAME to the list\n")
1208{
1209 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1210}
1211
1212DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1213 "no access-point-name NAME",
1214 NO_STR "Configure a global list of allowed APNs\n"
1215 "Remove entry with NAME\n")
1216{
1217 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1218 if (!apn_ctx)
1219 return CMD_SUCCESS;
1220
1221 sgsn_apn_ctx_free(apn_ctx);
1222 return CMD_SUCCESS;
1223}
1224
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001225DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1226 "cdr filename NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001227 "CDR\n"
1228 "Set the file name for the call-data-record file, logging the data usage of each subscriber.\n"
1229 "filename\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001230{
1231 talloc_free(g_cfg->cdr.filename);
1232 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1233 return CMD_SUCCESS;
1234}
1235
1236DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1237 "no cdr filename",
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001238 NO_STR "CDR\nDisable saving CDR to file\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001239{
1240 talloc_free(g_cfg->cdr.filename);
1241 g_cfg->cdr.filename = NULL;
1242 return CMD_SUCCESS;
1243}
1244
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001245DEFUN(cfg_cdr_trap, cfg_cdr_trap_cmd,
1246 "cdr trap",
1247 "CDR\nEnable sending CDR via TRAP CTRL messages\n")
1248{
1249 g_cfg->cdr.trap = true;
1250 return CMD_SUCCESS;
1251}
1252
1253DEFUN(cfg_no_cdr_trap, cfg_no_cdr_trap_cmd,
1254 "no cdr trap",
1255 NO_STR "CDR\nDisable sending CDR via TRAP CTRL messages\n")
1256{
1257 g_cfg->cdr.trap = false;
1258 return CMD_SUCCESS;
1259}
1260
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001261DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1262 "cdr interval <1-2147483647>",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001263 "CDR\n"
1264 "Set the interval for the call-data-record file\n"
1265 "interval in seconds\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001266{
1267 g_cfg->cdr.interval = atoi(argv[0]);
1268 return CMD_SUCCESS;
1269}
1270
Philippf1f34362016-08-26 17:00:21 +02001271#define COMPRESSION_STR "Configure compression\n"
1272DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1273 "no compression rfc1144",
1274 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1275{
1276 g_cfg->pcomp_rfc1144.active = 0;
1277 g_cfg->pcomp_rfc1144.passive = 0;
1278 return CMD_SUCCESS;
1279}
1280
1281DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1282 "compression rfc1144 active slots <1-256>",
1283 COMPRESSION_STR
1284 "RFC1144 Header compresion scheme\n"
1285 "Compression is actively proposed\n"
1286 "Number of compression state slots\n"
1287 "Number of compression state slots\n")
1288{
1289 g_cfg->pcomp_rfc1144.active = 1;
1290 g_cfg->pcomp_rfc1144.passive = 1;
1291 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1292 return CMD_SUCCESS;
1293}
1294
1295DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1296 "compression rfc1144 passive",
1297 COMPRESSION_STR
1298 "RFC1144 Header compresion scheme\n"
1299 "Compression is available on request\n")
1300{
1301 g_cfg->pcomp_rfc1144.active = 0;
1302 g_cfg->pcomp_rfc1144.passive = 1;
1303 return CMD_SUCCESS;
1304}
1305
Philipp73f83d52016-09-02 13:38:01 +02001306DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
1307 "no compression v42bis",
1308 NO_STR COMPRESSION_STR "disable V.42bis data compression\n")
1309{
1310 g_cfg->dcomp_v42bis.active = 0;
1311 g_cfg->dcomp_v42bis.passive = 0;
1312 return CMD_SUCCESS;
1313}
1314
1315DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
1316 "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
1317 COMPRESSION_STR
1318 "V.42bis data compresion scheme\n"
1319 "Compression is actively proposed\n"
1320 "Direction in which the compression shall be active (p0)\n"
1321 "Compress ms->sgsn direction only\n"
1322 "Compress sgsn->ms direction only\n"
1323 "Both directions\n"
1324 "Number of codewords (p1)\n"
1325 "Number of codewords\n"
1326 "Maximum string length (p2)\n" "Maximum string length\n")
1327{
1328 g_cfg->dcomp_v42bis.active = 1;
1329 g_cfg->dcomp_v42bis.passive = 1;
1330
1331 switch (argv[0][0]) {
1332 case 'm':
1333 g_cfg->dcomp_v42bis.p0 = 1;
1334 break;
1335 case 's':
1336 g_cfg->dcomp_v42bis.p0 = 2;
1337 break;
1338 case 'b':
1339 g_cfg->dcomp_v42bis.p0 = 3;
1340 break;
1341 }
1342
1343 g_cfg->dcomp_v42bis.p1 = atoi(argv[1]);
1344 g_cfg->dcomp_v42bis.p2 = atoi(argv[2]);
1345 return CMD_SUCCESS;
1346}
1347
1348DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
1349 "compression v42bis passive",
1350 COMPRESSION_STR
1351 "V.42bis data compresion scheme\n"
1352 "Compression is available on request\n")
1353{
1354 g_cfg->dcomp_v42bis.active = 0;
1355 g_cfg->dcomp_v42bis.passive = 1;
1356 return CMD_SUCCESS;
1357}
1358
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001359int sgsn_vty_init(struct sgsn_config *cfg)
Harald Welte288be162010-05-01 16:48:27 +02001360{
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001361 g_cfg = cfg;
1362
Harald Welted193cb32010-05-17 22:58:03 +02001363 install_element_ve(&show_sgsn_cmd);
1364 //install_element_ve(&show_mmctx_tlli_cmd);
1365 install_element_ve(&show_mmctx_imsi_cmd);
1366 install_element_ve(&show_mmctx_all_cmd);
1367 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001368 install_element_ve(&show_subscr_cache_cmd);
1369
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001370 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001371 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001372 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001373 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001374 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1375 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001376 install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001377
1378 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1379 install_node(&sgsn_node, config_write_sgsn);
Harald Weltee300d002010-06-02 12:41:34 +02001380 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001381 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1382 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1383 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +02001384 install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +02001385 install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001386 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001387 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Max93408ae2016-06-28 14:10:16 +02001388 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Stefan Sperling88220092018-12-11 14:42:00 +01001389 install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001390 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1391 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001392 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1393 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1394 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001395 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1396 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001397 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1398 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001399 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1400 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001401 install_element(SGSN_NODE, &cfg_cdr_trap_cmd);
1402 install_element(SGSN_NODE, &cfg_no_cdr_trap_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001403 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001404 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001405 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001406
Harald Welte94508822015-08-15 19:08:21 +02001407 install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd);
1408 install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd);
1409 install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd);
1410 install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd);
1411 install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd);
1412 install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd);
1413 install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd);
1414 install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd);
1415 install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd);
1416 install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd);
1417 install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd);
1418 install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd);
1419
Philippf1f34362016-08-26 17:00:21 +02001420 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1421 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1422 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
Philipp73f83d52016-09-02 13:38:01 +02001423 install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd);
1424 install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
1425 install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001426
1427#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +02001428 ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001429#endif
Harald Welte288be162010-05-01 16:48:27 +02001430 return 0;
1431}
1432
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001433int sgsn_parse_config(const char *config_file)
Harald Welte288be162010-05-01 16:48:27 +02001434{
1435 int rc;
1436
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001437 /* make sure sgsn_vty_init() was called before this */
1438 OSMO_ASSERT(g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +01001439
Harald Welte94508822015-08-15 19:08:21 +02001440 g_cfg->timers.T3312 = GSM0408_T3312_SECS;
1441 g_cfg->timers.T3322 = GSM0408_T3322_SECS;
1442 g_cfg->timers.T3350 = GSM0408_T3350_SECS;
1443 g_cfg->timers.T3360 = GSM0408_T3360_SECS;
1444 g_cfg->timers.T3370 = GSM0408_T3370_SECS;
1445 g_cfg->timers.T3313 = GSM0408_T3313_SECS;
1446 g_cfg->timers.T3314 = GSM0408_T3314_SECS;
1447 g_cfg->timers.T3316 = GSM0408_T3316_SECS;
1448 g_cfg->timers.T3385 = GSM0408_T3385_SECS;
1449 g_cfg->timers.T3386 = GSM0408_T3386_SECS;
1450 g_cfg->timers.T3395 = GSM0408_T3395_SECS;
1451 g_cfg->timers.T3397 = GSM0408_T3397_SECS;
1452
Harald Weltedcccb182010-05-16 20:52:23 +02001453 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001454 if (rc < 0) {
1455 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1456 return rc;
1457 }
1458
Neels Hofmeyr27355c92017-02-24 06:28:31 +01001459 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE
1460 && !(g_cfg->gsup_server_addr.sin_addr.s_addr
1461 && g_cfg->gsup_server_port)) {
1462 fprintf(stderr, "Configuration error:"
1463 " 'auth-policy remote' requires both"
1464 " 'gsup remote-ip' and 'gsup remote-port'\n");
1465 return -EINVAL;
1466 }
1467
Harald Welte288be162010-05-01 16:48:27 +02001468 return 0;
1469}