blob: 8092158fa8dbf493aa367e34b91e9d4a32f18826 [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>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020037#include <osmocom/sgsn/gprs_sgsn.h>
38#include <osmocom/sgsn/vty.h>
39#include <osmocom/sgsn/gsup_client.h>
Harald Welte288be162010-05-01 16:48:27 +020040
Harald Welte4b037e42010-05-19 19:45:32 +020041#include <osmocom/vty/command.h>
42#include <osmocom/vty/vty.h>
Pablo Neira Ayuso6110a3f2011-03-28 19:35:00 +020043#include <osmocom/vty/misc.h>
Max93408ae2016-06-28 14:10:16 +020044#include <osmocom/crypt/gprs_cipher.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010045#include <osmocom/abis/ipa.h>
46
Harald Welted193cb32010-05-17 22:58:03 +020047#include <pdp.h>
Maxbaabc682017-10-20 13:39:57 +020048#include <gtp.h>
Harald Welted193cb32010-05-17 22:58:03 +020049
Neels Hofmeyr2188a772016-05-20 21:59:55 +020050#include "../../bscconfig.h"
51
52#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +020053#include <osmocom/ranap/iu_client.h>
Neels Hofmeyr2188a772016-05-20 21:59:55 +020054#endif
55
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020056extern void *tall_bsc_ctx;
57
Harald Welte288be162010-05-01 16:48:27 +020058static struct sgsn_config *g_cfg = NULL;
59
Jacob Erlbeck106f5472014-11-04 10:08:37 +010060const struct value_string sgsn_auth_pol_strs[] = {
61 { SGSN_AUTH_POLICY_OPEN, "accept-all" },
62 { SGSN_AUTH_POLICY_CLOSED, "closed" },
63 { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" },
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +010064 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeck106f5472014-11-04 10:08:37 +010065 { 0, NULL }
66};
67
Harald Welte94508822015-08-15 19:08:21 +020068/* Section 11.2.2 / Table 11.3a GPRS Mobility management timers – MS side */
69#define GSM0408_T3312_SECS (10*60) /* periodic RAU interval, default 54min */
70
71/* Section 11.2.2 / Table 11.4 MM timers netwokr side */
72#define GSM0408_T3322_SECS 6 /* DETACH_REQ -> DETACH_ACC */
73#define GSM0408_T3350_SECS 6 /* waiting for ATT/RAU/TMSI COMPL */
74#define GSM0408_T3360_SECS 6 /* waiting for AUTH/CIPH RESP */
75#define GSM0408_T3370_SECS 6 /* waiting for ID RESP */
76
Alexander Couzens5ba6fb32017-01-31 18:04:27 +010077/* Section 11.2.2 / Table 11.4a MM timers network side */
Harald Welte94508822015-08-15 19:08:21 +020078#define GSM0408_T3313_SECS 30 /* waiting for paging response */
79#define GSM0408_T3314_SECS 44 /* force to STBY on expiry, Ready timer */
80#define GSM0408_T3316_SECS 44
81
82/* Section 11.3 / Table 11.2d Timers of Session Management - network side */
83#define GSM0408_T3385_SECS 8 /* wait for ACT PDP CTX REQ */
84#define GSM0408_T3386_SECS 8 /* wait for MODIFY PDP CTX ACK */
85#define GSM0408_T3395_SECS 8 /* wait for DEACT PDP CTX ACK */
86#define GSM0408_T3397_SECS 8 /* wait for DEACT AA PDP CTX ACK */
87
88#define DECLARE_TIMER(number, doc) \
89 DEFUN(cfg_sgsn_T##number, \
90 cfg_sgsn_T##number##_cmd, \
91 "timer t" #number " <0-65535>", \
92 "Configure GPRS Timers\n" \
Holger Hans Peter Freytherfe60cfb2015-11-02 12:55:07 +010093 doc "\nTimer Value in seconds\n") \
Harald Welte94508822015-08-15 19:08:21 +020094{ \
95 int value = atoi(argv[0]); \
96 \
97 if (value < 0 || value > 65535) { \
98 vty_out(vty, "Timer value %s out of range.%s", \
99 argv[0], VTY_NEWLINE); \
100 return CMD_WARNING; \
101 } \
102 \
103 g_cfg->timers.T##number = value; \
104 return CMD_SUCCESS; \
105}
106
107DECLARE_TIMER(3312, "Periodic RA Update timer (s)")
Neels Hofmeyr65482c92015-10-19 14:37:12 +0200108DECLARE_TIMER(3322, "Detach request -> accept timer (s)")
Harald Welte94508822015-08-15 19:08:21 +0200109DECLARE_TIMER(3350, "Waiting for ATT/RAU/TMSI_COMPL timer (s)")
110DECLARE_TIMER(3360, "Waiting for AUTH/CIPH response timer (s)")
111DECLARE_TIMER(3370, "Waiting for IDENTITY response timer (s)")
112
113DECLARE_TIMER(3313, "Waiting for paging response timer (s)")
114DECLARE_TIMER(3314, "Force to STANDBY on expiry timer (s)")
Holger Hans Peter Freytherfe60cfb2015-11-02 12:55:07 +0100115DECLARE_TIMER(3316, "AA-Ready timer (s)")
Harald Welte94508822015-08-15 19:08:21 +0200116
117DECLARE_TIMER(3385, "Wait for ACT PDP CTX REQ timer (s)")
118DECLARE_TIMER(3386, "Wait for MODIFY PDP CTX ACK timer (s)")
119DECLARE_TIMER(3395, "Wait for DEACT PDP CTX ACK timer (s)")
120DECLARE_TIMER(3397, "Wait for DEACT AA PDP CTX ACK timer (s)")
121
Holger Hans Peter Freythera2730302014-03-23 18:08:26 +0100122char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200123{
124 static char str[INET6_ADDRSTRLEN + 10];
125
126 if (!pdpa || len < 2)
127 return "none";
128
129 switch (pdpa[0] & 0x0f) {
130 case PDP_TYPE_ORG_IETF:
131 switch (pdpa[1]) {
132 case PDP_TYPE_N_IETF_IPv4:
133 if (len < 2 + 4)
134 break;
135 strcpy(str, "IPv4 ");
136 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
137 return str;
138 case PDP_TYPE_N_IETF_IPv6:
139 if (len < 2 + 8)
140 break;
141 strcpy(str, "IPv6 ");
142 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
143 return str;
144 default:
145 break;
146 }
147 break;
148 case PDP_TYPE_ORG_ETSI:
149 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
150 return "PPP";
151 break;
152 default:
153 break;
154 }
155
156 return "invalid";
157}
158
Harald Welte288be162010-05-01 16:48:27 +0200159static struct cmd_node sgsn_node = {
160 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200161 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200162 1,
163};
164
165static int config_write_sgsn(struct vty *vty)
166{
Harald Welte77289c22010-05-18 14:32:29 +0200167 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100168 struct imsi_acl_entry *acl;
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100169 struct apn_ctx *actx;
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800170 struct ares_addr_node *server;
Harald Welte288be162010-05-01 16:48:27 +0200171
172 vty_out(vty, "sgsn%s", VTY_NEWLINE);
173
Harald Weltee300d002010-06-02 12:41:34 +0200174 vty_out(vty, " gtp local-ip %s%s",
175 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
176
Harald Welted193cb32010-05-17 22:58:03 +0200177 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800178 if (gctx->id == UINT32_MAX)
179 continue;
180
Harald Welteff3bde82010-05-19 15:09:09 +0200181 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200182 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200183 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200184 gctx->gtp_version, VTY_NEWLINE);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200185 if (gctx->echo_interval != -1)
186 vty_out(vty, " ggsn %u echo-interval %"PRId32"%s",
187 gctx->id, gctx->echo_interval, VTY_NEWLINE);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200188 else
189 vty_out(vty, " ggsn %u no echo-interval%s",
190 gctx->id, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200191 }
192
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800193 if (sgsn->cfg.dynamic_lookup)
194 vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE);
195
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800196 for (server = sgsn->ares_servers; server; server = server->next)
197 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
198
Max93408ae2016-06-28 14:10:16 +0200199 if (g_cfg->cipher != GPRS_ALGO_GEA0)
200 vty_out(vty, " encryption %s%s",
201 get_value_string(gprs_cipher_names, g_cfg->cipher),
202 VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100203 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
204 vty_out(vty, " gsup remote-ip %s%s",
205 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
206 if (g_cfg->gsup_server_port)
207 vty_out(vty, " gsup remote-port %d%s",
208 g_cfg->gsup_server_port, VTY_NEWLINE);
Max176b62a2016-07-04 11:09:07 +0200209 vty_out(vty, " auth-policy %s%s",
210 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
211 VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200212
213 vty_out(vty, " gsup oap-id %d%s",
214 (int)g_cfg->oap.client_id, VTY_NEWLINE);
215 if (g_cfg->oap.secret_k_present != 0)
216 vty_out(vty, " gsup oap-k %s%s",
217 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
218 VTY_NEWLINE);
219 if (g_cfg->oap.secret_opc_present != 0)
220 vty_out(vty, " gsup oap-opc %s%s",
221 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
222 VTY_NEWLINE);
223
Harald Welte7f6da482013-03-19 11:00:13 +0100224 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
225 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
226
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100227 if (llist_empty(&sgsn_apn_ctxts))
228 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
229 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
230 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200231 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100232 actx->name, actx->imsi_prefix, actx->ggsn->id,
233 VTY_NEWLINE);
234 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200235 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100236 actx->ggsn->id, VTY_NEWLINE);
237 }
238
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200239 if (g_cfg->cdr.filename)
240 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
241 else
242 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +0100243 if (g_cfg->cdr.trap)
244 vty_out(vty, " cdr trap%s", VTY_NEWLINE);
245 else
246 vty_out(vty, " no cdr trap%s", VTY_NEWLINE);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200247 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
248
Harald Welte94508822015-08-15 19:08:21 +0200249 vty_out(vty, " timer t3312 %d%s", g_cfg->timers.T3312, VTY_NEWLINE);
250 vty_out(vty, " timer t3322 %d%s", g_cfg->timers.T3322, VTY_NEWLINE);
251 vty_out(vty, " timer t3350 %d%s", g_cfg->timers.T3350, VTY_NEWLINE);
252 vty_out(vty, " timer t3360 %d%s", g_cfg->timers.T3360, VTY_NEWLINE);
253 vty_out(vty, " timer t3370 %d%s", g_cfg->timers.T3370, VTY_NEWLINE);
254 vty_out(vty, " timer t3313 %d%s", g_cfg->timers.T3313, VTY_NEWLINE);
255 vty_out(vty, " timer t3314 %d%s", g_cfg->timers.T3314, VTY_NEWLINE);
256 vty_out(vty, " timer t3316 %d%s", g_cfg->timers.T3316, VTY_NEWLINE);
257 vty_out(vty, " timer t3385 %d%s", g_cfg->timers.T3385, VTY_NEWLINE);
258 vty_out(vty, " timer t3386 %d%s", g_cfg->timers.T3386, VTY_NEWLINE);
259 vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE);
260 vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE);
261
Philippf1f34362016-08-26 17:00:21 +0200262 if (g_cfg->pcomp_rfc1144.active) {
263 vty_out(vty, " compression rfc1144 active slots %d%s",
264 g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE);
265 } else if (g_cfg->pcomp_rfc1144.passive) {
266 vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE);
267 } else
268 vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE);
269
Philipp73f83d52016-09-02 13:38:01 +0200270 if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) {
271 vty_out(vty,
272 " compression v42bis active direction sgsn codewords %d strlen %d%s",
273 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
274 VTY_NEWLINE);
275 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) {
276 vty_out(vty,
277 " compression v42bis active direction ms codewords %d strlen %d%s",
278 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
279 VTY_NEWLINE);
280 } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) {
281 vty_out(vty,
282 " compression v42bis active direction both codewords %d strlen %d%s",
283 g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2,
284 VTY_NEWLINE);
285 } else if (g_cfg->dcomp_v42bis.passive) {
286 vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE);
287 } else
288 vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
289
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200290#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +0200291 ranap_iu_vty_config_write(vty, " ");
Neels Hofmeyr2188a772016-05-20 21:59:55 +0200292#endif
293
Harald Welte288be162010-05-01 16:48:27 +0200294 return CMD_SUCCESS;
295}
296
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100297#define SGSN_STR "Configure the SGSN\n"
298#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200299
300DEFUN(cfg_sgsn, cfg_sgsn_cmd,
301 "sgsn",
302 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200303{
304 vty->node = SGSN_NODE;
305 return CMD_SUCCESS;
306}
307
Harald Weltee300d002010-06-02 12:41:34 +0200308DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
309 "gtp local-ip A.B.C.D",
310 "GTP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100311 "Set the IP address for the local GTP bind for the Gp interface (towards the GGSNs)."
312 " Note: in case you would like to run the GGSN on the same machine as the SGSN, you can not run"
313 " both on the same IP address, since both sides are specified to use the same GTP port numbers"
314 " (" OSMO_STRINGIFY_VAL(GTP1C_PORT) " and " OSMO_STRINGIFY_VAL(GTP1U_PORT) ")."
315 " For example, you could use 127.0.0.1 for the SGSN and 127.0.0.2 for the GGSN in such"
316 " situations.\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100317 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200318{
319 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
320
321 return CMD_SUCCESS;
322}
323
Harald Welted193cb32010-05-17 22:58:03 +0200324DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
325 "ggsn <0-255> remote-ip A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100326 GGSN_STR "GGSN Number\n"
327 "Configure this static GGSN to use the specified remote IP address.\n"
328 "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200329{
330 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200331 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200332
Harald Welted193cb32010-05-17 22:58:03 +0200333 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200334
Harald Welted193cb32010-05-17 22:58:03 +0200335 return CMD_SUCCESS;
336}
337
338#if 0
339DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
340 "ggsn <0-255> remote-port <0-65535>",
341 "")
342{
343 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200344 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200345 uint16_t port = atoi(argv[1]);
346
347}
348#endif
349
350DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
351 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100352 GGSN_STR "GGSN Number\n" "GTP Version\n"
353 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200354{
355 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200356 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200357
358 if (atoi(argv[1]))
359 ggc->gtp_version = 1;
360 else
361 ggc->gtp_version = 0;
362
363 return CMD_SUCCESS;
364}
365
Pau Espin Pedrolfa120102018-07-09 20:37:47 +0200366/* Seee 3GPP TS 29.060 section 7.2.1 */
367DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
368 "ggsn <0-255> echo-interval <1-36000>",
369 GGSN_STR "GGSN Number\n"
370 "Send an echo request to this static GGSN every interval.\n"
371 "Interval between echo requests in seconds.\n")
372{
373 uint32_t id = atoi(argv[0]);
374 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
375
376 ggc->echo_interval = atoi(argv[1]);
377
378 if (ggc->echo_interval < 60)
379 vty_out(vty, "%% 3GPP TS 29.060 section states inteval should " \
380 "not be lower than 60 seconds, use this value for " \
381 "testing purposes only!%s", VTY_NEWLINE);
382
383 return CMD_SUCCESS;
384}
385
Pau Espin Pedrola83850c2018-07-10 12:43:59 +0200386DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
387 "ggsn <0-255> no echo-interval",
388 GGSN_STR "GGSN Number\n"
389 NO_STR "Send an echo request to this static GGSN every interval.\n")
390{
391 uint32_t id = atoi(argv[0]);
392 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
393
394 ggc->echo_interval = -1;
395
396 return CMD_SUCCESS;
397}
398
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800399DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
400 "ggsn dynamic",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100401 GGSN_STR
402 "Enable dynamic resolving of GGSNs based on DNS resolving the APN name like in a GRX-style setup."
403 " Changing this setting requires a restart.\n")
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800404{
405 sgsn->cfg.dynamic_lookup = 1;
406 return CMD_SUCCESS;
407}
408
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800409DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
410 "grx-dns-add A.B.C.D",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100411 "Use the specified IP address for DNS-resolving the AP names to GGSN IP addresses\n"
412 "IPv4 address\n")
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800413{
414 struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node);
415 node->family = AF_INET;
416 inet_aton(argv[0], &node->addr.addr4);
417
418 node->next = sgsn->ares_servers;
419 sgsn->ares_servers = node;
420 return CMD_SUCCESS;
421}
422
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100423#define APN_STR "Configure the information per APN\n"
424#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
425
426static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
427 const char *imsi_prefix, int ggsn_id)
428{
429 struct apn_ctx *actx;
430 struct sgsn_ggsn_ctx *ggsn;
431
432 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
433 if (ggsn == NULL) {
434 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
435 ggsn_id, VTY_NEWLINE);
436 return CMD_WARNING;
437 }
438
439 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
440 if (!actx) {
441 vty_out(vty, "%% unable to create APN context for %s/%s%s",
442 apn_str, imsi_prefix, VTY_NEWLINE);
443 return CMD_WARNING;
444 }
445
446 actx->ggsn = ggsn;
447
448 return CMD_SUCCESS;
449}
450
Harald Welted193cb32010-05-17 22:58:03 +0200451DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
452 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100453 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100454 "Select the GGSN to use for the given APN gateway prefix\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100455 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200456{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100457
458 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200459}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100460
461DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
462 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
463 APN_STR APN_GW_STR
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100464 "Select the GGSN to use for the given APN gateway prefix if and only if the IMSI matches the"
465 " given prefix.\n"
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100466 "An IMSI prefix\n"
467 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
468 "The GGSN id")
469{
470
471 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
472}
Harald Welted193cb32010-05-17 22:58:03 +0200473
474const struct value_string gprs_mm_st_strs[] = {
475 { GMM_DEREGISTERED, "DEREGISTERED" },
476 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
477 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200478 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200479 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
480 { 0, NULL }
481};
482
Maxc005db72017-10-27 18:43:29 +0200483char *sgsn_gtp_ntoa(struct ul16_t *ul)
Harald Welte471ac7d2016-12-15 19:48:58 +0100484{
Max8492c202017-12-05 17:28:15 +0100485 struct in_addr ia;
486
487 if (gsna2in_addr(&ia, ul) != 0)
Harald Welte471ac7d2016-12-15 19:48:58 +0100488 return "UNKNOWN";
Max8492c202017-12-05 17:28:15 +0100489
490 return inet_ntoa(ia);
Harald Welte471ac7d2016-12-15 19:48:58 +0100491}
492
Harald Welted193cb32010-05-17 22:58:03 +0200493static void vty_dump_pdp(struct vty *vty, const char *pfx,
494 struct sgsn_pdp_ctx *pdp)
495{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200496 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welte471ac7d2016-12-15 19:48:58 +0100497 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s",
498 pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200499 if (pdp->lib) {
Max7933d962017-10-19 16:52:30 +0200500 char apnbuf[APN_MAXLEN + 1];
Harald Weltedfbd2c82017-08-13 00:56:45 +0200501 vty_out(vty, "%s APN: %s%s", pfx,
Max7933d962017-10-19 16:52:30 +0200502 osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
Harald Weltedfbd2c82017-08-13 00:56:45 +0200503 VTY_NEWLINE);
504 vty_out(vty, "%s PDP Address: %s%s", pfx,
505 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
506 VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100507 vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200508 sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200509 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200510 sgsn_gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE);
Maxb24af2b2017-12-05 17:54:42 +0100511 vty_out(vty, "%s GTPv%d Remote Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
Maxc005db72017-10-27 18:43:29 +0200512 sgsn_gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200513 vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
Maxc005db72017-10-27 18:43:29 +0200514 sgsn_gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE);
Harald Weltedfbd2c82017-08-13 00:56:45 +0200515 }
Harald Welte471ac7d2016-12-15 19:48:58 +0100516
Harald Welteefbdee92010-06-10 00:20:12 +0200517 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200518}
519
520static void vty_dump_mmctx(struct vty *vty, const char *pfx,
521 struct sgsn_mm_ctx *mm, int pdp)
522{
523 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
524 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200525 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Harald Weltef97ee042015-12-25 19:12:21 +0100526 pfx, mm->msisdn, mm->gb.tlli, mm->hlr, VTY_NEWLINE);
Neels Hofmeyr10719b72018-02-21 00:39:36 +0100527 vty_out(vty, "%s MM State: %s, Routeing Area: %s, Cell ID: %u%s",
528 pfx, get_value_string(gprs_mm_st_strs, mm->gmm_state),
529 osmo_rai_name(&mm->ra), mm->gb.cell_id, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200530
Harald Welte8acd88f2010-05-18 10:57:45 +0200531 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
532
Harald Welted193cb32010-05-17 22:58:03 +0200533 if (pdp) {
534 struct sgsn_pdp_ctx *pdp;
535
536 llist_for_each_entry(pdp, &mm->pdp_list, list)
537 vty_dump_pdp(vty, " ", pdp);
538 }
539}
540
541DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
542 SHOW_STR "Display information about the SGSN")
543{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100544 if (sgsn->gsup_client) {
545 struct ipa_client_conn *link = sgsn->gsup_client->link;
546 vty_out(vty,
547 " Remote authorization: %sconnected to %s:%d via GSUP%s",
548 sgsn->gsup_client->is_connected ? "" : "not ",
549 link->addr, link->port,
550 VTY_NEWLINE);
551 }
Maxbaabc682017-10-20 13:39:57 +0200552 if (sgsn->gsn)
553 vty_out(vty, " GSN: signalling %s, user traffic %s%s",
554 inet_ntoa(sgsn->gsn->gsnc), inet_ntoa(sgsn->gsn->gsnu), VTY_NEWLINE);
555
Harald Welted193cb32010-05-17 22:58:03 +0200556 /* FIXME: statistics */
557 return CMD_SUCCESS;
558}
559
560#define MMCTX_STR "MM Context\n"
561#define INCLUDE_PDP_STR "Include PDP Context Information\n"
562
563#if 0
564DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
565 "show mm-context tlli HEX [pdp]",
566 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
567{
568 uint32_t tlli;
569 struct sgsn_mm_ctx *mm;
570
571 tlli = strtoul(argv[0], NULL, 16);
572 mm = sgsn_mm_ctx_by_tlli(tlli);
573 if (!mm) {
574 vty_out(vty, "No MM context for TLLI %08x%s",
575 tlli, VTY_NEWLINE);
576 return CMD_WARNING;
577 }
578 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
579 return CMD_SUCCESS;
580}
581#endif
582
583DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
584 "show mm-context imsi IMSI [pdp]",
585 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
586 INCLUDE_PDP_STR)
587{
588 struct sgsn_mm_ctx *mm;
589
590 mm = sgsn_mm_ctx_by_imsi(argv[0]);
591 if (!mm) {
592 vty_out(vty, "No MM context for IMSI %s%s",
593 argv[0], VTY_NEWLINE);
594 return CMD_WARNING;
595 }
596 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
597 return CMD_SUCCESS;
598}
599
600DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
601 "show mm-context all [pdp]",
602 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
603{
604 struct sgsn_mm_ctx *mm;
605
606 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
607 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
608
609 return CMD_SUCCESS;
610}
611
Harald Welted193cb32010-05-17 22:58:03 +0200612DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
613 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100614 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200615{
616 struct sgsn_pdp_ctx *pdp;
617
618 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
619 vty_dump_pdp(vty, "", pdp);
620
621 return CMD_SUCCESS;
622}
Harald Welte288be162010-05-01 16:48:27 +0200623
Harald Welte7f6da482013-03-19 11:00:13 +0100624
625DEFUN(imsi_acl, cfg_imsi_acl_cmd,
626 "imsi-acl (add|del) IMSI",
627 "Access Control List of foreign IMSIs\n"
628 "Add IMSI to ACL\n"
629 "Remove IMSI from ACL\n"
630 "IMSI of subscriber\n")
631{
Philipp Maier6ee49d82017-02-28 16:53:07 +0100632 char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS+1];
Harald Welte7f6da482013-03-19 11:00:13 +0100633 const char *op = argv[0];
Philipp Maier6ee49d82017-02-28 16:53:07 +0100634 const char *imsi = imsi_sanitized;
Harald Welte7f6da482013-03-19 11:00:13 +0100635 int rc;
636
Philipp Maier6ee49d82017-02-28 16:53:07 +0100637 /* Sanitize IMSI */
638 if (strlen(argv[1]) > GSM23003_IMSI_MAX_DIGITS) {
639 vty_out(vty, "%% IMSI (%s) too long -- ignored!%s",
640 argv[1], VTY_NEWLINE);
641 return CMD_WARNING;
642 }
643 memset(imsi_sanitized, '0', sizeof(imsi_sanitized));
644 strcpy(imsi_sanitized+GSM23003_IMSI_MAX_DIGITS-strlen(argv[1]),argv[1]);
645
Harald Welte7f6da482013-03-19 11:00:13 +0100646 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200647 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100648 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200649 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100650
651 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100652 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100653 return CMD_WARNING;
654 }
655
656 return CMD_SUCCESS;
657}
658
Max93408ae2016-06-28 14:10:16 +0200659DEFUN(cfg_encrypt, cfg_encrypt_cmd,
660 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
661 "Set encryption algorithm for SGSN\n"
662 "Use GEA0 (no encryption)\n"
663 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
664{
Max93408ae2016-06-28 14:10:16 +0200665 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
Max086067f2017-05-02 13:03:28 +0200666 if (c != GPRS_ALGO_GEA0) {
667 if (!gprs_cipher_supported(c)) {
668 vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
669 return CMD_WARNING;
670 }
671
672 if (!g_cfg->require_authentication) {
673 vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
674 argv[0], VTY_NEWLINE);
675 return CMD_WARNING;
676 }
Max93408ae2016-06-28 14:10:16 +0200677 }
678
679 g_cfg->cipher = c;
680
681 return CMD_SUCCESS;
682}
683
Harald Welte3dfb5492013-03-19 11:48:54 +0100684DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100685 "auth-policy (accept-all|closed|acl-only|remote)",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +0100686 "Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
687 " permitted to register to the network.\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100688 "Accept all IMSIs (DANGEROUS)\n"
689 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100690 "Accept only subscribers in the ACL\n"
691 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100692{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100693 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100694 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100695 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100696 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100697 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100698
699 return CMD_SUCCESS;
700}
701
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100702/* Subscriber */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +0200703#include <osmocom/sgsn/gprs_subscriber.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100704
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100705static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100706{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100707#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100708 char expire_time[200];
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100709#endif
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100710 struct gsm_auth_tuple *at;
711 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100712 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100713
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100714 vty_out(vty, " Authorized: %d%s",
715 gsub->authorized, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100716 vty_out(vty, " LAC: %d/0x%x%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100717 gsub->lac, gsub->lac, VTY_NEWLINE);
718 vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
719 if (gsub->tmsi != GSM_RESERVED_TMSI)
720 vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100721 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100722 if (gsub->sgsn_data->msisdn_len > 0)
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400723 vty_out(vty, " MSISDN (BCD): %s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100724 osmo_hexdump(gsub->sgsn_data->msisdn,
725 gsub->sgsn_data->msisdn_len),
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400726 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100727
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100728 if (strlen(gsub->imei) > 0)
729 vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100730
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100731 for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100732 at_idx++) {
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100733 at = &gsub->sgsn_data->auth_triplets[at_idx];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100734 if (at->key_seq == GSM_KEY_SEQ_INVAL)
735 continue;
736
737 vty_out(vty, " A3A8 tuple (used %d times): ",
738 at->use_count);
Harald Welte89837d42016-05-06 23:28:11 +0200739 vty_out(vty, " CKSN: %d, ",
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100740 at->key_seq);
Harald Welte89837d42016-05-06 23:28:11 +0200741 if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
742 vty_out(vty, "RAND: %s, ",
743 osmo_hexdump(at->vec.rand,
744 sizeof(at->vec.rand)));
745 vty_out(vty, "SRES: %s, ",
746 osmo_hexdump(at->vec.sres,
747 sizeof(at->vec.sres)));
748 vty_out(vty, "Kc: %s%s",
749 osmo_hexdump(at->vec.kc,
750 sizeof(at->vec.kc)), VTY_NEWLINE);
751 }
752 if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
753 vty_out(vty, " AUTN: %s, ",
754 osmo_hexdump(at->vec.autn,
755 sizeof(at->vec.autn)));
756 vty_out(vty, "RES: %s, ",
757 osmo_hexdump(at->vec.res, at->vec.res_len));
758 vty_out(vty, "IK: %s, ",
759 osmo_hexdump(at->vec.ik, sizeof(at->vec.ik)));
760 vty_out(vty, "CK: %s, ",
761 osmo_hexdump(at->vec.ck, sizeof(at->vec.ck)));
762 }
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100763 }
764
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100765 llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400766 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s' QoS: %s%s",
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100767 pdp->context_id, pdp->pdp_type, pdp->apn_str,
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400768 osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len),
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100769 VTY_NEWLINE);
770 }
771
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100772#if 0
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100773 /* print the expiration time of a subscriber */
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100774 if (gsub->expire_lu) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100775 strftime(expire_time, sizeof(expire_time),
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100776 "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100777 expire_time[sizeof(expire_time) - 1] = '\0';
778 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
779 }
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100780#endif
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100781
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100782 if (gsub->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100783 vty_out(vty, " Flags: %s%s%s%s%s%s",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100784 gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100785 "FIRST_CONTACT " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100786 gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100787 "CANCELLED " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100788 gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100789 "UPDATE_LOCATION_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100790 gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100791 "AUTH_INFO_PENDING " : "",
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100792 gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100793 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100794 VTY_NEWLINE);
795
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100796 vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100797}
798
799DEFUN(show_subscr_cache,
800 show_subscr_cache_cmd,
801 "show subscriber cache",
802 SHOW_STR "Show information about subscribers\n"
803 "Display contents of subscriber cache\n")
804{
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100805 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100806
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100807 llist_for_each_entry(subscr, gprs_subscribers, entry) {
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100808 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
809 subscr_dump_full_vty(vty, subscr, 0);
810 }
811
812 return CMD_SUCCESS;
813}
814
815#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
816#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
817 "Use the IMSI to select the subscriber\n" \
818 "The IMSI\n"
819
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100820#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
821
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100822DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
823 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
824 UPDATE_SUBSCR_HELP
825 UPDATE_SUBSCR_INSERT_HELP
826 "Update authentication triplet\n"
827 "Triplet index\n"
828 "Set SRES value\nSRES value (4 byte) in hex\n"
829 "Set RAND value\nRAND value (16 byte) in hex\n"
830 "Set Kc value\nKc value (8 byte) in hex\n")
831{
832 const char *imsi = argv[0];
833 const int cksn = atoi(argv[1]) - 1;
834 const char *sres_str = argv[2];
835 const char *rand_str = argv[3];
836 const char *kc_str = argv[4];
837 struct gsm_auth_tuple at = {0,};
838
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100839 struct gprs_subscr *subscr;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100840
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100841 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100842 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100843 vty_out(vty, "%% unable get subscriber record for %s%s",
844 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100845 return CMD_WARNING;
846 }
847
848 OSMO_ASSERT(subscr->sgsn_data);
849
Harald Welte121e9a42016-04-20 13:13:19 +0200850 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100851 vty_out(vty, "%% invalid SRES value '%s'%s",
852 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100853 goto failed;
854 }
Harald Welte121e9a42016-04-20 13:13:19 +0200855 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100856 vty_out(vty, "%% invalid RAND value '%s'%s",
857 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100858 goto failed;
859 }
Harald Welte121e9a42016-04-20 13:13:19 +0200860 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100861 vty_out(vty, "%% invalid Kc value '%s'%s",
862 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100863 goto failed;
864 }
865 at.key_seq = cksn;
866
867 subscr->sgsn_data->auth_triplets[cksn] = at;
868 subscr->sgsn_data->auth_triplets_updated = 1;
869
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100870 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100871
872 return CMD_SUCCESS;
873
874failed:
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100875 gprs_subscr_put(subscr);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100876 return CMD_SUCCESS;
877}
878
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100879DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100880 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100881 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100882 "Cancel (remove) subscriber record\n"
883 "The MS moved to another SGSN\n"
884 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100885{
886 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100887 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100888
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100889 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100890
891 subscr = gprs_subscr_get_by_imsi(imsi);
892 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100893 vty_out(vty, "%% no subscriber record for %s%s",
894 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100895 return CMD_WARNING;
896 }
897
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100898 if (strcmp(cancel_type, "update-procedure") == 0)
899 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
900 else
901 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
902
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100903 gprs_subscr_cancel(subscr);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100904 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100905
906 return CMD_SUCCESS;
907}
908
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100909DEFUN(update_subscr_create, update_subscr_create_cmd,
910 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100911 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100912 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100913{
914 const char *imsi = argv[0];
915
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100916 struct gprs_subscr *subscr;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100917
918 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100919 if (subscr) {
920 vty_out(vty, "%% subscriber record already exists for %s%s",
921 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100922 return CMD_WARNING;
923 }
924
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100925 subscr = gprs_subscr_get_or_create(imsi);
926 subscr->keep_in_ram = 1;
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100927 gprs_subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100928
929 return CMD_SUCCESS;
930}
931
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100932DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
933 UPDATE_SUBSCR_STR "destroy",
934 UPDATE_SUBSCR_HELP
935 "Destroy a subscriber entry\n")
936{
937 const char *imsi = argv[0];
938
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100939 struct gprs_subscr *subscr;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100940
941 subscr = gprs_subscr_get_by_imsi(imsi);
942 if (!subscr) {
943 vty_out(vty, "%% subscriber record does not exist for %s%s",
944 imsi, VTY_NEWLINE);
945 return CMD_WARNING;
946 }
947
948 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100949 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100950 gprs_subscr_cancel(subscr);
951 if (subscr->use_count > 1)
952 vty_out(vty, "%% subscriber is still in use%s",
953 VTY_NEWLINE);
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100954 gprs_subscr_put(subscr);
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100955
956 return CMD_SUCCESS;
957}
958
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100959#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
960 "unknown-subscriber|roaming-not-allowed"
961
962#define UL_ERR_HELP \
963 "Force error code SystemFailure\n" \
964 "Force error code DataMissing\n" \
965 "Force error code UnexpectedDataValue\n" \
966 "Force error code UnknownSubscriber\n" \
967 "Force error code RoamingNotAllowed\n"
968
969DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
970 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
971 UPDATE_SUBSCR_HELP
972 "Complete the update location procedure\n"
973 "The update location request succeeded\n"
974 UL_ERR_HELP)
975{
976 const char *imsi = argv[0];
977 const char *ret_code_str = argv[1];
978
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +0100979 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100980
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100981 const struct value_string cause_mapping[] = {
982 { GMM_CAUSE_NET_FAIL, "system-failure" },
983 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
984 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
985 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
986 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
987 { 0, NULL }
988 };
989
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100990 subscr = gprs_subscr_get_by_imsi(imsi);
991 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100992 vty_out(vty, "%% unable to get subscriber record for %s%s",
993 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100994 return CMD_WARNING;
995 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100996
997 if (strcmp(ret_code_str, "ok") == 0) {
998 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100999 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001000 } else {
1001 subscr->sgsn_data->error_cause =
1002 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001003 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +01001004 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001005
1006 gprs_subscr_update(subscr);
1007
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001008 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001009
1010 return CMD_SUCCESS;
1011}
1012
1013DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
1014 UPDATE_SUBSCR_STR "update-auth-info",
1015 UPDATE_SUBSCR_HELP
1016 "Complete the send authentication info procedure\n")
1017{
1018 const char *imsi = argv[0];
1019
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001020 struct gprs_subscr *subscr;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001021
1022 subscr = gprs_subscr_get_by_imsi(imsi);
1023 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +01001024 vty_out(vty, "%% unable to get subscriber record for %s%s",
1025 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001026 return CMD_WARNING;
1027 }
1028
1029 gprs_subscr_update_auth_info(subscr);
1030
Neels Hofmeyr0e5d8072017-01-10 00:49:56 +01001031 gprs_subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001032
1033 return CMD_SUCCESS;
1034}
1035
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001036DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
1037 "gsup remote-ip A.B.C.D",
1038 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001039 "Set the IP address of the remote GSUP server (e.g. OsmoHLR)."
1040 " This setting only applies if 'auth-policy remote' is used.\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001041 "IPv4 Address\n")
1042{
1043 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
1044
1045 return CMD_SUCCESS;
1046}
1047
1048DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
1049 "gsup remote-port <0-65535>",
1050 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001051 "Set the TCP port of the remote GSUP server, see also 'gsup remote-ip'\n"
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001052 "Remote TCP port\n")
1053{
1054 g_cfg->gsup_server_port = atoi(argv[0]);
1055
1056 return CMD_SUCCESS;
1057}
1058
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001059DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
1060 "gsup oap-id <0-65535>",
1061 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001062 "Set the OAP client ID for authentication on the GSUP protocol."
1063 " This setting only applies if 'auth-policy remote' is used.\n"
1064 "OAP client ID (0 == disabled)\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001065{
1066 /* VTY ensures range */
1067 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
1068 return CMD_SUCCESS;
1069}
1070
1071DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
1072 "gsup oap-k K",
1073 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001074 "Set the OAP shared secret key K for authentication on the GSUP protocol."
1075 " This setting only applies if auth-policy remote is used.\n"
1076 "K value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001077{
1078 const char *k = argv[0];
1079
1080 g_cfg->oap.secret_k_present = 0;
1081
1082 if ((!k) || (strlen(k) == 0))
1083 goto disable;
1084
1085 int k_len = osmo_hexparse(k,
1086 g_cfg->oap.secret_k,
1087 sizeof(g_cfg->oap.secret_k));
1088 if (k_len != 16) {
1089 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
1090 k_len, VTY_NEWLINE);
1091 goto disable;
1092 }
1093
1094 g_cfg->oap.secret_k_present = 1;
1095 return CMD_SUCCESS;
1096
1097disable:
1098 if (g_cfg->oap.client_id > 0) {
1099 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
1100 VTY_NEWLINE);
1101 return CMD_WARNING;
1102 }
1103 return CMD_SUCCESS;
1104}
1105
1106DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1107 "gsup oap-opc OPC",
1108 "GSUP Parameters\n"
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001109 "Set the OAP shared secret OPC for authentication on the GSUP protocol."
1110 " This setting only applies if auth-policy remote is used.\n"
1111 "OPC value (16 byte) hex\n")
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001112{
1113 const char *opc = argv[0];
1114
1115 g_cfg->oap.secret_opc_present = 0;
1116
1117 if ((!opc) || (strlen(opc) == 0))
1118 goto disable;
1119
1120 int opc_len = osmo_hexparse(opc,
1121 g_cfg->oap.secret_opc,
1122 sizeof(g_cfg->oap.secret_opc));
1123 if (opc_len != 16) {
1124 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1125 opc_len, VTY_NEWLINE);
1126 goto disable;
1127 }
1128
1129 g_cfg->oap.secret_opc_present = 1;
1130 return CMD_SUCCESS;
1131
1132disable:
1133 if (g_cfg->oap.client_id > 0) {
1134 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1135 VTY_NEWLINE);
1136 return CMD_WARNING;
1137 }
1138 return CMD_SUCCESS;
1139}
1140
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001141DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1142 "access-point-name NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001143 "Globally allow the given APN name for all subscribers.\n"
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001144 "Add this NAME to the list\n")
1145{
1146 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1147}
1148
1149DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1150 "no access-point-name NAME",
1151 NO_STR "Configure a global list of allowed APNs\n"
1152 "Remove entry with NAME\n")
1153{
1154 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1155 if (!apn_ctx)
1156 return CMD_SUCCESS;
1157
1158 sgsn_apn_ctx_free(apn_ctx);
1159 return CMD_SUCCESS;
1160}
1161
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001162DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1163 "cdr filename NAME",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001164 "CDR\n"
1165 "Set the file name for the call-data-record file, logging the data usage of each subscriber.\n"
1166 "filename\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001167{
1168 talloc_free(g_cfg->cdr.filename);
1169 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1170 return CMD_SUCCESS;
1171}
1172
1173DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1174 "no cdr filename",
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001175 NO_STR "CDR\nDisable saving CDR to file\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001176{
1177 talloc_free(g_cfg->cdr.filename);
1178 g_cfg->cdr.filename = NULL;
1179 return CMD_SUCCESS;
1180}
1181
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001182DEFUN(cfg_cdr_trap, cfg_cdr_trap_cmd,
1183 "cdr trap",
1184 "CDR\nEnable sending CDR via TRAP CTRL messages\n")
1185{
1186 g_cfg->cdr.trap = true;
1187 return CMD_SUCCESS;
1188}
1189
1190DEFUN(cfg_no_cdr_trap, cfg_no_cdr_trap_cmd,
1191 "no cdr trap",
1192 NO_STR "CDR\nDisable sending CDR via TRAP CTRL messages\n")
1193{
1194 g_cfg->cdr.trap = false;
1195 return CMD_SUCCESS;
1196}
1197
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001198DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1199 "cdr interval <1-2147483647>",
Neels Hofmeyr24bb7472018-03-06 16:14:26 +01001200 "CDR\n"
1201 "Set the interval for the call-data-record file\n"
1202 "interval in seconds\n")
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001203{
1204 g_cfg->cdr.interval = atoi(argv[0]);
1205 return CMD_SUCCESS;
1206}
1207
Philippf1f34362016-08-26 17:00:21 +02001208#define COMPRESSION_STR "Configure compression\n"
1209DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1210 "no compression rfc1144",
1211 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1212{
1213 g_cfg->pcomp_rfc1144.active = 0;
1214 g_cfg->pcomp_rfc1144.passive = 0;
1215 return CMD_SUCCESS;
1216}
1217
1218DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1219 "compression rfc1144 active slots <1-256>",
1220 COMPRESSION_STR
1221 "RFC1144 Header compresion scheme\n"
1222 "Compression is actively proposed\n"
1223 "Number of compression state slots\n"
1224 "Number of compression state slots\n")
1225{
1226 g_cfg->pcomp_rfc1144.active = 1;
1227 g_cfg->pcomp_rfc1144.passive = 1;
1228 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1229 return CMD_SUCCESS;
1230}
1231
1232DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1233 "compression rfc1144 passive",
1234 COMPRESSION_STR
1235 "RFC1144 Header compresion scheme\n"
1236 "Compression is available on request\n")
1237{
1238 g_cfg->pcomp_rfc1144.active = 0;
1239 g_cfg->pcomp_rfc1144.passive = 1;
1240 return CMD_SUCCESS;
1241}
1242
Philipp73f83d52016-09-02 13:38:01 +02001243DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
1244 "no compression v42bis",
1245 NO_STR COMPRESSION_STR "disable V.42bis data compression\n")
1246{
1247 g_cfg->dcomp_v42bis.active = 0;
1248 g_cfg->dcomp_v42bis.passive = 0;
1249 return CMD_SUCCESS;
1250}
1251
1252DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
1253 "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
1254 COMPRESSION_STR
1255 "V.42bis data compresion scheme\n"
1256 "Compression is actively proposed\n"
1257 "Direction in which the compression shall be active (p0)\n"
1258 "Compress ms->sgsn direction only\n"
1259 "Compress sgsn->ms direction only\n"
1260 "Both directions\n"
1261 "Number of codewords (p1)\n"
1262 "Number of codewords\n"
1263 "Maximum string length (p2)\n" "Maximum string length\n")
1264{
1265 g_cfg->dcomp_v42bis.active = 1;
1266 g_cfg->dcomp_v42bis.passive = 1;
1267
1268 switch (argv[0][0]) {
1269 case 'm':
1270 g_cfg->dcomp_v42bis.p0 = 1;
1271 break;
1272 case 's':
1273 g_cfg->dcomp_v42bis.p0 = 2;
1274 break;
1275 case 'b':
1276 g_cfg->dcomp_v42bis.p0 = 3;
1277 break;
1278 }
1279
1280 g_cfg->dcomp_v42bis.p1 = atoi(argv[1]);
1281 g_cfg->dcomp_v42bis.p2 = atoi(argv[2]);
1282 return CMD_SUCCESS;
1283}
1284
1285DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
1286 "compression v42bis passive",
1287 COMPRESSION_STR
1288 "V.42bis data compresion scheme\n"
1289 "Compression is available on request\n")
1290{
1291 g_cfg->dcomp_v42bis.active = 0;
1292 g_cfg->dcomp_v42bis.passive = 1;
1293 return CMD_SUCCESS;
1294}
1295
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001296int sgsn_vty_init(struct sgsn_config *cfg)
Harald Welte288be162010-05-01 16:48:27 +02001297{
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001298 g_cfg = cfg;
1299
Harald Welted193cb32010-05-17 22:58:03 +02001300 install_element_ve(&show_sgsn_cmd);
1301 //install_element_ve(&show_mmctx_tlli_cmd);
1302 install_element_ve(&show_mmctx_imsi_cmd);
1303 install_element_ve(&show_mmctx_all_cmd);
1304 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001305 install_element_ve(&show_subscr_cache_cmd);
1306
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001307 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001308 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001309 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001310 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001311 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1312 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001313
1314 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1315 install_node(&sgsn_node, config_write_sgsn);
Harald Weltee300d002010-06-02 12:41:34 +02001316 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001317 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1318 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1319 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Pau Espin Pedrolfa120102018-07-09 20:37:47 +02001320 install_element(SGSN_NODE, &cfg_ggsn_echo_interval_cmd);
Pau Espin Pedrola83850c2018-07-10 12:43:59 +02001321 install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001322 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001323 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Max93408ae2016-06-28 14:10:16 +02001324 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001325 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1326 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001327 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1328 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1329 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001330 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1331 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001332 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1333 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001334 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1335 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
Pau Espin Pedrol2e9ea502017-11-29 14:01:35 +01001336 install_element(SGSN_NODE, &cfg_cdr_trap_cmd);
1337 install_element(SGSN_NODE, &cfg_no_cdr_trap_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001338 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001339 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001340 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001341
Harald Welte94508822015-08-15 19:08:21 +02001342 install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd);
1343 install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd);
1344 install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd);
1345 install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd);
1346 install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd);
1347 install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd);
1348 install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd);
1349 install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd);
1350 install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd);
1351 install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd);
1352 install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd);
1353 install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd);
1354
Philippf1f34362016-08-26 17:00:21 +02001355 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1356 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1357 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
Philipp73f83d52016-09-02 13:38:01 +02001358 install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd);
1359 install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
1360 install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001361
1362#ifdef BUILD_IU
Neels Hofmeyra7a39472017-07-05 15:19:52 +02001363 ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
Neels Hofmeyr2188a772016-05-20 21:59:55 +02001364#endif
Harald Welte288be162010-05-01 16:48:27 +02001365 return 0;
1366}
1367
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001368int sgsn_parse_config(const char *config_file)
Harald Welte288be162010-05-01 16:48:27 +02001369{
1370 int rc;
1371
Neels Hofmeyrc9a352f2017-07-20 14:41:20 +02001372 /* make sure sgsn_vty_init() was called before this */
1373 OSMO_ASSERT(g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +01001374
Harald Welte94508822015-08-15 19:08:21 +02001375 g_cfg->timers.T3312 = GSM0408_T3312_SECS;
1376 g_cfg->timers.T3322 = GSM0408_T3322_SECS;
1377 g_cfg->timers.T3350 = GSM0408_T3350_SECS;
1378 g_cfg->timers.T3360 = GSM0408_T3360_SECS;
1379 g_cfg->timers.T3370 = GSM0408_T3370_SECS;
1380 g_cfg->timers.T3313 = GSM0408_T3313_SECS;
1381 g_cfg->timers.T3314 = GSM0408_T3314_SECS;
1382 g_cfg->timers.T3316 = GSM0408_T3316_SECS;
1383 g_cfg->timers.T3385 = GSM0408_T3385_SECS;
1384 g_cfg->timers.T3386 = GSM0408_T3386_SECS;
1385 g_cfg->timers.T3395 = GSM0408_T3395_SECS;
1386 g_cfg->timers.T3397 = GSM0408_T3397_SECS;
1387
Harald Weltedcccb182010-05-16 20:52:23 +02001388 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001389 if (rc < 0) {
1390 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1391 return rc;
1392 }
1393
Neels Hofmeyr27355c92017-02-24 06:28:31 +01001394 if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE
1395 && !(g_cfg->gsup_server_addr.sin_addr.s_addr
1396 && g_cfg->gsup_server_port)) {
1397 fprintf(stderr, "Configuration error:"
1398 " 'auth-policy remote' requires both"
1399 " 'gsup remote-ip' and 'gsup remote-port'\n");
1400 return -EINVAL;
1401 }
1402
Harald Welte288be162010-05-01 16:48:27 +02001403 return 0;
1404}