blob: 601b3c59fa05b5d9fb8d8d03d08afc86a281495e [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);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100206 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
207 vty_out(vty, " gsup remote-ip %s%s",
208 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
209 if (g_cfg->gsup_server_port)
210 vty_out(vty, " gsup remote-port %d%s",
211 g_cfg->gsup_server_port, VTY_NEWLINE);
Max176b62a2016-07-04 11:09:07 +0200212 vty_out(vty, " auth-policy %s%s",
213 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
214 VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200215
216 vty_out(vty, " gsup oap-id %d%s",
217 (int)g_cfg->oap.client_id, VTY_NEWLINE);
218 if (g_cfg->oap.secret_k_present != 0)
219 vty_out(vty, " gsup oap-k %s%s",
220 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
221 VTY_NEWLINE);
222 if (g_cfg->oap.secret_opc_present != 0)
223 vty_out(vty, " gsup oap-opc %s%s",
224 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
225 VTY_NEWLINE);
226
Harald Welte7f6da482013-03-19 11:00:13 +0100227 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
228 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
229
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100230 if (llist_empty(&sgsn_apn_ctxts))
231 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
232 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
233 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200234 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100235 actx->name, actx->imsi_prefix, actx->ggsn->id,
236 VTY_NEWLINE);
237 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200238 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100239 actx->ggsn->id, VTY_NEWLINE);
240 }
241
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200242 if (g_cfg->cdr.filename)
243 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
244 else
245 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +0100246 if (g_cfg->cdr.trap)
247 vty_out(vty, " cdr trap%s", VTY_NEWLINE);
248 else
249 vty_out(vty, " no cdr trap%s", VTY_NEWLINE);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200250 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
251
Harald Welte94508822015-08-15 19:08:21 +0200252 vty_out(vty, " timer t3312 %d%s", g_cfg->timers.T3312, VTY_NEWLINE);
253 vty_out(vty, " timer t3322 %d%s", g_cfg->timers.T3322, VTY_NEWLINE);
254 vty_out(vty, " timer t3350 %d%s", g_cfg->timers.T3350, VTY_NEWLINE);
255 vty_out(vty, " timer t3360 %d%s", g_cfg->timers.T3360, VTY_NEWLINE);
256 vty_out(vty, " timer t3370 %d%s", g_cfg->timers.T3370, VTY_NEWLINE);
257 vty_out(vty, " timer t3313 %d%s", g_cfg->timers.T3313, VTY_NEWLINE);
258 vty_out(vty, " timer t3314 %d%s", g_cfg->timers.T3314, VTY_NEWLINE);
259 vty_out(vty, " timer t3316 %d%s", g_cfg->timers.T3316, VTY_NEWLINE);
260 vty_out(vty, " timer t3385 %d%s", g_cfg->timers.T3385, VTY_NEWLINE);
261 vty_out(vty, " timer t3386 %d%s", g_cfg->timers.T3386, VTY_NEWLINE);
262 vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE);
263 vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE);
264
Philippf1f34362016-08-26 17:00:21 +0200265 if (g_cfg->pcomp_rfc1144.active) {
266 vty_out(vty, " compression rfc1144 active slots %d%s",
267 g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE);
268 } else if (g_cfg->pcomp_rfc1144.passive) {
269 vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE);
270 } else
271 vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE);
272
Philipp73f83d52016-09-02 13:38:01 +0200273 if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) {
274 vty_out(vty,
275 " compression v42bis active direction sgsn codewords %d strlen %d%s",
276 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
277 VTY_NEWLINE);
278 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) {
279 vty_out(vty,
280 " compression v42bis active direction ms codewords %d strlen %d%s",
281 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
282 VTY_NEWLINE);
283 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) {
284 vty_out(vty,
285 " compression v42bis active direction both codewords %d strlen %d%s",
286 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
287 VTY_NEWLINE);
288 } else if (g_cfg->dcomp_v42bis.passive) {
289 vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE);
290 } else
291 vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
292
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200293#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +0200294 ranap_iu_vty_config_write(vty, " ");
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200295#endif
296
Harald Welte288be162010-05-01 16:48:27 +0200297 return CMD_SUCCESS;
298}
299
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100300#define SGSN_STR "Configure the SGSN\n"
301#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200302
303DEFUN(cfg_sgsn, cfg_sgsn_cmd,
304 "sgsn",
305 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200306{
307 vty->node = SGSN_NODE;
308 return CMD_SUCCESS;
309}
310
Harald Weltee300d002010-06-02 12:41:34 +0200311DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
312 "gtp local-ip A.B.C.D",
313 "GTP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100314 "Set the IP address for the local GTP bind for the Gp interface (towards the GGSNs)."
315 " Note: in case you would like to run the GGSN on the same machine as the SGSN, you can not run"
316 " both on the same IP address, since both sides are specified to use the same GTP port numbers"
317 " (" OSMO_STRINGIFY_VAL(GTP1C_PORT) " and " OSMO_STRINGIFY_VAL(GTP1U_PORT) ")."
318 " For example, you could use 127.0.0.1 for the SGSN and 127.0.0.2 for the GGSN in such"
319 " situations.\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100320 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200321{
322 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
323
324 return CMD_SUCCESS;
325}
326
Harald Welted193cb32010-05-17 22:58:03 +0200327DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
328 "ggsn <0-255> remote-ip A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100329 GGSN_STR "GGSN Number\n"
330 "Configure this static GGSN to use the specified remote IP address.\n"
331 "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200332{
333 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200334 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200335
Harald Welted193cb32010-05-17 22:58:03 +0200336 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200337
Harald Welted193cb32010-05-17 22:58:03 +0200338 return CMD_SUCCESS;
339}
340
341#if 0
342DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
343 "ggsn <0-255> remote-port <0-65535>",
344 "")
345{
346 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200347 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200348 uint16_t port = atoi(argv[1]);
349
350}
351#endif
352
353DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
354 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100355 GGSN_STR "GGSN Number\n" "GTP Version\n"
356 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200357{
358 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200359 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200360
361 if (atoi(argv[1]))
362 ggc->gtp_version = 1;
363 else
364 ggc->gtp_version = 0;
365
366 return CMD_SUCCESS;
367}
368
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200369/* Seee 3GPP TS 29.060 section 7.2.1 */
370DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
371 "ggsn <0-255> echo-interval <1-36000>",
372 GGSN_STR "GGSN Number\n"
373 "Send an echo request to this static GGSN every interval.\n"
374 "Interval between echo requests in seconds.\n")
375{
376 uint32_t id = atoi(argv[0]);
377 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
378
379 ggc->echo_interval = atoi(argv[1]);
380
381 if (ggc->echo_interval < 60)
382 vty_out(vty, "%% 3GPP TS 29.060 section states inteval should " \
383 "not be lower than 60 seconds, use this value for " \
384 "testing purposes only!%s", VTY_NEWLINE);
385
Alexander Couzens176a4d22018-09-18 20:07:37 +0200386 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200387 return CMD_SUCCESS;
388}
389
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200390DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
391 "ggsn <0-255> no echo-interval",
392 GGSN_STR "GGSN Number\n"
393 NO_STR "Send an echo request to this static GGSN every interval.\n")
394{
395 uint32_t id = atoi(argv[0]);
396 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
397
398 ggc->echo_interval = -1;
Alexander Couzens176a4d22018-09-18 20:07:37 +0200399 sgsn_ggsn_ctx_check_echo_timer(ggc);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200400
401 return CMD_SUCCESS;
402}
403
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800404DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
405 "ggsn dynamic",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100406 GGSN_STR
407 "Enable dynamic resolving of GGSNs based on DNS resolving the APN name like in a GRX-style setup."
408 " Changing this setting requires a restart.\n")
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800409{
410 sgsn->cfg.dynamic_lookup = 1;
411 return CMD_SUCCESS;
412}
413
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800414DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
415 "grx-dns-add A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100416 "Use the specified IP address for DNS-resolving the AP names to GGSN IP addresses\n"
417 "IPv4 address\n")
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800418{
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +0100419 struct ares_addr_node *node = talloc_zero(tall_sgsn_ctx, struct ares_addr_node);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800420 node->family = AF_INET;
421 inet_aton(argv[0], &node->addr.addr4);
422
423 node->next = sgsn->ares_servers;
424 sgsn->ares_servers = node;
425 return CMD_SUCCESS;
426}
427
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100428#define APN_STR "Configure the information per APN\n"
429#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
430
431static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
432 const char *imsi_prefix, int ggsn_id)
433{
434 struct apn_ctx *actx;
435 struct sgsn_ggsn_ctx *ggsn;
436
437 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
438 if (ggsn == NULL) {
439 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
440 ggsn_id, VTY_NEWLINE);
441 return CMD_WARNING;
442 }
443
444 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
445 if (!actx) {
446 vty_out(vty, "%% unable to create APN context for %s/%s%s",
447 apn_str, imsi_prefix, VTY_NEWLINE);
448 return CMD_WARNING;
449 }
450
451 actx->ggsn = ggsn;
452
453 return CMD_SUCCESS;
454}
455
Harald Welted193cb32010-05-17 22:58:03 +0200456DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
457 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100458 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100459 "Select the GGSN to use for the given APN gateway prefix\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100460 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200461{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100462
463 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200464}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100465
466DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
467 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
468 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100469 "Select the GGSN to use for the given APN gateway prefix if and only if the IMSI matches the"
470 " given prefix.\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100471 "An IMSI prefix\n"
472 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
473 "The GGSN id")
474{
475
476 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
477}
Harald Welted193cb32010-05-17 22:58:03 +0200478
479const struct value_string gprs_mm_st_strs[] = {
480 { GMM_DEREGISTERED, "DEREGISTERED" },
481 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
482 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200483 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200484 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
485 { 0, NULL }
486};
487
Maxc005db72017-10-27 18:43:29 +0200488char *sgsn_gtp_ntoa(struct ul16_t *ul)
Harald Welte471ac7d2016-12-15 19:48:58 +0100489{
Max8492c202017-12-05 17:28:15 +0100490 struct in_addr ia;
491
492 if (gsna2in_addr(&ia, ul) != 0)
Harald Welte471ac7d2016-12-15 19:48:58 +0100493 return "UNKNOWN";
Max8492c202017-12-05 17:28:15 +0100494
495 return inet_ntoa(ia);
Harald Welte471ac7d2016-12-15 19:48:58 +0100496}
497
Harald Welted193cb32010-05-17 22:58:03 +0200498static void vty_dump_pdp(struct vty *vty, const char *pfx,
499 struct sgsn_pdp_ctx *pdp)
500{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200501 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welte471ac7d2016-12-15 19:48:58 +0100502 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s",
503 pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200504 if (pdp->lib) {
Max7933d962017-10-19 16:52:30 +0200505 char apnbuf[APN_MAXLEN + 1];
Harald Weltedfbd2c82017-08-13 00:56:45 +0200506 vty_out(vty, "%s APN: %s%s", pfx,
Max7933d962017-10-19 16:52:30 +0200507 osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200508 VTY_NEWLINE);
509 vty_out(vty, "%s PDP Address: %s%s", pfx,
510 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
511 VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100512 vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200513 sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200514 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200515 sgsn_gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100516 vty_out(vty, "%s GTPv%d Remote Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200517 sgsn_gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200518 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200519 sgsn_gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200520 }
Harald Welte471ac7d2016-12-15 19:48:58 +0100521
Harald Welteefbdee92010-06-10 00:20:12 +0200522 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200523}
524
525static void vty_dump_mmctx(struct vty *vty, const char *pfx,
526 struct sgsn_mm_ctx *mm, int pdp)
527{
528 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
529 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200530 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Harald Weltef97ee042015-12-25 19:12:21 +0100531 pfx, mm->msisdn, mm->gb.tlli, mm->hlr, VTY_NEWLINE);
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100532 vty_out(vty, "%s MM State: %s, Routeing Area: %s, Cell ID: %u%s",
533 pfx, get_value_string(gprs_mm_st_strs, mm->gmm_state),
534 osmo_rai_name(&mm->ra), mm->gb.cell_id, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200535
Harald Welte8acd88f2010-05-18 10:57:45 +0200536 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
537
Harald Welted193cb32010-05-17 22:58:03 +0200538 if (pdp) {
539 struct sgsn_pdp_ctx *pdp;
540
541 llist_for_each_entry(pdp, &mm->pdp_list, list)
542 vty_dump_pdp(vty, " ", pdp);
543 }
544}
545
546DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
547 SHOW_STR "Display information about the SGSN")
548{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100549 if (sgsn->gsup_client) {
550 struct ipa_client_conn *link = sgsn->gsup_client->link;
551 vty_out(vty,
552 " Remote authorization: %sconnected to %s:%d via GSUP%s",
553 sgsn->gsup_client->is_connected ? "" : "not ",
554 link->addr, link->port,
555 VTY_NEWLINE);
556 }
Maxbaabc682017-10-20 13:39:57 +0200557 if (sgsn->gsn)
558 vty_out(vty, " GSN: signalling %s, user traffic %s%s",
559 inet_ntoa(sgsn->gsn->gsnc), inet_ntoa(sgsn->gsn->gsnu), VTY_NEWLINE);
560
Harald Welted193cb32010-05-17 22:58:03 +0200561 /* FIXME: statistics */
562 return CMD_SUCCESS;
563}
564
565#define MMCTX_STR "MM Context\n"
566#define INCLUDE_PDP_STR "Include PDP Context Information\n"
567
568#if 0
569DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
570 "show mm-context tlli HEX [pdp]",
571 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
572{
573 uint32_t tlli;
574 struct sgsn_mm_ctx *mm;
575
576 tlli = strtoul(argv[0], NULL, 16);
577 mm = sgsn_mm_ctx_by_tlli(tlli);
578 if (!mm) {
579 vty_out(vty, "No MM context for TLLI %08x%s",
580 tlli, VTY_NEWLINE);
581 return CMD_WARNING;
582 }
583 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
584 return CMD_SUCCESS;
585}
586#endif
587
588DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
589 "show mm-context imsi IMSI [pdp]",
590 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
591 INCLUDE_PDP_STR)
592{
593 struct sgsn_mm_ctx *mm;
594
595 mm = sgsn_mm_ctx_by_imsi(argv[0]);
596 if (!mm) {
597 vty_out(vty, "No MM context for IMSI %s%s",
598 argv[0], VTY_NEWLINE);
599 return CMD_WARNING;
600 }
601 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
602 return CMD_SUCCESS;
603}
604
605DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
606 "show mm-context all [pdp]",
607 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
608{
609 struct sgsn_mm_ctx *mm;
610
611 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
612 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
613
614 return CMD_SUCCESS;
615}
616
Harald Welted193cb32010-05-17 22:58:03 +0200617DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
618 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100619 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200620{
621 struct sgsn_pdp_ctx *pdp;
622
623 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
624 vty_dump_pdp(vty, "", pdp);
625
626 return CMD_SUCCESS;
627}
Harald Welte288be162010-05-01 16:48:27 +0200628
Harald Welte7f6da482013-03-19 11:00:13 +0100629
630DEFUN(imsi_acl, cfg_imsi_acl_cmd,
631 "imsi-acl (add|del) IMSI",
632 "Access Control List of foreign IMSIs\n"
633 "Add IMSI to ACL\n"
634 "Remove IMSI from ACL\n"
635 "IMSI of subscriber\n")
636{
Maxf4fa6952018-01-15 12:12:51 +0100637 char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS + 1] = { '0' };
Harald Welte7f6da482013-03-19 11:00:13 +0100638 const char *op = argv[0];
Philipp Maier6ee49d82017-02-28 16:53:07 +0100639 const char *imsi = imsi_sanitized;
Maxf4fa6952018-01-15 12:12:51 +0100640 size_t len = strnlen(argv[1], GSM23003_IMSI_MAX_DIGITS + 1);
Harald Welte7f6da482013-03-19 11:00:13 +0100641 int rc;
642
Philipp Maier6ee49d82017-02-28 16:53:07 +0100643 /* Sanitize IMSI */
Maxf4fa6952018-01-15 12:12:51 +0100644 if (len > GSM23003_IMSI_MAX_DIGITS) {
645 vty_out(vty, "%% IMSI (%s) too long (max %u digits) -- ignored!%s",
646 argv[1], GSM23003_IMSI_MAX_DIGITS, VTY_NEWLINE);
Philipp Maier6ee49d82017-02-28 16:53:07 +0100647 return CMD_WARNING;
648 }
Maxf4fa6952018-01-15 12:12:51 +0100649
650 osmo_strlcpy(imsi_sanitized + GSM23003_IMSI_MAX_DIGITS - len, argv[1],
651 sizeof(imsi_sanitized) - (GSM23003_IMSI_MAX_DIGITS - len));
Philipp Maier6ee49d82017-02-28 16:53:07 +0100652
Harald Welte7f6da482013-03-19 11:00:13 +0100653 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200654 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100655 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200656 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100657
658 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100659 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100660 return CMD_WARNING;
661 }
662
663 return CMD_SUCCESS;
664}
665
Max93408ae2016-06-28 14:10:16 +0200666DEFUN(cfg_encrypt, cfg_encrypt_cmd,
667 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
668 "Set encryption algorithm for SGSN\n"
669 "Use GEA0 (no encryption)\n"
670 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
671{
Max93408ae2016-06-28 14:10:16 +0200672 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
Max086067f2017-05-02 13:03:28 +0200673 if (c != GPRS_ALGO_GEA0) {
674 if (!gprs_cipher_supported(c)) {
675 vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
676 return CMD_WARNING;
677 }
678
679 if (!g_cfg->require_authentication) {
680 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
681 argv[0], VTY_NEWLINE);
682 return CMD_WARNING;
683 }
Max93408ae2016-06-28 14:10:16 +0200684 }
685
686 g_cfg->cipher = c;
687
688 return CMD_SUCCESS;
689}
690
Harald Welte3dfb5492013-03-19 11:48:54 +0100691DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100692 "auth-policy (accept-all|closed|acl-only|remote)",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100693 "Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
694 " permitted to register to the network.\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100695 "Accept all IMSIs (DANGEROUS)\n"
696 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100697 "Accept only subscribers in the ACL\n"
698 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100699{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100700 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100701 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100702 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100703 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100704 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100705
706 return CMD_SUCCESS;
707}
708
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100709/* Subscriber */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +0200710#include <osmocom/sgsn/gprs_subscriber.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100711
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100712static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100713{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100714#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100715 char expire_time[200];
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100716#endif
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100717 struct gsm_auth_tuple *at;
718 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100719 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100720
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100721 vty_out(vty, " Authorized: %d%s",
722 gsub->authorized, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100723 vty_out(vty, " LAC: %d/0x%x%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100724 gsub->lac, gsub->lac, VTY_NEWLINE);
725 vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
726 if (gsub->tmsi != GSM_RESERVED_TMSI)
727 vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100728 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100729 if (gsub->sgsn_data->msisdn_len > 0)
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400730 vty_out(vty, " MSISDN (BCD): %s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100731 osmo_hexdump(gsub->sgsn_data->msisdn,
732 gsub->sgsn_data->msisdn_len),
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400733 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100734
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100735 if (strlen(gsub->imei) > 0)
736 vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100737
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100738 for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100739 at_idx++) {
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100740 at = &gsub->sgsn_data->auth_triplets[at_idx];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100741 if (at->key_seq == GSM_KEY_SEQ_INVAL)
742 continue;
743
744 vty_out(vty, " A3A8 tuple (used %d times): ",
745 at->use_count);
Harald Welte89837d42016-05-06 23:28:11 +0200746 vty_out(vty, " CKSN: %d, ",
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100747 at->key_seq);
Harald Welte89837d42016-05-06 23:28:11 +0200748 if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
749 vty_out(vty, "RAND: %s, ",
750 osmo_hexdump(at->vec.rand,
751 sizeof(at->vec.rand)));
752 vty_out(vty, "SRES: %s, ",
753 osmo_hexdump(at->vec.sres,
754 sizeof(at->vec.sres)));
755 vty_out(vty, "Kc: %s%s",
756 osmo_hexdump(at->vec.kc,
757 sizeof(at->vec.kc)), VTY_NEWLINE);
758 }
759 if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
760 vty_out(vty, " AUTN: %s, ",
761 osmo_hexdump(at->vec.autn,
762 sizeof(at->vec.autn)));
763 vty_out(vty, "RES: %s, ",
764 osmo_hexdump(at->vec.res, at->vec.res_len));
765 vty_out(vty, "IK: %s, ",
766 osmo_hexdump(at->vec.ik, sizeof(at->vec.ik)));
767 vty_out(vty, "CK: %s, ",
768 osmo_hexdump(at->vec.ck, sizeof(at->vec.ck)));
769 }
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100770 }
771
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100772 llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400773 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s' QoS: %s%s",
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100774 pdp->context_id, pdp->pdp_type, pdp->apn_str,
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400775 osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len),
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100776 VTY_NEWLINE);
777 }
778
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100779#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100780 /* print the expiration time of a subscriber */
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100781 if (gsub->expire_lu) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100782 strftime(expire_time, sizeof(expire_time),
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100783 "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100784 expire_time[sizeof(expire_time) - 1] = '\0';
785 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
786 }
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100787#endif
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100788
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100789 if (gsub->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100790 vty_out(vty, " Flags: %s%s%s%s%s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100791 gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100792 "FIRST_CONTACT " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100793 gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100794 "CANCELLED " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100795 gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100796 "UPDATE_LOCATION_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100797 gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100798 "AUTH_INFO_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100799 gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100800 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100801 VTY_NEWLINE);
802
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100803 vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100804}
805
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200806#define RESET_SGSN_STATE_STR \
807 "Remove all known subscribers, MM contexts and flush BSSGP queues." \
808 " Useful only when running tests against the SGSN\n"
809
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200810DEFUN_HIDDEN(reset_sgsn_state,
811 reset_sgsn_state_cmd,
812 "reset sgsn state",
Neels Hofmeyr1a9414b2018-09-24 18:14:29 +0200813 RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR)
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200814{
815 struct gprs_subscr *subscr, *tmp_subscr;
816 struct sgsn_mm_ctx *mm, *tmp_mm;
817
818 llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
819 {
820 gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
821 }
822 vty_out(vty, "Cancelled MM Ctx. %s", VTY_NEWLINE);
823
824 llist_for_each_entry_safe(subscr, tmp_subscr, gprs_subscribers, entry) {
825 gprs_subscr_get(subscr);
826 gprs_subscr_cancel(subscr);
827 gprs_subscr_put(subscr);
828 }
829 vty_out(vty, "Removed all gprs subscribers.%s", VTY_NEWLINE);
830
831 bssgp_flush_all_queues();
832 vty_out(vty, "Flushed all BSSGPs queues.%s", VTY_NEWLINE);
833
Alexander Couzens35c34942018-09-17 04:39:14 +0200834 gtp_clear_queues(sgsn->gsn);
Alexander Couzensa66f0f22018-09-18 16:09:18 +0200835 vty_out(vty, "Flushed rx & tx queus towards the GGSN.%s", VTY_NEWLINE);
Alexander Couzens35c34942018-09-17 04:39:14 +0200836
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200837 /* remove all queues to bssgp */
838 return CMD_SUCCESS;
839}
840
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100841DEFUN(show_subscr_cache,
842 show_subscr_cache_cmd,
843 "show subscriber cache",
844 SHOW_STR "Show information about subscribers\n"
845 "Display contents of subscriber cache\n")
846{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100847 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100848
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100849 llist_for_each_entry(subscr, gprs_subscribers, entry) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100850 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
851 subscr_dump_full_vty(vty, subscr, 0);
852 }
853
854 return CMD_SUCCESS;
855}
856
857#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
858#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
859 "Use the IMSI to select the subscriber\n" \
860 "The IMSI\n"
861
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100862#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
863
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100864DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
865 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
866 UPDATE_SUBSCR_HELP
867 UPDATE_SUBSCR_INSERT_HELP
868 "Update authentication triplet\n"
869 "Triplet index\n"
870 "Set SRES value\nSRES value (4 byte) in hex\n"
871 "Set RAND value\nRAND value (16 byte) in hex\n"
872 "Set Kc value\nKc value (8 byte) in hex\n")
873{
874 const char *imsi = argv[0];
875 const int cksn = atoi(argv[1]) - 1;
876 const char *sres_str = argv[2];
877 const char *rand_str = argv[3];
878 const char *kc_str = argv[4];
879 struct gsm_auth_tuple at = {0,};
880
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100881 struct gprs_subscr *subscr;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100882
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100883 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100884 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100885 vty_out(vty, "%% unable get subscriber record for %s%s",
886 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100887 return CMD_WARNING;
888 }
889
890 OSMO_ASSERT(subscr->sgsn_data);
891
Harald Welte121e9a42016-04-20 13:13:19 +0200892 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100893 vty_out(vty, "%% invalid SRES value '%s'%s",
894 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100895 goto failed;
896 }
Harald Welte121e9a42016-04-20 13:13:19 +0200897 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100898 vty_out(vty, "%% invalid RAND value '%s'%s",
899 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100900 goto failed;
901 }
Harald Welte121e9a42016-04-20 13:13:19 +0200902 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100903 vty_out(vty, "%% invalid Kc value '%s'%s",
904 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100905 goto failed;
906 }
907 at.key_seq = cksn;
908
909 subscr->sgsn_data->auth_triplets[cksn] = at;
910 subscr->sgsn_data->auth_triplets_updated = 1;
911
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100912 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100913
914 return CMD_SUCCESS;
915
916failed:
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100917 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100918 return CMD_SUCCESS;
919}
920
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100921DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100922 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100923 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100924 "Cancel (remove) subscriber record\n"
925 "The MS moved to another SGSN\n"
926 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100927{
928 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100929 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100930
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100931 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100932
933 subscr = gprs_subscr_get_by_imsi(imsi);
934 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100935 vty_out(vty, "%% no subscriber record for %s%s",
936 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100937 return CMD_WARNING;
938 }
939
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100940 if (strcmp(cancel_type, "update-procedure") == 0)
941 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
942 else
943 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
944
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100945 gprs_subscr_cancel(subscr);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100946 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100947
948 return CMD_SUCCESS;
949}
950
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100951DEFUN(update_subscr_create, update_subscr_create_cmd,
952 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100953 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100954 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100955{
956 const char *imsi = argv[0];
957
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100958 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100959
960 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100961 if (subscr) {
962 vty_out(vty, "%% subscriber record already exists for %s%s",
963 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100964 return CMD_WARNING;
965 }
966
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100967 subscr = gprs_subscr_get_or_create(imsi);
968 subscr->keep_in_ram = 1;
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100969 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100970
971 return CMD_SUCCESS;
972}
973
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100974DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
975 UPDATE_SUBSCR_STR "destroy",
976 UPDATE_SUBSCR_HELP
977 "Destroy a subscriber entry\n")
978{
979 const char *imsi = argv[0];
980
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100981 struct gprs_subscr *subscr;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100982
983 subscr = gprs_subscr_get_by_imsi(imsi);
984 if (!subscr) {
985 vty_out(vty, "%% subscriber record does not exist for %s%s",
986 imsi, VTY_NEWLINE);
987 return CMD_WARNING;
988 }
989
990 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100991 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100992 gprs_subscr_cancel(subscr);
993 if (subscr->use_count > 1)
994 vty_out(vty, "%% subscriber is still in use%s",
995 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100996 gprs_subscr_put(subscr);
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100997
998 return CMD_SUCCESS;
999}
1000
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001001#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
1002 "unknown-subscriber|roaming-not-allowed"
1003
1004#define UL_ERR_HELP \
1005 "Force error code SystemFailure\n" \
1006 "Force error code DataMissing\n" \
1007 "Force error code UnexpectedDataValue\n" \
1008 "Force error code UnknownSubscriber\n" \
1009 "Force error code RoamingNotAllowed\n"
1010
1011DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
1012 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
1013 UPDATE_SUBSCR_HELP
1014 "Complete the update location procedure\n"
1015 "The update location request succeeded\n"
1016 UL_ERR_HELP)
1017{
1018 const char *imsi = argv[0];
1019 const char *ret_code_str = argv[1];
1020
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001021 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001022
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001023 const struct value_string cause_mapping[] = {
1024 { GMM_CAUSE_NET_FAIL, "system-failure" },
1025 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
1026 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
1027 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
1028 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
1029 { 0, NULL }
1030 };
1031
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001032 subscr = gprs_subscr_get_by_imsi(imsi);
1033 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001034 vty_out(vty, "%% unable to get subscriber record for %s%s",
1035 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001036 return CMD_WARNING;
1037 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001038
1039 if (strcmp(ret_code_str, "ok") == 0) {
1040 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001041 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001042 } else {
1043 subscr->sgsn_data->error_cause =
1044 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001045 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001046 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001047
1048 gprs_subscr_update(subscr);
1049
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001050 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001051
1052 return CMD_SUCCESS;
1053}
1054
1055DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
1056 UPDATE_SUBSCR_STR "update-auth-info",
1057 UPDATE_SUBSCR_HELP
1058 "Complete the send authentication info procedure\n")
1059{
1060 const char *imsi = argv[0];
1061
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001062 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001063
1064 subscr = gprs_subscr_get_by_imsi(imsi);
1065 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001066 vty_out(vty, "%% unable to get subscriber record for %s%s",
1067 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001068 return CMD_WARNING;
1069 }
1070
1071 gprs_subscr_update_auth_info(subscr);
1072
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001073 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001074
1075 return CMD_SUCCESS;
1076}
1077
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001078DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
1079 "gsup remote-ip A.B.C.D",
1080 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001081 "Set the IP address of the remote GSUP server (e.g. OsmoHLR)."
1082 " This setting only applies if 'auth-policy remote' is used.\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001083 "IPv4 Address\n")
1084{
1085 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
1086
1087 return CMD_SUCCESS;
1088}
1089
1090DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
1091 "gsup remote-port <0-65535>",
1092 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001093 "Set the TCP port of the remote GSUP server, see also 'gsup remote-ip'\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001094 "Remote TCP port\n")
1095{
1096 g_cfg->gsup_server_port = atoi(argv[0]);
1097
1098 return CMD_SUCCESS;
1099}
1100
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001101DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
1102 "gsup oap-id <0-65535>",
1103 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001104 "Set the OAP client ID for authentication on the GSUP protocol."
1105 " This setting only applies if 'auth-policy remote' is used.\n"
1106 "OAP client ID (0 == disabled)\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001107{
1108 /* VTY ensures range */
1109 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
1110 return CMD_SUCCESS;
1111}
1112
1113DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
1114 "gsup oap-k K",
1115 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001116 "Set the OAP shared secret key K for authentication on the GSUP protocol."
1117 " This setting only applies if auth-policy remote is used.\n"
1118 "K value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001119{
1120 const char *k = argv[0];
1121
1122 g_cfg->oap.secret_k_present = 0;
1123
1124 if ((!k) || (strlen(k) == 0))
1125 goto disable;
1126
1127 int k_len = osmo_hexparse(k,
1128 g_cfg->oap.secret_k,
1129 sizeof(g_cfg->oap.secret_k));
1130 if (k_len != 16) {
1131 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
1132 k_len, VTY_NEWLINE);
1133 goto disable;
1134 }
1135
1136 g_cfg->oap.secret_k_present = 1;
1137 return CMD_SUCCESS;
1138
1139disable:
1140 if (g_cfg->oap.client_id > 0) {
1141 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
1142 VTY_NEWLINE);
1143 return CMD_WARNING;
1144 }
1145 return CMD_SUCCESS;
1146}
1147
1148DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1149 "gsup oap-opc OPC",
1150 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001151 "Set the OAP shared secret OPC for authentication on the GSUP protocol."
1152 " This setting only applies if auth-policy remote is used.\n"
1153 "OPC value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001154{
1155 const char *opc = argv[0];
1156
1157 g_cfg->oap.secret_opc_present = 0;
1158
1159 if ((!opc) || (strlen(opc) == 0))
1160 goto disable;
1161
1162 int opc_len = osmo_hexparse(opc,
1163 g_cfg->oap.secret_opc,
1164 sizeof(g_cfg->oap.secret_opc));
1165 if (opc_len != 16) {
1166 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1167 opc_len, VTY_NEWLINE);
1168 goto disable;
1169 }
1170
1171 g_cfg->oap.secret_opc_present = 1;
1172 return CMD_SUCCESS;
1173
1174disable:
1175 if (g_cfg->oap.client_id > 0) {
1176 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1177 VTY_NEWLINE);
1178 return CMD_WARNING;
1179 }
1180 return CMD_SUCCESS;
1181}
1182
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001183DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1184 "access-point-name NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001185 "Globally allow the given APN name for all subscribers.\n"
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001186 "Add this NAME to the list\n")
1187{
1188 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1189}
1190
1191DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1192 "no access-point-name NAME",
1193 NO_STR "Configure a global list of allowed APNs\n"
1194 "Remove entry with NAME\n")
1195{
1196 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1197 if (!apn_ctx)
1198 return CMD_SUCCESS;
1199
1200 sgsn_apn_ctx_free(apn_ctx);
1201 return CMD_SUCCESS;
1202}
1203
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001204DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1205 "cdr filename NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001206 "CDR\n"
1207 "Set the file name for the call-data-record file, logging the data usage of each subscriber.\n"
1208 "filename\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001209{
1210 talloc_free(g_cfg->cdr.filename);
1211 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1212 return CMD_SUCCESS;
1213}
1214
1215DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1216 "no cdr filename",
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001217 NO_STR "CDR\nDisable saving CDR to file\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001218{
1219 talloc_free(g_cfg->cdr.filename);
1220 g_cfg->cdr.filename = NULL;
1221 return CMD_SUCCESS;
1222}
1223
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001224DEFUN(cfg_cdr_trap, cfg_cdr_trap_cmd,
1225 "cdr trap",
1226 "CDR\nEnable sending CDR via TRAP CTRL messages\n")
1227{
1228 g_cfg->cdr.trap = true;
1229 return CMD_SUCCESS;
1230}
1231
1232DEFUN(cfg_no_cdr_trap, cfg_no_cdr_trap_cmd,
1233 "no cdr trap",
1234 NO_STR "CDR\nDisable sending CDR via TRAP CTRL messages\n")
1235{
1236 g_cfg->cdr.trap = false;
1237 return CMD_SUCCESS;
1238}
1239
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001240DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1241 "cdr interval <1-2147483647>",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001242 "CDR\n"
1243 "Set the interval for the call-data-record file\n"
1244 "interval in seconds\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001245{
1246 g_cfg->cdr.interval = atoi(argv[0]);
1247 return CMD_SUCCESS;
1248}
1249
Philippf1f34362016-08-26 17:00:21 +02001250#define COMPRESSION_STR "Configure compression\n"
1251DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1252 "no compression rfc1144",
1253 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1254{
1255 g_cfg->pcomp_rfc1144.active = 0;
1256 g_cfg->pcomp_rfc1144.passive = 0;
1257 return CMD_SUCCESS;
1258}
1259
1260DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1261 "compression rfc1144 active slots <1-256>",
1262 COMPRESSION_STR
1263 "RFC1144 Header compresion scheme\n"
1264 "Compression is actively proposed\n"
1265 "Number of compression state slots\n"
1266 "Number of compression state slots\n")
1267{
1268 g_cfg->pcomp_rfc1144.active = 1;
1269 g_cfg->pcomp_rfc1144.passive = 1;
1270 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1271 return CMD_SUCCESS;
1272}
1273
1274DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1275 "compression rfc1144 passive",
1276 COMPRESSION_STR
1277 "RFC1144 Header compresion scheme\n"
1278 "Compression is available on request\n")
1279{
1280 g_cfg->pcomp_rfc1144.active = 0;
1281 g_cfg->pcomp_rfc1144.passive = 1;
1282 return CMD_SUCCESS;
1283}
1284
Philipp73f83d52016-09-02 13:38:01 +02001285DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
1286 "no compression v42bis",
1287 NO_STR COMPRESSION_STR "disable V.42bis data compression\n")
1288{
1289 g_cfg->dcomp_v42bis.active = 0;
1290 g_cfg->dcomp_v42bis.passive = 0;
1291 return CMD_SUCCESS;
1292}
1293
1294DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
1295 "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
1296 COMPRESSION_STR
1297 "V.42bis data compresion scheme\n"
1298 "Compression is actively proposed\n"
1299 "Direction in which the compression shall be active (p0)\n"
1300 "Compress ms->sgsn direction only\n"
1301 "Compress sgsn->ms direction only\n"
1302 "Both directions\n"
1303 "Number of codewords (p1)\n"
1304 "Number of codewords\n"
1305 "Maximum string length (p2)\n" "Maximum string length\n")
1306{
1307 g_cfg->dcomp_v42bis.active = 1;
1308 g_cfg->dcomp_v42bis.passive = 1;
1309
1310 switch (argv[0][0]) {
1311 case 'm':
1312 g_cfg->dcomp_v42bis.p0 = 1;
1313 break;
1314 case 's':
1315 g_cfg->dcomp_v42bis.p0 = 2;
1316 break;
1317 case 'b':
1318 g_cfg->dcomp_v42bis.p0 = 3;
1319 break;
1320 }
1321
1322 g_cfg->dcomp_v42bis.p1 = atoi(argv[1]);
1323 g_cfg->dcomp_v42bis.p2 = atoi(argv[2]);
1324 return CMD_SUCCESS;
1325}
1326
1327DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
1328 "compression v42bis passive",
1329 COMPRESSION_STR
1330 "V.42bis data compresion scheme\n"
1331 "Compression is available on request\n")
1332{
1333 g_cfg->dcomp_v42bis.active = 0;
1334 g_cfg->dcomp_v42bis.passive = 1;
1335 return CMD_SUCCESS;
1336}
1337
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001338int sgsn_vty_init(struct sgsn_config *cfg)
Harald Welte288be162010-05-01 16:48:27 +02001339{
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001340 g_cfg = cfg;
1341
Harald Welted193cb32010-05-17 22:58:03 +02001342 install_element_ve(&show_sgsn_cmd);
1343 //install_element_ve(&show_mmctx_tlli_cmd);
1344 install_element_ve(&show_mmctx_imsi_cmd);
1345 install_element_ve(&show_mmctx_all_cmd);
1346 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001347 install_element_ve(&show_subscr_cache_cmd);
1348
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001349 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001350 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001351 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001352 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001353 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1354 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001355 install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001356
1357 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1358 install_node(&sgsn_node, config_write_sgsn);
Harald Weltee300d002010-06-02 12:41:34 +02001359 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001360 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1361 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1362 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +02001363 install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +02001364 install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001365 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001366 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Max93408ae2016-06-28 14:10:16 +02001367 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001368 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1369 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001370 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1371 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1372 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001373 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1374 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001375 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1376 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001377 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1378 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001379 install_element(SGSN_NODE, &cfg_cdr_trap_cmd);
1380 install_element(SGSN_NODE, &cfg_no_cdr_trap_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001381 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001382 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001383 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001384
Harald Welte94508822015-08-15 19:08:21 +02001385 install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd);
1386 install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd);
1387 install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd);
1388 install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd);
1389 install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd);
1390 install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd);
1391 install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd);
1392 install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd);
1393 install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd);
1394 install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd);
1395 install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd);
1396 install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd);
1397
Philippf1f34362016-08-26 17:00:21 +02001398 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1399 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1400 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
Philipp73f83d52016-09-02 13:38:01 +02001401 install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd);
1402 install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
1403 install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001404
1405#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +02001406 ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001407#endif
Harald Welte288be162010-05-01 16:48:27 +02001408 return 0;
1409}
1410
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001411int sgsn_parse_config(const char *config_file)
Harald Welte288be162010-05-01 16:48:27 +02001412{
1413 int rc;
1414
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001415 /* make sure sgsn_vty_init() was called before this */
1416 OSMO_ASSERT(g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +01001417
Harald Welte94508822015-08-15 19:08:21 +02001418 g_cfg->timers.T3312 = GSM0408_T3312_SECS;
1419 g_cfg->timers.T3322 = GSM0408_T3322_SECS;
1420 g_cfg->timers.T3350 = GSM0408_T3350_SECS;
1421 g_cfg->timers.T3360 = GSM0408_T3360_SECS;
1422 g_cfg->timers.T3370 = GSM0408_T3370_SECS;
1423 g_cfg->timers.T3313 = GSM0408_T3313_SECS;
1424 g_cfg->timers.T3314 = GSM0408_T3314_SECS;
1425 g_cfg->timers.T3316 = GSM0408_T3316_SECS;
1426 g_cfg->timers.T3385 = GSM0408_T3385_SECS;
1427 g_cfg->timers.T3386 = GSM0408_T3386_SECS;
1428 g_cfg->timers.T3395 = GSM0408_T3395_SECS;
1429 g_cfg->timers.T3397 = GSM0408_T3397_SECS;
1430
Harald Weltedcccb182010-05-16 20:52:23 +02001431 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001432 if (rc < 0) {
1433 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1434 return rc;
1435 }
1436
Neels Hofmeyr27355c92017-02-24 06:28:31 +01001437 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE
1438 && !(g_cfg->gsup_server_addr.sin_addr.s_addr
1439 && g_cfg->gsup_server_port)) {
1440 fprintf(stderr, "Configuration error:"
1441 " 'auth-policy remote' requires both"
1442 " 'gsup remote-ip' and 'gsup remote-port'\n");
1443 return -EINVAL;
1444 }
1445
Harald Welte288be162010-05-01 16:48:27 +02001446 return 0;
1447}