blob: 6389d92aca0f01c198d33ef7c3b66c77705b9a1f [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)
Pau Espin Pedrolba2e5002019-05-27 17:35:32 +0200384 vty_out(vty, "%% 3GPP TS 29.060 section 7.2.1 states interval should " \
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200385 "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{
Maxef38b4c2018-11-20 10:25:53 +0100639 char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS + 1];
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
Maxef38b4c2018-11-20 10:25:53 +0100645 memset(imsi_sanitized, '0', GSM23003_IMSI_MAX_DIGITS);
646 imsi_sanitized[GSM23003_IMSI_MAX_DIGITS] = '\0';
647
Philipp Maier6ee49d82017-02-28 16:53:07 +0100648 /* Sanitize IMSI */
Maxf4fa6952018-01-15 12:12:51 +0100649 if (len > GSM23003_IMSI_MAX_DIGITS) {
650 vty_out(vty, "%% IMSI (%s) too long (max %u digits) -- ignored!%s",
651 argv[1], GSM23003_IMSI_MAX_DIGITS, VTY_NEWLINE);
Philipp Maier6ee49d82017-02-28 16:53:07 +0100652 return CMD_WARNING;
653 }
Maxf4fa6952018-01-15 12:12:51 +0100654
655 osmo_strlcpy(imsi_sanitized + GSM23003_IMSI_MAX_DIGITS - len, argv[1],
656 sizeof(imsi_sanitized) - (GSM23003_IMSI_MAX_DIGITS - len));
Philipp Maier6ee49d82017-02-28 16:53:07 +0100657
Harald Welte7f6da482013-03-19 11:00:13 +0100658 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200659 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100660 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200661 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100662
663 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100664 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100665 return CMD_WARNING;
666 }
667
668 return CMD_SUCCESS;
669}
670
Max93408ae2016-06-28 14:10:16 +0200671DEFUN(cfg_encrypt, cfg_encrypt_cmd,
672 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
673 "Set encryption algorithm for SGSN\n"
674 "Use GEA0 (no encryption)\n"
675 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
676{
Max93408ae2016-06-28 14:10:16 +0200677 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
Max086067f2017-05-02 13:03:28 +0200678 if (c != GPRS_ALGO_GEA0) {
679 if (!gprs_cipher_supported(c)) {
680 vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
681 return CMD_WARNING;
682 }
683
684 if (!g_cfg->require_authentication) {
685 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
686 argv[0], VTY_NEWLINE);
687 return CMD_WARNING;
688 }
Max93408ae2016-06-28 14:10:16 +0200689 }
690
691 g_cfg->cipher = c;
692
693 return CMD_SUCCESS;
694}
695
Harald Welte3dfb5492013-03-19 11:48:54 +0100696DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100697 "auth-policy (accept-all|closed|acl-only|remote)",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100698 "Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
699 " permitted to register to the network.\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100700 "Accept all IMSIs (DANGEROUS)\n"
701 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100702 "Accept only subscribers in the ACL\n"
703 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100704{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100705 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100706 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100707 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100708 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100709 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100710
711 return CMD_SUCCESS;
712}
713
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100714/* Subscriber */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +0200715#include <osmocom/sgsn/gprs_subscriber.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100716
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100717static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100718{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100719#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100720 char expire_time[200];
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100721#endif
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100722 struct gsm_auth_tuple *at;
723 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100724 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100725
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100726 vty_out(vty, " Authorized: %d%s",
727 gsub->authorized, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100728 vty_out(vty, " LAC: %d/0x%x%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100729 gsub->lac, gsub->lac, VTY_NEWLINE);
730 vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
731 if (gsub->tmsi != GSM_RESERVED_TMSI)
732 vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100733 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100734 if (gsub->sgsn_data->msisdn_len > 0)
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400735 vty_out(vty, " MSISDN (BCD): %s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100736 osmo_hexdump(gsub->sgsn_data->msisdn,
737 gsub->sgsn_data->msisdn_len),
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400738 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100739
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100740 if (strlen(gsub->imei) > 0)
741 vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100742
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100743 for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100744 at_idx++) {
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100745 at = &gsub->sgsn_data->auth_triplets[at_idx];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100746 if (at->key_seq == GSM_KEY_SEQ_INVAL)
747 continue;
748
749 vty_out(vty, " A3A8 tuple (used %d times): ",
750 at->use_count);
Harald Welte89837d42016-05-06 23:28:11 +0200751 vty_out(vty, " CKSN: %d, ",
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100752 at->key_seq);
Harald Welte89837d42016-05-06 23:28:11 +0200753 if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
754 vty_out(vty, "RAND: %s, ",
Max34604c22019-02-13 14:11:29 +0100755 osmo_hexdump_nospc(at->vec.rand,
Harald Welte89837d42016-05-06 23:28:11 +0200756 sizeof(at->vec.rand)));
757 vty_out(vty, "SRES: %s, ",
Max34604c22019-02-13 14:11:29 +0100758 osmo_hexdump_nospc(at->vec.sres,
Harald Welte89837d42016-05-06 23:28:11 +0200759 sizeof(at->vec.sres)));
760 vty_out(vty, "Kc: %s%s",
Max34604c22019-02-13 14:11:29 +0100761 osmo_hexdump_nospc(at->vec.kc,
Harald Welte89837d42016-05-06 23:28:11 +0200762 sizeof(at->vec.kc)), VTY_NEWLINE);
763 }
764 if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
765 vty_out(vty, " AUTN: %s, ",
766 osmo_hexdump(at->vec.autn,
767 sizeof(at->vec.autn)));
768 vty_out(vty, "RES: %s, ",
Max34604c22019-02-13 14:11:29 +0100769 osmo_hexdump_nospc(at->vec.res, at->vec.res_len));
Harald Welte89837d42016-05-06 23:28:11 +0200770 vty_out(vty, "IK: %s, ",
Max34604c22019-02-13 14:11:29 +0100771 osmo_hexdump_nospc(at->vec.ik, sizeof(at->vec.ik)));
Harald Welte89837d42016-05-06 23:28:11 +0200772 vty_out(vty, "CK: %s, ",
Max34604c22019-02-13 14:11:29 +0100773 osmo_hexdump_nospc(at->vec.ck, sizeof(at->vec.ck)));
Harald Welte89837d42016-05-06 23:28:11 +0200774 }
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100775 }
776
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100777 llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
Max34604c22019-02-13 14:11:29 +0100778 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'",
779 pdp->context_id, pdp->pdp_type, pdp->apn_str);
780
781 if (pdp->qos_subscribed_len)
782 vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len));
783
784 vty_out(vty, "%s", VTY_NEWLINE);
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100785 }
786
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100787#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100788 /* print the expiration time of a subscriber */
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100789 if (gsub->expire_lu) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100790 strftime(expire_time, sizeof(expire_time),
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100791 "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100792 expire_time[sizeof(expire_time) - 1] = '\0';
793 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
794 }
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100795#endif
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100796
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100797 if (gsub->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100798 vty_out(vty, " Flags: %s%s%s%s%s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100799 gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100800 "FIRST_CONTACT " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100801 gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100802 "CANCELLED " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100803 gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100804 "UPDATE_LOCATION_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100805 gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100806 "AUTH_INFO_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100807 gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100808 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100809 VTY_NEWLINE);
810
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100811 vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100812}
813
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200814#define RESET_SGSN_STATE_STR \
815 "Remove all known subscribers, MM contexts and flush BSSGP queues." \
816 " Useful only when running tests against the SGSN\n"
817
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200818DEFUN_HIDDEN(reset_sgsn_state,
819 reset_sgsn_state_cmd,
820 "reset sgsn state",
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200821 RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR)
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200822{
823 struct gprs_subscr *subscr, *tmp_subscr;
824 struct sgsn_mm_ctx *mm, *tmp_mm;
825
826 llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
827 {
828 gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
829 }
830 vty_out(vty, "Cancelled MM Ctx. %s", VTY_NEWLINE);
831
832 llist_for_each_entry_safe(subscr, tmp_subscr, gprs_subscribers, entry) {
833 gprs_subscr_get(subscr);
834 gprs_subscr_cancel(subscr);
835 gprs_subscr_put(subscr);
836 }
837 vty_out(vty, "Removed all gprs subscribers.%s", VTY_NEWLINE);
838
839 bssgp_flush_all_queues();
840 vty_out(vty, "Flushed all BSSGPs queues.%s", VTY_NEWLINE);
841
Alexander Couzens35c34942018-09-17 04:39:14 +0200842 gtp_clear_queues(sgsn->gsn);
Alexander Couzensa66f0f22018-09-18 16:09:18 +0200843 vty_out(vty, "Flushed rx & tx queus towards the GGSN.%s", VTY_NEWLINE);
Alexander Couzens35c34942018-09-17 04:39:14 +0200844
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200845 /* remove all queues to bssgp */
846 return CMD_SUCCESS;
847}
848
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100849DEFUN(show_subscr_cache,
850 show_subscr_cache_cmd,
851 "show subscriber cache",
852 SHOW_STR "Show information about subscribers\n"
853 "Display contents of subscriber cache\n")
854{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100855 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100856
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100857 llist_for_each_entry(subscr, gprs_subscribers, entry) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100858 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
859 subscr_dump_full_vty(vty, subscr, 0);
860 }
861
862 return CMD_SUCCESS;
863}
864
865#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
866#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
867 "Use the IMSI to select the subscriber\n" \
868 "The IMSI\n"
869
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100870#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
871
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100872DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
873 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
874 UPDATE_SUBSCR_HELP
875 UPDATE_SUBSCR_INSERT_HELP
876 "Update authentication triplet\n"
877 "Triplet index\n"
878 "Set SRES value\nSRES value (4 byte) in hex\n"
879 "Set RAND value\nRAND value (16 byte) in hex\n"
880 "Set Kc value\nKc value (8 byte) in hex\n")
881{
882 const char *imsi = argv[0];
883 const int cksn = atoi(argv[1]) - 1;
884 const char *sres_str = argv[2];
885 const char *rand_str = argv[3];
886 const char *kc_str = argv[4];
887 struct gsm_auth_tuple at = {0,};
888
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100889 struct gprs_subscr *subscr;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100890
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100891 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100892 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100893 vty_out(vty, "%% unable get subscriber record for %s%s",
894 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100895 return CMD_WARNING;
896 }
897
898 OSMO_ASSERT(subscr->sgsn_data);
899
Harald Welte121e9a42016-04-20 13:13:19 +0200900 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100901 vty_out(vty, "%% invalid SRES value '%s'%s",
902 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100903 goto failed;
904 }
Harald Welte121e9a42016-04-20 13:13:19 +0200905 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100906 vty_out(vty, "%% invalid RAND value '%s'%s",
907 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100908 goto failed;
909 }
Harald Welte121e9a42016-04-20 13:13:19 +0200910 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100911 vty_out(vty, "%% invalid Kc value '%s'%s",
912 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100913 goto failed;
914 }
915 at.key_seq = cksn;
916
917 subscr->sgsn_data->auth_triplets[cksn] = at;
918 subscr->sgsn_data->auth_triplets_updated = 1;
919
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100920 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100921
922 return CMD_SUCCESS;
923
924failed:
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100925 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100926 return CMD_SUCCESS;
927}
928
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100929DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100930 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100931 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100932 "Cancel (remove) subscriber record\n"
933 "The MS moved to another SGSN\n"
934 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100935{
936 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100937 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100938
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100939 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100940
941 subscr = gprs_subscr_get_by_imsi(imsi);
942 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100943 vty_out(vty, "%% no subscriber record for %s%s",
944 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100945 return CMD_WARNING;
946 }
947
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100948 if (strcmp(cancel_type, "update-procedure") == 0)
949 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
950 else
951 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
952
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100953 gprs_subscr_cancel(subscr);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100954 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100955
956 return CMD_SUCCESS;
957}
958
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100959DEFUN(update_subscr_create, update_subscr_create_cmd,
960 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100961 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100962 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100963{
964 const char *imsi = argv[0];
965
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100966 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100967
968 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100969 if (subscr) {
970 vty_out(vty, "%% subscriber record already exists for %s%s",
971 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100972 return CMD_WARNING;
973 }
974
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100975 subscr = gprs_subscr_get_or_create(imsi);
976 subscr->keep_in_ram = 1;
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100977 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100978
979 return CMD_SUCCESS;
980}
981
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100982DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
983 UPDATE_SUBSCR_STR "destroy",
984 UPDATE_SUBSCR_HELP
985 "Destroy a subscriber entry\n")
986{
987 const char *imsi = argv[0];
988
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100989 struct gprs_subscr *subscr;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100990
991 subscr = gprs_subscr_get_by_imsi(imsi);
992 if (!subscr) {
993 vty_out(vty, "%% subscriber record does not exist for %s%s",
994 imsi, VTY_NEWLINE);
995 return CMD_WARNING;
996 }
997
998 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100999 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001000 gprs_subscr_cancel(subscr);
1001 if (subscr->use_count > 1)
1002 vty_out(vty, "%% subscriber is still in use%s",
1003 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001004 gprs_subscr_put(subscr);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001005
1006 return CMD_SUCCESS;
1007}
1008
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001009#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
1010 "unknown-subscriber|roaming-not-allowed"
1011
1012#define UL_ERR_HELP \
1013 "Force error code SystemFailure\n" \
1014 "Force error code DataMissing\n" \
1015 "Force error code UnexpectedDataValue\n" \
1016 "Force error code UnknownSubscriber\n" \
1017 "Force error code RoamingNotAllowed\n"
1018
1019DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
1020 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
1021 UPDATE_SUBSCR_HELP
1022 "Complete the update location procedure\n"
1023 "The update location request succeeded\n"
1024 UL_ERR_HELP)
1025{
1026 const char *imsi = argv[0];
1027 const char *ret_code_str = argv[1];
1028
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001029 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001030
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001031 const struct value_string cause_mapping[] = {
1032 { GMM_CAUSE_NET_FAIL, "system-failure" },
1033 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
1034 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
1035 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
1036 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
1037 { 0, NULL }
1038 };
1039
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001040 subscr = gprs_subscr_get_by_imsi(imsi);
1041 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001042 vty_out(vty, "%% unable to get subscriber record for %s%s",
1043 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001044 return CMD_WARNING;
1045 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001046
1047 if (strcmp(ret_code_str, "ok") == 0) {
1048 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001049 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001050 } else {
1051 subscr->sgsn_data->error_cause =
1052 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001053 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001054 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001055
1056 gprs_subscr_update(subscr);
1057
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001058 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001059
1060 return CMD_SUCCESS;
1061}
1062
1063DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
1064 UPDATE_SUBSCR_STR "update-auth-info",
1065 UPDATE_SUBSCR_HELP
1066 "Complete the send authentication info procedure\n")
1067{
1068 const char *imsi = argv[0];
1069
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001070 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001071
1072 subscr = gprs_subscr_get_by_imsi(imsi);
1073 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001074 vty_out(vty, "%% unable to get subscriber record for %s%s",
1075 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001076 return CMD_WARNING;
1077 }
1078
1079 gprs_subscr_update_auth_info(subscr);
1080
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001081 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001082
1083 return CMD_SUCCESS;
1084}
1085
Stefan Sperling88220092018-12-11 14:42:00 +01001086DEFUN(cfg_gsup_ipa_name,
1087 cfg_gsup_ipa_name_cmd,
1088 "gsup ipa-name NAME",
1089 "GSUP Parameters\n"
1090 "Set the IPA name of this SGSN\n"
1091 "A unique name for this SGSN. For example: PLMN + redundancy server number: SGSN-901-70-0. "
1092 "This name is used for GSUP routing and must be set if more than one SGSN is connected to the network. "
1093 "The default is 'SGSN-00-00-00-00-00-00'.\n")
1094{
1095 if (vty->type != VTY_FILE) {
1096 vty_out(vty, "The IPA name cannot be changed at run-time; "
1097 "It can only be set in the configuraton file.%s", VTY_NEWLINE);
1098 return CMD_WARNING;
1099 }
1100
1101 g_cfg->sgsn_ipa_name = talloc_strdup(tall_vty_ctx, argv[0]);
1102 return CMD_SUCCESS;
1103}
1104
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001105DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
1106 "gsup remote-ip A.B.C.D",
1107 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001108 "Set the IP address of the remote GSUP server (e.g. OsmoHLR)."
1109 " This setting only applies if 'auth-policy remote' is used.\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001110 "IPv4 Address\n")
1111{
1112 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
1113
1114 return CMD_SUCCESS;
1115}
1116
1117DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
1118 "gsup remote-port <0-65535>",
1119 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001120 "Set the TCP port of the remote GSUP server, see also 'gsup remote-ip'\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001121 "Remote TCP port\n")
1122{
1123 g_cfg->gsup_server_port = atoi(argv[0]);
1124
1125 return CMD_SUCCESS;
1126}
1127
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001128DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
1129 "gsup oap-id <0-65535>",
1130 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001131 "Set the OAP client ID for authentication on the GSUP protocol."
1132 " This setting only applies if 'auth-policy remote' is used.\n"
1133 "OAP client ID (0 == disabled)\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001134{
1135 /* VTY ensures range */
1136 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
1137 return CMD_SUCCESS;
1138}
1139
1140DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
1141 "gsup oap-k K",
1142 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001143 "Set the OAP shared secret key K for authentication on the GSUP protocol."
1144 " This setting only applies if auth-policy remote is used.\n"
1145 "K value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001146{
1147 const char *k = argv[0];
1148
1149 g_cfg->oap.secret_k_present = 0;
1150
1151 if ((!k) || (strlen(k) == 0))
1152 goto disable;
1153
1154 int k_len = osmo_hexparse(k,
1155 g_cfg->oap.secret_k,
1156 sizeof(g_cfg->oap.secret_k));
1157 if (k_len != 16) {
1158 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
1159 k_len, VTY_NEWLINE);
1160 goto disable;
1161 }
1162
1163 g_cfg->oap.secret_k_present = 1;
1164 return CMD_SUCCESS;
1165
1166disable:
1167 if (g_cfg->oap.client_id > 0) {
1168 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
1169 VTY_NEWLINE);
1170 return CMD_WARNING;
1171 }
1172 return CMD_SUCCESS;
1173}
1174
1175DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1176 "gsup oap-opc OPC",
1177 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001178 "Set the OAP shared secret OPC for authentication on the GSUP protocol."
1179 " This setting only applies if auth-policy remote is used.\n"
1180 "OPC value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001181{
1182 const char *opc = argv[0];
1183
1184 g_cfg->oap.secret_opc_present = 0;
1185
1186 if ((!opc) || (strlen(opc) == 0))
1187 goto disable;
1188
1189 int opc_len = osmo_hexparse(opc,
1190 g_cfg->oap.secret_opc,
1191 sizeof(g_cfg->oap.secret_opc));
1192 if (opc_len != 16) {
1193 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1194 opc_len, VTY_NEWLINE);
1195 goto disable;
1196 }
1197
1198 g_cfg->oap.secret_opc_present = 1;
1199 return CMD_SUCCESS;
1200
1201disable:
1202 if (g_cfg->oap.client_id > 0) {
1203 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1204 VTY_NEWLINE);
1205 return CMD_WARNING;
1206 }
1207 return CMD_SUCCESS;
1208}
1209
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001210DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1211 "access-point-name NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001212 "Globally allow the given APN name for all subscribers.\n"
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001213 "Add this NAME to the list\n")
1214{
1215 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1216}
1217
1218DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1219 "no access-point-name NAME",
1220 NO_STR "Configure a global list of allowed APNs\n"
1221 "Remove entry with NAME\n")
1222{
1223 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1224 if (!apn_ctx)
1225 return CMD_SUCCESS;
1226
1227 sgsn_apn_ctx_free(apn_ctx);
1228 return CMD_SUCCESS;
1229}
1230
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001231DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1232 "cdr filename NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001233 "CDR\n"
1234 "Set the file name for the call-data-record file, logging the data usage of each subscriber.\n"
1235 "filename\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001236{
1237 talloc_free(g_cfg->cdr.filename);
1238 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1239 return CMD_SUCCESS;
1240}
1241
1242DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1243 "no cdr filename",
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001244 NO_STR "CDR\nDisable saving CDR to file\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001245{
1246 talloc_free(g_cfg->cdr.filename);
1247 g_cfg->cdr.filename = NULL;
1248 return CMD_SUCCESS;
1249}
1250
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001251DEFUN(cfg_cdr_trap, cfg_cdr_trap_cmd,
1252 "cdr trap",
1253 "CDR\nEnable sending CDR via TRAP CTRL messages\n")
1254{
1255 g_cfg->cdr.trap = true;
1256 return CMD_SUCCESS;
1257}
1258
1259DEFUN(cfg_no_cdr_trap, cfg_no_cdr_trap_cmd,
1260 "no cdr trap",
1261 NO_STR "CDR\nDisable sending CDR via TRAP CTRL messages\n")
1262{
1263 g_cfg->cdr.trap = false;
1264 return CMD_SUCCESS;
1265}
1266
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001267DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1268 "cdr interval <1-2147483647>",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001269 "CDR\n"
1270 "Set the interval for the call-data-record file\n"
1271 "interval in seconds\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001272{
1273 g_cfg->cdr.interval = atoi(argv[0]);
1274 return CMD_SUCCESS;
1275}
1276
Philippf1f34362016-08-26 17:00:21 +02001277#define COMPRESSION_STR "Configure compression\n"
1278DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1279 "no compression rfc1144",
1280 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1281{
1282 g_cfg->pcomp_rfc1144.active = 0;
1283 g_cfg->pcomp_rfc1144.passive = 0;
1284 return CMD_SUCCESS;
1285}
1286
1287DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1288 "compression rfc1144 active slots <1-256>",
1289 COMPRESSION_STR
1290 "RFC1144 Header compresion scheme\n"
1291 "Compression is actively proposed\n"
1292 "Number of compression state slots\n"
1293 "Number of compression state slots\n")
1294{
1295 g_cfg->pcomp_rfc1144.active = 1;
1296 g_cfg->pcomp_rfc1144.passive = 1;
1297 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1298 return CMD_SUCCESS;
1299}
1300
1301DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1302 "compression rfc1144 passive",
1303 COMPRESSION_STR
1304 "RFC1144 Header compresion scheme\n"
1305 "Compression is available on request\n")
1306{
1307 g_cfg->pcomp_rfc1144.active = 0;
1308 g_cfg->pcomp_rfc1144.passive = 1;
1309 return CMD_SUCCESS;
1310}
1311
Philipp73f83d52016-09-02 13:38:01 +02001312DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
1313 "no compression v42bis",
1314 NO_STR COMPRESSION_STR "disable V.42bis data compression\n")
1315{
1316 g_cfg->dcomp_v42bis.active = 0;
1317 g_cfg->dcomp_v42bis.passive = 0;
1318 return CMD_SUCCESS;
1319}
1320
1321DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
1322 "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
1323 COMPRESSION_STR
1324 "V.42bis data compresion scheme\n"
1325 "Compression is actively proposed\n"
1326 "Direction in which the compression shall be active (p0)\n"
1327 "Compress ms->sgsn direction only\n"
1328 "Compress sgsn->ms direction only\n"
1329 "Both directions\n"
1330 "Number of codewords (p1)\n"
1331 "Number of codewords\n"
1332 "Maximum string length (p2)\n" "Maximum string length\n")
1333{
1334 g_cfg->dcomp_v42bis.active = 1;
1335 g_cfg->dcomp_v42bis.passive = 1;
1336
1337 switch (argv[0][0]) {
1338 case 'm':
1339 g_cfg->dcomp_v42bis.p0 = 1;
1340 break;
1341 case 's':
1342 g_cfg->dcomp_v42bis.p0 = 2;
1343 break;
1344 case 'b':
1345 g_cfg->dcomp_v42bis.p0 = 3;
1346 break;
1347 }
1348
1349 g_cfg->dcomp_v42bis.p1 = atoi(argv[1]);
1350 g_cfg->dcomp_v42bis.p2 = atoi(argv[2]);
1351 return CMD_SUCCESS;
1352}
1353
1354DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
1355 "compression v42bis passive",
1356 COMPRESSION_STR
1357 "V.42bis data compresion scheme\n"
1358 "Compression is available on request\n")
1359{
1360 g_cfg->dcomp_v42bis.active = 0;
1361 g_cfg->dcomp_v42bis.passive = 1;
1362 return CMD_SUCCESS;
1363}
1364
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001365int sgsn_vty_init(struct sgsn_config *cfg)
Harald Welte288be162010-05-01 16:48:27 +02001366{
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001367 g_cfg = cfg;
1368
Harald Welted193cb32010-05-17 22:58:03 +02001369 install_element_ve(&show_sgsn_cmd);
1370 //install_element_ve(&show_mmctx_tlli_cmd);
1371 install_element_ve(&show_mmctx_imsi_cmd);
1372 install_element_ve(&show_mmctx_all_cmd);
1373 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001374 install_element_ve(&show_subscr_cache_cmd);
1375
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001376 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001377 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001378 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001379 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001380 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1381 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001382 install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001383
1384 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1385 install_node(&sgsn_node, config_write_sgsn);
Harald Weltee300d002010-06-02 12:41:34 +02001386 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001387 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1388 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1389 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +02001390 install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +02001391 install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001392 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001393 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Max93408ae2016-06-28 14:10:16 +02001394 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Stefan Sperling88220092018-12-11 14:42:00 +01001395 install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001396 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1397 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001398 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1399 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1400 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001401 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1402 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001403 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1404 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001405 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1406 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001407 install_element(SGSN_NODE, &cfg_cdr_trap_cmd);
1408 install_element(SGSN_NODE, &cfg_no_cdr_trap_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001409 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001410 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001411 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001412
Harald Welte94508822015-08-15 19:08:21 +02001413 install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd);
1414 install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd);
1415 install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd);
1416 install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd);
1417 install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd);
1418 install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd);
1419 install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd);
1420 install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd);
1421 install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd);
1422 install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd);
1423 install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd);
1424 install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd);
1425
Philippf1f34362016-08-26 17:00:21 +02001426 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1427 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1428 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
Philipp73f83d52016-09-02 13:38:01 +02001429 install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd);
1430 install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
1431 install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001432
1433#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +02001434 ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001435#endif
Harald Welte288be162010-05-01 16:48:27 +02001436 return 0;
1437}
1438
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001439int sgsn_parse_config(const char *config_file)
Harald Welte288be162010-05-01 16:48:27 +02001440{
1441 int rc;
1442
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001443 /* make sure sgsn_vty_init() was called before this */
1444 OSMO_ASSERT(g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +01001445
Harald Welte94508822015-08-15 19:08:21 +02001446 g_cfg->timers.T3312 = GSM0408_T3312_SECS;
1447 g_cfg->timers.T3322 = GSM0408_T3322_SECS;
1448 g_cfg->timers.T3350 = GSM0408_T3350_SECS;
1449 g_cfg->timers.T3360 = GSM0408_T3360_SECS;
1450 g_cfg->timers.T3370 = GSM0408_T3370_SECS;
1451 g_cfg->timers.T3313 = GSM0408_T3313_SECS;
1452 g_cfg->timers.T3314 = GSM0408_T3314_SECS;
1453 g_cfg->timers.T3316 = GSM0408_T3316_SECS;
1454 g_cfg->timers.T3385 = GSM0408_T3385_SECS;
1455 g_cfg->timers.T3386 = GSM0408_T3386_SECS;
1456 g_cfg->timers.T3395 = GSM0408_T3395_SECS;
1457 g_cfg->timers.T3397 = GSM0408_T3397_SECS;
1458
Harald Weltedcccb182010-05-16 20:52:23 +02001459 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001460 if (rc < 0) {
1461 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1462 return rc;
1463 }
1464
Neels Hofmeyr27355c92017-02-24 06:28:31 +01001465 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE
1466 && !(g_cfg->gsup_server_addr.sin_addr.s_addr
1467 && g_cfg->gsup_server_port)) {
1468 fprintf(stderr, "Configuration error:"
1469 " 'auth-policy remote' requires both"
1470 " 'gsup remote-ip' and 'gsup remote-port'\n");
1471 return -EINVAL;
1472 }
1473
Harald Welte288be162010-05-01 16:48:27 +02001474 return 0;
1475}