blob: 057be9f0b0ebf7d7e1cada6fa836487c3425b70b [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>
40#include <osmocom/sgsn/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
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020059extern void *tall_bsc_ctx;
60
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
386 return CMD_SUCCESS;
387}
388
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200389DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
390 "ggsn <0-255> no echo-interval",
391 GGSN_STR "GGSN Number\n"
392 NO_STR "Send an echo request to this static GGSN every interval.\n")
393{
394 uint32_t id = atoi(argv[0]);
395 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
396
397 ggc->echo_interval = -1;
398
399 return CMD_SUCCESS;
400}
401
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800402DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
403 "ggsn dynamic",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100404 GGSN_STR
405 "Enable dynamic resolving of GGSNs based on DNS resolving the APN name like in a GRX-style setup."
406 " Changing this setting requires a restart.\n")
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800407{
408 sgsn->cfg.dynamic_lookup = 1;
409 return CMD_SUCCESS;
410}
411
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800412DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
413 "grx-dns-add A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100414 "Use the specified IP address for DNS-resolving the AP names to GGSN IP addresses\n"
415 "IPv4 address\n")
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800416{
417 struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node);
418 node->family = AF_INET;
419 inet_aton(argv[0], &node->addr.addr4);
420
421 node->next = sgsn->ares_servers;
422 sgsn->ares_servers = node;
423 return CMD_SUCCESS;
424}
425
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100426#define APN_STR "Configure the information per APN\n"
427#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
428
429static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
430 const char *imsi_prefix, int ggsn_id)
431{
432 struct apn_ctx *actx;
433 struct sgsn_ggsn_ctx *ggsn;
434
435 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
436 if (ggsn == NULL) {
437 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
438 ggsn_id, VTY_NEWLINE);
439 return CMD_WARNING;
440 }
441
442 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
443 if (!actx) {
444 vty_out(vty, "%% unable to create APN context for %s/%s%s",
445 apn_str, imsi_prefix, VTY_NEWLINE);
446 return CMD_WARNING;
447 }
448
449 actx->ggsn = ggsn;
450
451 return CMD_SUCCESS;
452}
453
Harald Welted193cb32010-05-17 22:58:03 +0200454DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
455 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100456 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100457 "Select the GGSN to use for the given APN gateway prefix\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100458 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200459{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100460
461 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200462}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100463
464DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
465 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
466 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100467 "Select the GGSN to use for the given APN gateway prefix if and only if the IMSI matches the"
468 " given prefix.\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100469 "An IMSI prefix\n"
470 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
471 "The GGSN id")
472{
473
474 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
475}
Harald Welted193cb32010-05-17 22:58:03 +0200476
477const struct value_string gprs_mm_st_strs[] = {
478 { GMM_DEREGISTERED, "DEREGISTERED" },
479 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
480 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200481 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200482 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
483 { 0, NULL }
484};
485
Maxc005db72017-10-27 18:43:29 +0200486char *sgsn_gtp_ntoa(struct ul16_t *ul)
Harald Welte471ac7d2016-12-15 19:48:58 +0100487{
Max8492c202017-12-05 17:28:15 +0100488 struct in_addr ia;
489
490 if (gsna2in_addr(&ia, ul) != 0)
Harald Welte471ac7d2016-12-15 19:48:58 +0100491 return "UNKNOWN";
Max8492c202017-12-05 17:28:15 +0100492
493 return inet_ntoa(ia);
Harald Welte471ac7d2016-12-15 19:48:58 +0100494}
495
Harald Welted193cb32010-05-17 22:58:03 +0200496static void vty_dump_pdp(struct vty *vty, const char *pfx,
497 struct sgsn_pdp_ctx *pdp)
498{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200499 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welte471ac7d2016-12-15 19:48:58 +0100500 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s",
501 pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200502 if (pdp->lib) {
Max7933d962017-10-19 16:52:30 +0200503 char apnbuf[APN_MAXLEN + 1];
Harald Weltedfbd2c82017-08-13 00:56:45 +0200504 vty_out(vty, "%s APN: %s%s", pfx,
Max7933d962017-10-19 16:52:30 +0200505 osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200506 VTY_NEWLINE);
507 vty_out(vty, "%s PDP Address: %s%s", pfx,
508 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
509 VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100510 vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200511 sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200512 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200513 sgsn_gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100514 vty_out(vty, "%s GTPv%d Remote Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200515 sgsn_gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200516 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200517 sgsn_gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200518 }
Harald Welte471ac7d2016-12-15 19:48:58 +0100519
Harald Welteefbdee92010-06-10 00:20:12 +0200520 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200521}
522
523static void vty_dump_mmctx(struct vty *vty, const char *pfx,
524 struct sgsn_mm_ctx *mm, int pdp)
525{
526 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
527 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200528 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Harald Weltef97ee042015-12-25 19:12:21 +0100529 pfx, mm->msisdn, mm->gb.tlli, mm->hlr, VTY_NEWLINE);
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100530 vty_out(vty, "%s MM State: %s, Routeing Area: %s, Cell ID: %u%s",
531 pfx, get_value_string(gprs_mm_st_strs, mm->gmm_state),
532 osmo_rai_name(&mm->ra), mm->gb.cell_id, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200533
Harald Welte8acd88f2010-05-18 10:57:45 +0200534 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
535
Harald Welted193cb32010-05-17 22:58:03 +0200536 if (pdp) {
537 struct sgsn_pdp_ctx *pdp;
538
539 llist_for_each_entry(pdp, &mm->pdp_list, list)
540 vty_dump_pdp(vty, " ", pdp);
541 }
542}
543
544DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
545 SHOW_STR "Display information about the SGSN")
546{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100547 if (sgsn->gsup_client) {
548 struct ipa_client_conn *link = sgsn->gsup_client->link;
549 vty_out(vty,
550 " Remote authorization: %sconnected to %s:%d via GSUP%s",
551 sgsn->gsup_client->is_connected ? "" : "not ",
552 link->addr, link->port,
553 VTY_NEWLINE);
554 }
Maxbaabc682017-10-20 13:39:57 +0200555 if (sgsn->gsn)
556 vty_out(vty, " GSN: signalling %s, user traffic %s%s",
557 inet_ntoa(sgsn->gsn->gsnc), inet_ntoa(sgsn->gsn->gsnu), VTY_NEWLINE);
558
Harald Welted193cb32010-05-17 22:58:03 +0200559 /* FIXME: statistics */
560 return CMD_SUCCESS;
561}
562
563#define MMCTX_STR "MM Context\n"
564#define INCLUDE_PDP_STR "Include PDP Context Information\n"
565
566#if 0
567DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
568 "show mm-context tlli HEX [pdp]",
569 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
570{
571 uint32_t tlli;
572 struct sgsn_mm_ctx *mm;
573
574 tlli = strtoul(argv[0], NULL, 16);
575 mm = sgsn_mm_ctx_by_tlli(tlli);
576 if (!mm) {
577 vty_out(vty, "No MM context for TLLI %08x%s",
578 tlli, VTY_NEWLINE);
579 return CMD_WARNING;
580 }
581 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
582 return CMD_SUCCESS;
583}
584#endif
585
586DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
587 "show mm-context imsi IMSI [pdp]",
588 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
589 INCLUDE_PDP_STR)
590{
591 struct sgsn_mm_ctx *mm;
592
593 mm = sgsn_mm_ctx_by_imsi(argv[0]);
594 if (!mm) {
595 vty_out(vty, "No MM context for IMSI %s%s",
596 argv[0], VTY_NEWLINE);
597 return CMD_WARNING;
598 }
599 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
600 return CMD_SUCCESS;
601}
602
603DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
604 "show mm-context all [pdp]",
605 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
606{
607 struct sgsn_mm_ctx *mm;
608
609 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
610 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
611
612 return CMD_SUCCESS;
613}
614
Harald Welted193cb32010-05-17 22:58:03 +0200615DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
616 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100617 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200618{
619 struct sgsn_pdp_ctx *pdp;
620
621 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
622 vty_dump_pdp(vty, "", pdp);
623
624 return CMD_SUCCESS;
625}
Harald Welte288be162010-05-01 16:48:27 +0200626
Harald Welte7f6da482013-03-19 11:00:13 +0100627
628DEFUN(imsi_acl, cfg_imsi_acl_cmd,
629 "imsi-acl (add|del) IMSI",
630 "Access Control List of foreign IMSIs\n"
631 "Add IMSI to ACL\n"
632 "Remove IMSI from ACL\n"
633 "IMSI of subscriber\n")
634{
Philipp Maier6ee49d82017-02-28 16:53:07 +0100635 char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS+1];
Harald Welte7f6da482013-03-19 11:00:13 +0100636 const char *op = argv[0];
Philipp Maier6ee49d82017-02-28 16:53:07 +0100637 const char *imsi = imsi_sanitized;
Harald Welte7f6da482013-03-19 11:00:13 +0100638 int rc;
639
Philipp Maier6ee49d82017-02-28 16:53:07 +0100640 /* Sanitize IMSI */
641 if (strlen(argv[1]) > GSM23003_IMSI_MAX_DIGITS) {
642 vty_out(vty, "%% IMSI (%s) too long -- ignored!%s",
643 argv[1], VTY_NEWLINE);
644 return CMD_WARNING;
645 }
646 memset(imsi_sanitized, '0', sizeof(imsi_sanitized));
647 strcpy(imsi_sanitized+GSM23003_IMSI_MAX_DIGITS-strlen(argv[1]),argv[1]);
648
Harald Welte7f6da482013-03-19 11:00:13 +0100649 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200650 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100651 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200652 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100653
654 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100655 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100656 return CMD_WARNING;
657 }
658
659 return CMD_SUCCESS;
660}
661
Max93408ae2016-06-28 14:10:16 +0200662DEFUN(cfg_encrypt, cfg_encrypt_cmd,
663 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
664 "Set encryption algorithm for SGSN\n"
665 "Use GEA0 (no encryption)\n"
666 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
667{
Max93408ae2016-06-28 14:10:16 +0200668 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
Max086067f2017-05-02 13:03:28 +0200669 if (c != GPRS_ALGO_GEA0) {
670 if (!gprs_cipher_supported(c)) {
671 vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
672 return CMD_WARNING;
673 }
674
675 if (!g_cfg->require_authentication) {
676 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
677 argv[0], VTY_NEWLINE);
678 return CMD_WARNING;
679 }
Max93408ae2016-06-28 14:10:16 +0200680 }
681
682 g_cfg->cipher = c;
683
684 return CMD_SUCCESS;
685}
686
Harald Welte3dfb5492013-03-19 11:48:54 +0100687DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100688 "auth-policy (accept-all|closed|acl-only|remote)",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100689 "Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
690 " permitted to register to the network.\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100691 "Accept all IMSIs (DANGEROUS)\n"
692 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100693 "Accept only subscribers in the ACL\n"
694 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100695{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100696 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100697 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100698 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100699 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100700 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100701
702 return CMD_SUCCESS;
703}
704
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100705/* Subscriber */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +0200706#include <osmocom/sgsn/gprs_subscriber.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100707
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100708static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100709{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100710#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100711 char expire_time[200];
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100712#endif
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100713 struct gsm_auth_tuple *at;
714 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100715 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100716
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100717 vty_out(vty, " Authorized: %d%s",
718 gsub->authorized, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100719 vty_out(vty, " LAC: %d/0x%x%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100720 gsub->lac, gsub->lac, VTY_NEWLINE);
721 vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
722 if (gsub->tmsi != GSM_RESERVED_TMSI)
723 vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100724 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100725 if (gsub->sgsn_data->msisdn_len > 0)
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400726 vty_out(vty, " MSISDN (BCD): %s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100727 osmo_hexdump(gsub->sgsn_data->msisdn,
728 gsub->sgsn_data->msisdn_len),
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400729 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100730
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100731 if (strlen(gsub->imei) > 0)
732 vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100733
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100734 for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100735 at_idx++) {
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100736 at = &gsub->sgsn_data->auth_triplets[at_idx];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100737 if (at->key_seq == GSM_KEY_SEQ_INVAL)
738 continue;
739
740 vty_out(vty, " A3A8 tuple (used %d times): ",
741 at->use_count);
Harald Welte89837d42016-05-06 23:28:11 +0200742 vty_out(vty, " CKSN: %d, ",
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100743 at->key_seq);
Harald Welte89837d42016-05-06 23:28:11 +0200744 if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
745 vty_out(vty, "RAND: %s, ",
746 osmo_hexdump(at->vec.rand,
747 sizeof(at->vec.rand)));
748 vty_out(vty, "SRES: %s, ",
749 osmo_hexdump(at->vec.sres,
750 sizeof(at->vec.sres)));
751 vty_out(vty, "Kc: %s%s",
752 osmo_hexdump(at->vec.kc,
753 sizeof(at->vec.kc)), VTY_NEWLINE);
754 }
755 if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
756 vty_out(vty, " AUTN: %s, ",
757 osmo_hexdump(at->vec.autn,
758 sizeof(at->vec.autn)));
759 vty_out(vty, "RES: %s, ",
760 osmo_hexdump(at->vec.res, at->vec.res_len));
761 vty_out(vty, "IK: %s, ",
762 osmo_hexdump(at->vec.ik, sizeof(at->vec.ik)));
763 vty_out(vty, "CK: %s, ",
764 osmo_hexdump(at->vec.ck, sizeof(at->vec.ck)));
765 }
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100766 }
767
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100768 llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400769 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s' QoS: %s%s",
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100770 pdp->context_id, pdp->pdp_type, pdp->apn_str,
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400771 osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len),
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100772 VTY_NEWLINE);
773 }
774
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100775#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100776 /* print the expiration time of a subscriber */
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100777 if (gsub->expire_lu) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100778 strftime(expire_time, sizeof(expire_time),
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100779 "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100780 expire_time[sizeof(expire_time) - 1] = '\0';
781 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
782 }
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100783#endif
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100784
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100785 if (gsub->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100786 vty_out(vty, " Flags: %s%s%s%s%s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100787 gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100788 "FIRST_CONTACT " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100789 gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100790 "CANCELLED " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100791 gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100792 "UPDATE_LOCATION_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100793 gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100794 "AUTH_INFO_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100795 gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100796 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100797 VTY_NEWLINE);
798
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100799 vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100800}
801
Alexander Couzensc503f0a2018-08-07 17:50:04 +0200802DEFUN_HIDDEN(reset_sgsn_state,
803 reset_sgsn_state_cmd,
804 "reset sgsn state",
805 "Remove all known subscriber, MM ctx and flush BSSGP queues Useful when running tests against the SGSN")
806{
807 struct gprs_subscr *subscr, *tmp_subscr;
808 struct sgsn_mm_ctx *mm, *tmp_mm;
809
810 llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
811 {
812 gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
813 }
814 vty_out(vty, "Cancelled MM Ctx. %s", VTY_NEWLINE);
815
816 llist_for_each_entry_safe(subscr, tmp_subscr, gprs_subscribers, entry) {
817 gprs_subscr_get(subscr);
818 gprs_subscr_cancel(subscr);
819 gprs_subscr_put(subscr);
820 }
821 vty_out(vty, "Removed all gprs subscribers.%s", VTY_NEWLINE);
822
823 bssgp_flush_all_queues();
824 vty_out(vty, "Flushed all BSSGPs queues.%s", VTY_NEWLINE);
825
826 /* remove all queues to bssgp */
827 return CMD_SUCCESS;
828}
829
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100830DEFUN(show_subscr_cache,
831 show_subscr_cache_cmd,
832 "show subscriber cache",
833 SHOW_STR "Show information about subscribers\n"
834 "Display contents of subscriber cache\n")
835{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100836 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100837
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100838 llist_for_each_entry(subscr, gprs_subscribers, entry) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100839 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
840 subscr_dump_full_vty(vty, subscr, 0);
841 }
842
843 return CMD_SUCCESS;
844}
845
846#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
847#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
848 "Use the IMSI to select the subscriber\n" \
849 "The IMSI\n"
850
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100851#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
852
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100853DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
854 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
855 UPDATE_SUBSCR_HELP
856 UPDATE_SUBSCR_INSERT_HELP
857 "Update authentication triplet\n"
858 "Triplet index\n"
859 "Set SRES value\nSRES value (4 byte) in hex\n"
860 "Set RAND value\nRAND value (16 byte) in hex\n"
861 "Set Kc value\nKc value (8 byte) in hex\n")
862{
863 const char *imsi = argv[0];
864 const int cksn = atoi(argv[1]) - 1;
865 const char *sres_str = argv[2];
866 const char *rand_str = argv[3];
867 const char *kc_str = argv[4];
868 struct gsm_auth_tuple at = {0,};
869
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100870 struct gprs_subscr *subscr;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100871
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100872 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100873 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100874 vty_out(vty, "%% unable get subscriber record for %s%s",
875 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100876 return CMD_WARNING;
877 }
878
879 OSMO_ASSERT(subscr->sgsn_data);
880
Harald Welte121e9a42016-04-20 13:13:19 +0200881 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100882 vty_out(vty, "%% invalid SRES value '%s'%s",
883 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100884 goto failed;
885 }
Harald Welte121e9a42016-04-20 13:13:19 +0200886 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100887 vty_out(vty, "%% invalid RAND value '%s'%s",
888 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100889 goto failed;
890 }
Harald Welte121e9a42016-04-20 13:13:19 +0200891 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100892 vty_out(vty, "%% invalid Kc value '%s'%s",
893 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100894 goto failed;
895 }
896 at.key_seq = cksn;
897
898 subscr->sgsn_data->auth_triplets[cksn] = at;
899 subscr->sgsn_data->auth_triplets_updated = 1;
900
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100901 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100902
903 return CMD_SUCCESS;
904
905failed:
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100906 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100907 return CMD_SUCCESS;
908}
909
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100910DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100911 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100912 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100913 "Cancel (remove) subscriber record\n"
914 "The MS moved to another SGSN\n"
915 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100916{
917 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100918 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100919
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100920 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100921
922 subscr = gprs_subscr_get_by_imsi(imsi);
923 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100924 vty_out(vty, "%% no subscriber record for %s%s",
925 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100926 return CMD_WARNING;
927 }
928
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100929 if (strcmp(cancel_type, "update-procedure") == 0)
930 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
931 else
932 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
933
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100934 gprs_subscr_cancel(subscr);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100935 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100936
937 return CMD_SUCCESS;
938}
939
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100940DEFUN(update_subscr_create, update_subscr_create_cmd,
941 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100942 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100943 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100944{
945 const char *imsi = argv[0];
946
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100947 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100948
949 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100950 if (subscr) {
951 vty_out(vty, "%% subscriber record already exists for %s%s",
952 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100953 return CMD_WARNING;
954 }
955
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100956 subscr = gprs_subscr_get_or_create(imsi);
957 subscr->keep_in_ram = 1;
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100958 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100959
960 return CMD_SUCCESS;
961}
962
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100963DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
964 UPDATE_SUBSCR_STR "destroy",
965 UPDATE_SUBSCR_HELP
966 "Destroy a subscriber entry\n")
967{
968 const char *imsi = argv[0];
969
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100970 struct gprs_subscr *subscr;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100971
972 subscr = gprs_subscr_get_by_imsi(imsi);
973 if (!subscr) {
974 vty_out(vty, "%% subscriber record does not exist for %s%s",
975 imsi, VTY_NEWLINE);
976 return CMD_WARNING;
977 }
978
979 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100980 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100981 gprs_subscr_cancel(subscr);
982 if (subscr->use_count > 1)
983 vty_out(vty, "%% subscriber is still in use%s",
984 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100985 gprs_subscr_put(subscr);
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100986
987 return CMD_SUCCESS;
988}
989
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100990#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
991 "unknown-subscriber|roaming-not-allowed"
992
993#define UL_ERR_HELP \
994 "Force error code SystemFailure\n" \
995 "Force error code DataMissing\n" \
996 "Force error code UnexpectedDataValue\n" \
997 "Force error code UnknownSubscriber\n" \
998 "Force error code RoamingNotAllowed\n"
999
1000DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
1001 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
1002 UPDATE_SUBSCR_HELP
1003 "Complete the update location procedure\n"
1004 "The update location request succeeded\n"
1005 UL_ERR_HELP)
1006{
1007 const char *imsi = argv[0];
1008 const char *ret_code_str = argv[1];
1009
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001010 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001011
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001012 const struct value_string cause_mapping[] = {
1013 { GMM_CAUSE_NET_FAIL, "system-failure" },
1014 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
1015 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
1016 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
1017 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
1018 { 0, NULL }
1019 };
1020
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001021 subscr = gprs_subscr_get_by_imsi(imsi);
1022 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001023 vty_out(vty, "%% unable to get subscriber record for %s%s",
1024 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001025 return CMD_WARNING;
1026 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001027
1028 if (strcmp(ret_code_str, "ok") == 0) {
1029 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001030 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001031 } else {
1032 subscr->sgsn_data->error_cause =
1033 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001034 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001035 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001036
1037 gprs_subscr_update(subscr);
1038
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001039 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001040
1041 return CMD_SUCCESS;
1042}
1043
1044DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
1045 UPDATE_SUBSCR_STR "update-auth-info",
1046 UPDATE_SUBSCR_HELP
1047 "Complete the send authentication info procedure\n")
1048{
1049 const char *imsi = argv[0];
1050
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001051 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001052
1053 subscr = gprs_subscr_get_by_imsi(imsi);
1054 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001055 vty_out(vty, "%% unable to get subscriber record for %s%s",
1056 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001057 return CMD_WARNING;
1058 }
1059
1060 gprs_subscr_update_auth_info(subscr);
1061
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001062 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001063
1064 return CMD_SUCCESS;
1065}
1066
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001067DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
1068 "gsup remote-ip A.B.C.D",
1069 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001070 "Set the IP address of the remote GSUP server (e.g. OsmoHLR)."
1071 " This setting only applies if 'auth-policy remote' is used.\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001072 "IPv4 Address\n")
1073{
1074 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
1075
1076 return CMD_SUCCESS;
1077}
1078
1079DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
1080 "gsup remote-port <0-65535>",
1081 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001082 "Set the TCP port of the remote GSUP server, see also 'gsup remote-ip'\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001083 "Remote TCP port\n")
1084{
1085 g_cfg->gsup_server_port = atoi(argv[0]);
1086
1087 return CMD_SUCCESS;
1088}
1089
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001090DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
1091 "gsup oap-id <0-65535>",
1092 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001093 "Set the OAP client ID for authentication on the GSUP protocol."
1094 " This setting only applies if 'auth-policy remote' is used.\n"
1095 "OAP client ID (0 == disabled)\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001096{
1097 /* VTY ensures range */
1098 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
1099 return CMD_SUCCESS;
1100}
1101
1102DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
1103 "gsup oap-k K",
1104 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001105 "Set the OAP shared secret key K for authentication on the GSUP protocol."
1106 " This setting only applies if auth-policy remote is used.\n"
1107 "K value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001108{
1109 const char *k = argv[0];
1110
1111 g_cfg->oap.secret_k_present = 0;
1112
1113 if ((!k) || (strlen(k) == 0))
1114 goto disable;
1115
1116 int k_len = osmo_hexparse(k,
1117 g_cfg->oap.secret_k,
1118 sizeof(g_cfg->oap.secret_k));
1119 if (k_len != 16) {
1120 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
1121 k_len, VTY_NEWLINE);
1122 goto disable;
1123 }
1124
1125 g_cfg->oap.secret_k_present = 1;
1126 return CMD_SUCCESS;
1127
1128disable:
1129 if (g_cfg->oap.client_id > 0) {
1130 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
1131 VTY_NEWLINE);
1132 return CMD_WARNING;
1133 }
1134 return CMD_SUCCESS;
1135}
1136
1137DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1138 "gsup oap-opc OPC",
1139 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001140 "Set the OAP shared secret OPC for authentication on the GSUP protocol."
1141 " This setting only applies if auth-policy remote is used.\n"
1142 "OPC value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001143{
1144 const char *opc = argv[0];
1145
1146 g_cfg->oap.secret_opc_present = 0;
1147
1148 if ((!opc) || (strlen(opc) == 0))
1149 goto disable;
1150
1151 int opc_len = osmo_hexparse(opc,
1152 g_cfg->oap.secret_opc,
1153 sizeof(g_cfg->oap.secret_opc));
1154 if (opc_len != 16) {
1155 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1156 opc_len, VTY_NEWLINE);
1157 goto disable;
1158 }
1159
1160 g_cfg->oap.secret_opc_present = 1;
1161 return CMD_SUCCESS;
1162
1163disable:
1164 if (g_cfg->oap.client_id > 0) {
1165 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1166 VTY_NEWLINE);
1167 return CMD_WARNING;
1168 }
1169 return CMD_SUCCESS;
1170}
1171
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001172DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1173 "access-point-name NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001174 "Globally allow the given APN name for all subscribers.\n"
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001175 "Add this NAME to the list\n")
1176{
1177 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1178}
1179
1180DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1181 "no access-point-name NAME",
1182 NO_STR "Configure a global list of allowed APNs\n"
1183 "Remove entry with NAME\n")
1184{
1185 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1186 if (!apn_ctx)
1187 return CMD_SUCCESS;
1188
1189 sgsn_apn_ctx_free(apn_ctx);
1190 return CMD_SUCCESS;
1191}
1192
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001193DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1194 "cdr filename NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001195 "CDR\n"
1196 "Set the file name for the call-data-record file, logging the data usage of each subscriber.\n"
1197 "filename\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001198{
1199 talloc_free(g_cfg->cdr.filename);
1200 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1201 return CMD_SUCCESS;
1202}
1203
1204DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1205 "no cdr filename",
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001206 NO_STR "CDR\nDisable saving CDR to file\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001207{
1208 talloc_free(g_cfg->cdr.filename);
1209 g_cfg->cdr.filename = NULL;
1210 return CMD_SUCCESS;
1211}
1212
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001213DEFUN(cfg_cdr_trap, cfg_cdr_trap_cmd,
1214 "cdr trap",
1215 "CDR\nEnable sending CDR via TRAP CTRL messages\n")
1216{
1217 g_cfg->cdr.trap = true;
1218 return CMD_SUCCESS;
1219}
1220
1221DEFUN(cfg_no_cdr_trap, cfg_no_cdr_trap_cmd,
1222 "no cdr trap",
1223 NO_STR "CDR\nDisable sending CDR via TRAP CTRL messages\n")
1224{
1225 g_cfg->cdr.trap = false;
1226 return CMD_SUCCESS;
1227}
1228
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001229DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1230 "cdr interval <1-2147483647>",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001231 "CDR\n"
1232 "Set the interval for the call-data-record file\n"
1233 "interval in seconds\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001234{
1235 g_cfg->cdr.interval = atoi(argv[0]);
1236 return CMD_SUCCESS;
1237}
1238
Philippf1f34362016-08-26 17:00:21 +02001239#define COMPRESSION_STR "Configure compression\n"
1240DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1241 "no compression rfc1144",
1242 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1243{
1244 g_cfg->pcomp_rfc1144.active = 0;
1245 g_cfg->pcomp_rfc1144.passive = 0;
1246 return CMD_SUCCESS;
1247}
1248
1249DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1250 "compression rfc1144 active slots <1-256>",
1251 COMPRESSION_STR
1252 "RFC1144 Header compresion scheme\n"
1253 "Compression is actively proposed\n"
1254 "Number of compression state slots\n"
1255 "Number of compression state slots\n")
1256{
1257 g_cfg->pcomp_rfc1144.active = 1;
1258 g_cfg->pcomp_rfc1144.passive = 1;
1259 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1260 return CMD_SUCCESS;
1261}
1262
1263DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1264 "compression rfc1144 passive",
1265 COMPRESSION_STR
1266 "RFC1144 Header compresion scheme\n"
1267 "Compression is available on request\n")
1268{
1269 g_cfg->pcomp_rfc1144.active = 0;
1270 g_cfg->pcomp_rfc1144.passive = 1;
1271 return CMD_SUCCESS;
1272}
1273
Philipp73f83d52016-09-02 13:38:01 +02001274DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
1275 "no compression v42bis",
1276 NO_STR COMPRESSION_STR "disable V.42bis data compression\n")
1277{
1278 g_cfg->dcomp_v42bis.active = 0;
1279 g_cfg->dcomp_v42bis.passive = 0;
1280 return CMD_SUCCESS;
1281}
1282
1283DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
1284 "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
1285 COMPRESSION_STR
1286 "V.42bis data compresion scheme\n"
1287 "Compression is actively proposed\n"
1288 "Direction in which the compression shall be active (p0)\n"
1289 "Compress ms->sgsn direction only\n"
1290 "Compress sgsn->ms direction only\n"
1291 "Both directions\n"
1292 "Number of codewords (p1)\n"
1293 "Number of codewords\n"
1294 "Maximum string length (p2)\n" "Maximum string length\n")
1295{
1296 g_cfg->dcomp_v42bis.active = 1;
1297 g_cfg->dcomp_v42bis.passive = 1;
1298
1299 switch (argv[0][0]) {
1300 case 'm':
1301 g_cfg->dcomp_v42bis.p0 = 1;
1302 break;
1303 case 's':
1304 g_cfg->dcomp_v42bis.p0 = 2;
1305 break;
1306 case 'b':
1307 g_cfg->dcomp_v42bis.p0 = 3;
1308 break;
1309 }
1310
1311 g_cfg->dcomp_v42bis.p1 = atoi(argv[1]);
1312 g_cfg->dcomp_v42bis.p2 = atoi(argv[2]);
1313 return CMD_SUCCESS;
1314}
1315
1316DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
1317 "compression v42bis passive",
1318 COMPRESSION_STR
1319 "V.42bis data compresion scheme\n"
1320 "Compression is available on request\n")
1321{
1322 g_cfg->dcomp_v42bis.active = 0;
1323 g_cfg->dcomp_v42bis.passive = 1;
1324 return CMD_SUCCESS;
1325}
1326
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001327int sgsn_vty_init(struct sgsn_config *cfg)
Harald Welte288be162010-05-01 16:48:27 +02001328{
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001329 g_cfg = cfg;
1330
Harald Welted193cb32010-05-17 22:58:03 +02001331 install_element_ve(&show_sgsn_cmd);
1332 //install_element_ve(&show_mmctx_tlli_cmd);
1333 install_element_ve(&show_mmctx_imsi_cmd);
1334 install_element_ve(&show_mmctx_all_cmd);
1335 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001336 install_element_ve(&show_subscr_cache_cmd);
1337
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001338 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001339 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001340 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001341 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001342 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1343 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Alexander Couzensc503f0a2018-08-07 17:50:04 +02001344 install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001345
1346 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1347 install_node(&sgsn_node, config_write_sgsn);
Harald Weltee300d002010-06-02 12:41:34 +02001348 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001349 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1350 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1351 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +02001352 install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +02001353 install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001354 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001355 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Max93408ae2016-06-28 14:10:16 +02001356 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001357 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1358 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001359 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1360 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1361 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001362 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1363 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001364 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1365 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001366 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1367 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001368 install_element(SGSN_NODE, &cfg_cdr_trap_cmd);
1369 install_element(SGSN_NODE, &cfg_no_cdr_trap_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001370 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001371 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001372 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001373
Harald Welte94508822015-08-15 19:08:21 +02001374 install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd);
1375 install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd);
1376 install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd);
1377 install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd);
1378 install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd);
1379 install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd);
1380 install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd);
1381 install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd);
1382 install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd);
1383 install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd);
1384 install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd);
1385 install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd);
1386
Philippf1f34362016-08-26 17:00:21 +02001387 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1388 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1389 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
Philipp73f83d52016-09-02 13:38:01 +02001390 install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd);
1391 install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
1392 install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001393
1394#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +02001395 ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001396#endif
Harald Welte288be162010-05-01 16:48:27 +02001397 return 0;
1398}
1399
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001400int sgsn_parse_config(const char *config_file)
Harald Welte288be162010-05-01 16:48:27 +02001401{
1402 int rc;
1403
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001404 /* make sure sgsn_vty_init() was called before this */
1405 OSMO_ASSERT(g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +01001406
Harald Welte94508822015-08-15 19:08:21 +02001407 g_cfg->timers.T3312 = GSM0408_T3312_SECS;
1408 g_cfg->timers.T3322 = GSM0408_T3322_SECS;
1409 g_cfg->timers.T3350 = GSM0408_T3350_SECS;
1410 g_cfg->timers.T3360 = GSM0408_T3360_SECS;
1411 g_cfg->timers.T3370 = GSM0408_T3370_SECS;
1412 g_cfg->timers.T3313 = GSM0408_T3313_SECS;
1413 g_cfg->timers.T3314 = GSM0408_T3314_SECS;
1414 g_cfg->timers.T3316 = GSM0408_T3316_SECS;
1415 g_cfg->timers.T3385 = GSM0408_T3385_SECS;
1416 g_cfg->timers.T3386 = GSM0408_T3386_SECS;
1417 g_cfg->timers.T3395 = GSM0408_T3395_SECS;
1418 g_cfg->timers.T3397 = GSM0408_T3397_SECS;
1419
Harald Weltedcccb182010-05-16 20:52:23 +02001420 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001421 if (rc < 0) {
1422 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1423 return rc;
1424 }
1425
Neels Hofmeyr27355c92017-02-24 06:28:31 +01001426 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE
1427 && !(g_cfg->gsup_server_addr.sin_addr.s_addr
1428 && g_cfg->gsup_server_port)) {
1429 fprintf(stderr, "Configuration error:"
1430 " 'auth-policy remote' requires both"
1431 " 'gsup remote-ip' and 'gsup remote-port'\n");
1432 return -EINVAL;
1433 }
1434
Harald Welte288be162010-05-01 16:48:27 +02001435 return 0;
1436}