blob: 0eea3502936be64580dd1d40d44e7d0c92e5119d [file] [log] [blame]
Harald Welte288be162010-05-01 16:48:27 +02001/*
Harald Welte7f6da482013-03-19 11:00:13 +01002 * (C) 2010-2013 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>
Harald Welte288be162010-05-01 16:48:27 +020026
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010027#include <osmocom/core/talloc.h>
28#include <osmocom/core/utils.h>
29#include <osmocom/core/rate_ctr.h>
Harald Welte53373bc2016-04-20 17:11:43 +020030#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
Harald Welte288be162010-05-01 16:48:27 +020031
32#include <openbsc/debug.h>
33#include <openbsc/sgsn.h>
Harald Welteea34a4e2012-06-16 14:59:56 +080034#include <osmocom/gprs/gprs_ns.h>
Harald Welted193cb32010-05-17 22:58:03 +020035#include <openbsc/gprs_sgsn.h>
Harald Welte62ab20c2010-05-14 18:59:17 +020036#include <openbsc/vty.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010037#include <openbsc/gprs_gsup_client.h>
Harald Welte288be162010-05-01 16:48:27 +020038
Harald Welte4b037e42010-05-19 19:45:32 +020039#include <osmocom/vty/command.h>
40#include <osmocom/vty/vty.h>
Pablo Neira Ayuso6110a3f2011-03-28 19:35:00 +020041#include <osmocom/vty/misc.h>
Max93408ae2016-06-28 14:10:16 +020042#include <osmocom/crypt/gprs_cipher.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010043#include <osmocom/abis/ipa.h>
44
Harald Welted193cb32010-05-17 22:58:03 +020045#include <pdp.h>
46
Harald Welte288be162010-05-01 16:48:27 +020047static struct sgsn_config *g_cfg = NULL;
48
Jacob Erlbeck106f5472014-11-04 10:08:37 +010049const struct value_string sgsn_auth_pol_strs[] = {
50 { SGSN_AUTH_POLICY_OPEN, "accept-all" },
51 { SGSN_AUTH_POLICY_CLOSED, "closed" },
52 { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" },
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +010053 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeck106f5472014-11-04 10:08:37 +010054 { 0, NULL }
55};
56
Harald Welte94508822015-08-15 19:08:21 +020057/* Section 11.2.2 / Table 11.3a GPRS Mobility management timers – MS side */
58#define GSM0408_T3312_SECS (10*60) /* periodic RAU interval, default 54min */
59
60/* Section 11.2.2 / Table 11.4 MM timers netwokr side */
61#define GSM0408_T3322_SECS 6 /* DETACH_REQ -> DETACH_ACC */
62#define GSM0408_T3350_SECS 6 /* waiting for ATT/RAU/TMSI COMPL */
63#define GSM0408_T3360_SECS 6 /* waiting for AUTH/CIPH RESP */
64#define GSM0408_T3370_SECS 6 /* waiting for ID RESP */
65
66/* Section 11.2.2 / Table 11.4a MM timers netwokr side */
67#define GSM0408_T3313_SECS 30 /* waiting for paging response */
68#define GSM0408_T3314_SECS 44 /* force to STBY on expiry, Ready timer */
69#define GSM0408_T3316_SECS 44
70
71/* Section 11.3 / Table 11.2d Timers of Session Management - network side */
72#define GSM0408_T3385_SECS 8 /* wait for ACT PDP CTX REQ */
73#define GSM0408_T3386_SECS 8 /* wait for MODIFY PDP CTX ACK */
74#define GSM0408_T3395_SECS 8 /* wait for DEACT PDP CTX ACK */
75#define GSM0408_T3397_SECS 8 /* wait for DEACT AA PDP CTX ACK */
76
77#define DECLARE_TIMER(number, doc) \
78 DEFUN(cfg_sgsn_T##number, \
79 cfg_sgsn_T##number##_cmd, \
80 "timer t" #number " <0-65535>", \
81 "Configure GPRS Timers\n" \
Holger Hans Peter Freytherfe60cfb2015-11-02 12:55:07 +010082 doc "\nTimer Value in seconds\n") \
Harald Welte94508822015-08-15 19:08:21 +020083{ \
84 int value = atoi(argv[0]); \
85 \
86 if (value < 0 || value > 65535) { \
87 vty_out(vty, "Timer value %s out of range.%s", \
88 argv[0], VTY_NEWLINE); \
89 return CMD_WARNING; \
90 } \
91 \
92 g_cfg->timers.T##number = value; \
93 return CMD_SUCCESS; \
94}
95
96DECLARE_TIMER(3312, "Periodic RA Update timer (s)")
Neels Hofmeyr65482c92015-10-19 14:37:12 +020097DECLARE_TIMER(3322, "Detach request -> accept timer (s)")
Harald Welte94508822015-08-15 19:08:21 +020098DECLARE_TIMER(3350, "Waiting for ATT/RAU/TMSI_COMPL timer (s)")
99DECLARE_TIMER(3360, "Waiting for AUTH/CIPH response timer (s)")
100DECLARE_TIMER(3370, "Waiting for IDENTITY response timer (s)")
101
102DECLARE_TIMER(3313, "Waiting for paging response timer (s)")
103DECLARE_TIMER(3314, "Force to STANDBY on expiry timer (s)")
Holger Hans Peter Freytherfe60cfb2015-11-02 12:55:07 +0100104DECLARE_TIMER(3316, "AA-Ready timer (s)")
Harald Welte94508822015-08-15 19:08:21 +0200105
106DECLARE_TIMER(3385, "Wait for ACT PDP CTX REQ timer (s)")
107DECLARE_TIMER(3386, "Wait for MODIFY PDP CTX ACK timer (s)")
108DECLARE_TIMER(3395, "Wait for DEACT PDP CTX ACK timer (s)")
109DECLARE_TIMER(3397, "Wait for DEACT AA PDP CTX ACK timer (s)")
110
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100111
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200112#define GSM48_MAX_APN_LEN 102 /* 10.5.6.1 */
Neels Hofmeyr30f7bcb2015-11-08 20:34:47 +0100113/* TODO: consolidate with gprs_apn_to_str(). */
114/** Copy apn to a static buffer, replacing the length octets in apn_enc with '.'
115 * and terminating with a '\0'. Return the static buffer.
116 * len: the length of the encoded APN (which has no terminating zero).
117 */
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200118static char *gprs_apn2str(uint8_t *apn, unsigned int len)
119{
120 static char apnbuf[GSM48_MAX_APN_LEN+1];
Holger Hans Peter Freyther80e03652013-07-04 18:44:16 +0200121 unsigned int i = 0;
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200122
123 if (!apn)
124 return "";
125
126 if (len > sizeof(apnbuf)-1)
127 len = sizeof(apnbuf)-1;
128
129 memcpy(apnbuf, apn, len);
130 apnbuf[len] = '\0';
131
132 /* replace the domain name step sizes with dots */
133 while (i < len) {
134 unsigned int step = apnbuf[i];
135 apnbuf[i] = '.';
136 i += step+1;
137 }
138
139 return apnbuf+1;
140}
141
Holger Hans Peter Freythera2730302014-03-23 18:08:26 +0100142char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200143{
144 static char str[INET6_ADDRSTRLEN + 10];
145
146 if (!pdpa || len < 2)
147 return "none";
148
149 switch (pdpa[0] & 0x0f) {
150 case PDP_TYPE_ORG_IETF:
151 switch (pdpa[1]) {
152 case PDP_TYPE_N_IETF_IPv4:
153 if (len < 2 + 4)
154 break;
155 strcpy(str, "IPv4 ");
156 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
157 return str;
158 case PDP_TYPE_N_IETF_IPv6:
159 if (len < 2 + 8)
160 break;
161 strcpy(str, "IPv6 ");
162 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
163 return str;
164 default:
165 break;
166 }
167 break;
168 case PDP_TYPE_ORG_ETSI:
169 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
170 return "PPP";
171 break;
172 default:
173 break;
174 }
175
176 return "invalid";
177}
178
Harald Welte288be162010-05-01 16:48:27 +0200179static struct cmd_node sgsn_node = {
180 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200181 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200182 1,
183};
184
185static int config_write_sgsn(struct vty *vty)
186{
Harald Welte77289c22010-05-18 14:32:29 +0200187 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100188 struct imsi_acl_entry *acl;
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100189 struct apn_ctx *actx;
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800190 struct ares_addr_node *server;
Harald Welte288be162010-05-01 16:48:27 +0200191
192 vty_out(vty, "sgsn%s", VTY_NEWLINE);
193
Harald Weltee300d002010-06-02 12:41:34 +0200194 vty_out(vty, " gtp local-ip %s%s",
195 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
196
Harald Welted193cb32010-05-17 22:58:03 +0200197 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800198 if (gctx->id == UINT32_MAX)
199 continue;
200
Harald Welteff3bde82010-05-19 15:09:09 +0200201 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200202 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200203 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200204 gctx->gtp_version, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200205 }
206
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800207 if (sgsn->cfg.dynamic_lookup)
208 vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE);
209
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800210 for (server = sgsn->ares_servers; server; server = server->next)
211 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
212
Max93408ae2016-06-28 14:10:16 +0200213 if (g_cfg->cipher != GPRS_ALGO_GEA0)
214 vty_out(vty, " encryption %s%s",
215 get_value_string(gprs_cipher_names, g_cfg->cipher),
216 VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100217 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
218 vty_out(vty, " gsup remote-ip %s%s",
219 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
220 if (g_cfg->gsup_server_port)
221 vty_out(vty, " gsup remote-port %d%s",
222 g_cfg->gsup_server_port, VTY_NEWLINE);
Max176b62a2016-07-04 11:09:07 +0200223 vty_out(vty, " auth-policy %s%s",
224 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
225 VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200226
227 vty_out(vty, " gsup oap-id %d%s",
228 (int)g_cfg->oap.client_id, VTY_NEWLINE);
229 if (g_cfg->oap.secret_k_present != 0)
230 vty_out(vty, " gsup oap-k %s%s",
231 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
232 VTY_NEWLINE);
233 if (g_cfg->oap.secret_opc_present != 0)
234 vty_out(vty, " gsup oap-opc %s%s",
235 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
236 VTY_NEWLINE);
237
Harald Welte7f6da482013-03-19 11:00:13 +0100238 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
239 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
240
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100241 if (llist_empty(&sgsn_apn_ctxts))
242 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
243 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
244 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200245 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100246 actx->name, actx->imsi_prefix, actx->ggsn->id,
247 VTY_NEWLINE);
248 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200249 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100250 actx->ggsn->id, VTY_NEWLINE);
251 }
252
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200253 if (g_cfg->cdr.filename)
254 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
255 else
256 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
257 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
258
Harald Welte94508822015-08-15 19:08:21 +0200259 vty_out(vty, " timer t3312 %d%s", g_cfg->timers.T3312, VTY_NEWLINE);
260 vty_out(vty, " timer t3322 %d%s", g_cfg->timers.T3322, VTY_NEWLINE);
261 vty_out(vty, " timer t3350 %d%s", g_cfg->timers.T3350, VTY_NEWLINE);
262 vty_out(vty, " timer t3360 %d%s", g_cfg->timers.T3360, VTY_NEWLINE);
263 vty_out(vty, " timer t3370 %d%s", g_cfg->timers.T3370, VTY_NEWLINE);
264 vty_out(vty, " timer t3313 %d%s", g_cfg->timers.T3313, VTY_NEWLINE);
265 vty_out(vty, " timer t3314 %d%s", g_cfg->timers.T3314, VTY_NEWLINE);
266 vty_out(vty, " timer t3316 %d%s", g_cfg->timers.T3316, VTY_NEWLINE);
267 vty_out(vty, " timer t3385 %d%s", g_cfg->timers.T3385, VTY_NEWLINE);
268 vty_out(vty, " timer t3386 %d%s", g_cfg->timers.T3386, VTY_NEWLINE);
269 vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE);
270 vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE);
271
Philippf1f34362016-08-26 17:00:21 +0200272 if (g_cfg->pcomp_rfc1144.active) {
273 vty_out(vty, " compression rfc1144 active slots %d%s",
274 g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE);
275 } else if (g_cfg->pcomp_rfc1144.passive) {
276 vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE);
277 } else
278 vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE);
279
Harald Welte288be162010-05-01 16:48:27 +0200280 return CMD_SUCCESS;
281}
282
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100283#define SGSN_STR "Configure the SGSN\n"
284#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200285
286DEFUN(cfg_sgsn, cfg_sgsn_cmd,
287 "sgsn",
288 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200289{
290 vty->node = SGSN_NODE;
291 return CMD_SUCCESS;
292}
293
Harald Weltee300d002010-06-02 12:41:34 +0200294DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
295 "gtp local-ip A.B.C.D",
296 "GTP Parameters\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100297 "Set the IP address for the local GTP bind\n"
298 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200299{
300 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
301
302 return CMD_SUCCESS;
303}
304
Harald Welted193cb32010-05-17 22:58:03 +0200305DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
306 "ggsn <0-255> remote-ip A.B.C.D",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100307 GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200308{
309 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200310 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200311
Harald Welted193cb32010-05-17 22:58:03 +0200312 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200313
Harald Welted193cb32010-05-17 22:58:03 +0200314 return CMD_SUCCESS;
315}
316
317#if 0
318DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
319 "ggsn <0-255> remote-port <0-65535>",
320 "")
321{
322 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200323 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200324 uint16_t port = atoi(argv[1]);
325
326}
327#endif
328
329DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
330 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100331 GGSN_STR "GGSN Number\n" "GTP Version\n"
332 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200333{
334 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200335 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200336
337 if (atoi(argv[1]))
338 ggc->gtp_version = 1;
339 else
340 ggc->gtp_version = 0;
341
342 return CMD_SUCCESS;
343}
344
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800345DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
346 "ggsn dynamic",
347 GGSN_STR "Enable dynamic GRX based look-up (requires restart)\n")
348{
349 sgsn->cfg.dynamic_lookup = 1;
350 return CMD_SUCCESS;
351}
352
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800353DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
354 "grx-dns-add A.B.C.D",
355 "Add DNS server\nIPv4 address\n")
356{
357 struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node);
358 node->family = AF_INET;
359 inet_aton(argv[0], &node->addr.addr4);
360
361 node->next = sgsn->ares_servers;
362 sgsn->ares_servers = node;
363 return CMD_SUCCESS;
364}
365
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100366#define APN_STR "Configure the information per APN\n"
367#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
368
369static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
370 const char *imsi_prefix, int ggsn_id)
371{
372 struct apn_ctx *actx;
373 struct sgsn_ggsn_ctx *ggsn;
374
375 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
376 if (ggsn == NULL) {
377 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
378 ggsn_id, VTY_NEWLINE);
379 return CMD_WARNING;
380 }
381
382 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
383 if (!actx) {
384 vty_out(vty, "%% unable to create APN context for %s/%s%s",
385 apn_str, imsi_prefix, VTY_NEWLINE);
386 return CMD_WARNING;
387 }
388
389 actx->ggsn = ggsn;
390
391 return CMD_SUCCESS;
392}
393
Harald Welted193cb32010-05-17 22:58:03 +0200394DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
395 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100396 APN_STR APN_GW_STR
397 "Select the GGSN to use when the APN gateway prefix matches\n"
398 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200399{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100400
401 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200402}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100403
404DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
405 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
406 APN_STR APN_GW_STR
407 "Restrict rule to a certain IMSI prefix\n"
408 "An IMSI prefix\n"
409 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
410 "The GGSN id")
411{
412
413 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
414}
Harald Welted193cb32010-05-17 22:58:03 +0200415
416const struct value_string gprs_mm_st_strs[] = {
417 { GMM_DEREGISTERED, "DEREGISTERED" },
418 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
419 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200420 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200421 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
422 { 0, NULL }
423};
424
425static void vty_dump_pdp(struct vty *vty, const char *pfx,
426 struct sgsn_pdp_ctx *pdp)
427{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200428 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welted193cb32010-05-17 22:58:03 +0200429 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200430 pfx, imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200431 vty_out(vty, "%s APN: %s%s", pfx,
432 gprs_apn2str(pdp->lib->apn_use.v, pdp->lib->apn_use.l),
433 VTY_NEWLINE);
434 vty_out(vty, "%s PDP Address: %s%s", pfx,
435 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
436 VTY_NEWLINE);
Harald Welteefbdee92010-06-10 00:20:12 +0200437 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200438}
439
440static void vty_dump_mmctx(struct vty *vty, const char *pfx,
441 struct sgsn_mm_ctx *mm, int pdp)
442{
443 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
444 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200445 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Harald Weltef97ee042015-12-25 19:12:21 +0100446 pfx, mm->msisdn, mm->gb.tlli, mm->hlr, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200447 vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, "
448 "Cell ID: %u%s", pfx,
449 get_value_string(gprs_mm_st_strs, mm->mm_state),
450 mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac,
Harald Weltef97ee042015-12-25 19:12:21 +0100451 mm->gb.cell_id, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200452
Harald Welte8acd88f2010-05-18 10:57:45 +0200453 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
454
Harald Welted193cb32010-05-17 22:58:03 +0200455 if (pdp) {
456 struct sgsn_pdp_ctx *pdp;
457
458 llist_for_each_entry(pdp, &mm->pdp_list, list)
459 vty_dump_pdp(vty, " ", pdp);
460 }
461}
462
463DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
464 SHOW_STR "Display information about the SGSN")
465{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100466 if (sgsn->gsup_client) {
467 struct ipa_client_conn *link = sgsn->gsup_client->link;
468 vty_out(vty,
469 " Remote authorization: %sconnected to %s:%d via GSUP%s",
470 sgsn->gsup_client->is_connected ? "" : "not ",
471 link->addr, link->port,
472 VTY_NEWLINE);
473 }
Harald Welted193cb32010-05-17 22:58:03 +0200474 /* FIXME: statistics */
475 return CMD_SUCCESS;
476}
477
478#define MMCTX_STR "MM Context\n"
479#define INCLUDE_PDP_STR "Include PDP Context Information\n"
480
481#if 0
482DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
483 "show mm-context tlli HEX [pdp]",
484 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
485{
486 uint32_t tlli;
487 struct sgsn_mm_ctx *mm;
488
489 tlli = strtoul(argv[0], NULL, 16);
490 mm = sgsn_mm_ctx_by_tlli(tlli);
491 if (!mm) {
492 vty_out(vty, "No MM context for TLLI %08x%s",
493 tlli, VTY_NEWLINE);
494 return CMD_WARNING;
495 }
496 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
497 return CMD_SUCCESS;
498}
499#endif
500
501DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
502 "show mm-context imsi IMSI [pdp]",
503 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
504 INCLUDE_PDP_STR)
505{
506 struct sgsn_mm_ctx *mm;
507
508 mm = sgsn_mm_ctx_by_imsi(argv[0]);
509 if (!mm) {
510 vty_out(vty, "No MM context for IMSI %s%s",
511 argv[0], VTY_NEWLINE);
512 return CMD_WARNING;
513 }
514 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
515 return CMD_SUCCESS;
516}
517
518DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
519 "show mm-context all [pdp]",
520 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
521{
522 struct sgsn_mm_ctx *mm;
523
524 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
525 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
526
527 return CMD_SUCCESS;
528}
529
Harald Welted193cb32010-05-17 22:58:03 +0200530DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
531 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100532 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200533{
534 struct sgsn_pdp_ctx *pdp;
535
536 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
537 vty_dump_pdp(vty, "", pdp);
538
539 return CMD_SUCCESS;
540}
Harald Welte288be162010-05-01 16:48:27 +0200541
Harald Welte7f6da482013-03-19 11:00:13 +0100542
543DEFUN(imsi_acl, cfg_imsi_acl_cmd,
544 "imsi-acl (add|del) IMSI",
545 "Access Control List of foreign IMSIs\n"
546 "Add IMSI to ACL\n"
547 "Remove IMSI from ACL\n"
548 "IMSI of subscriber\n")
549{
550 const char *op = argv[0];
551 const char *imsi = argv[1];
552 int rc;
553
554 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200555 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100556 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200557 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100558
559 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100560 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
561
Harald Welte7f6da482013-03-19 11:00:13 +0100562 return CMD_WARNING;
563 }
564
565 return CMD_SUCCESS;
566}
567
Max93408ae2016-06-28 14:10:16 +0200568DEFUN(cfg_encrypt, cfg_encrypt_cmd,
569 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
570 "Set encryption algorithm for SGSN\n"
571 "Use GEA0 (no encryption)\n"
572 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
573{
574 if (!g_cfg->require_authentication) {
575 vty_out(vty, "%% unable to use encryption without "
576 "authentication: adjust auth-policy%s", VTY_NEWLINE);
577 return CMD_WARNING;
578 }
579
580 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
581 if (!gprs_cipher_supported(c)) {
582 vty_out(vty, "%% cipher %s is unsupported in current version%s",
583 argv[0], VTY_NEWLINE);
584 return CMD_WARNING;
585 }
586
587 g_cfg->cipher = c;
588
589 return CMD_SUCCESS;
590}
591
Harald Welte3dfb5492013-03-19 11:48:54 +0100592DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100593 "auth-policy (accept-all|closed|acl-only|remote)",
Harald Welte3dfb5492013-03-19 11:48:54 +0100594 "Autorization Policy of SGSN\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100595 "Accept all IMSIs (DANGEROUS)\n"
596 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100597 "Accept only subscribers in the ACL\n"
598 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100599{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100600 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100601 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Max176b62a2016-07-04 11:09:07 +0200602 if (val == SGSN_AUTH_POLICY_REMOTE) {
603 const char *err = "%% auth-policy remote requires";
604 if (!g_cfg->gsup_server_addr.sin_addr.s_addr) {
605 vty_out(vty, "%s 'gsup remote-ip'%s", err, VTY_NEWLINE);
606 return CMD_WARNING;
607 }
608 if (!g_cfg->gsup_server_port) {
609 vty_out(vty, "%s 'gsup remote-port'%s", err, VTY_NEWLINE);
610 return CMD_WARNING;
611 }
612 }
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100613 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100614 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100615 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100616
617 return CMD_SUCCESS;
618}
619
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100620/* Subscriber */
621#include <openbsc/gsm_subscriber.h>
622
623static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending)
624{
625 char expire_time[200];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100626 struct gsm_auth_tuple *at;
627 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100628 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100629
630 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
631 subscr->authorized, VTY_NEWLINE);
632 if (strlen(subscr->name))
633 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
634 if (strlen(subscr->extension))
635 vty_out(vty, " Extension: %s%s", subscr->extension,
636 VTY_NEWLINE);
637 vty_out(vty, " LAC: %d/0x%x%s",
638 subscr->lac, subscr->lac, VTY_NEWLINE);
639 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
640 if (subscr->tmsi != GSM_RESERVED_TMSI)
641 vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
642 VTY_NEWLINE);
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400643 if (subscr->sgsn_data->msisdn_len > 0)
644 vty_out(vty, " MSISDN (BCD): %s%s",
645 osmo_hexdump(subscr->sgsn_data->msisdn,
646 subscr->sgsn_data->msisdn_len),
647 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100648
649 if (strlen(subscr->equipment.imei) > 0)
650 vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE);
651
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100652 for (at_idx = 0; at_idx < ARRAY_SIZE(subscr->sgsn_data->auth_triplets);
653 at_idx++) {
654 at = &subscr->sgsn_data->auth_triplets[at_idx];
655 if (at->key_seq == GSM_KEY_SEQ_INVAL)
656 continue;
657
658 vty_out(vty, " A3A8 tuple (used %d times): ",
659 at->use_count);
660 vty_out(vty, " seq # : %d, ",
661 at->key_seq);
662 vty_out(vty, " RAND : %s, ",
Harald Welte121e9a42016-04-20 13:13:19 +0200663 osmo_hexdump(at->vec.rand, sizeof(at->vec.rand)));
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100664 vty_out(vty, " SRES : %s, ",
Harald Welte121e9a42016-04-20 13:13:19 +0200665 osmo_hexdump(at->vec.sres, sizeof(at->vec.sres)));
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100666 vty_out(vty, " Kc : %s%s",
Harald Welte121e9a42016-04-20 13:13:19 +0200667 osmo_hexdump(at->vec.kc, sizeof(at->vec.kc)),
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100668 VTY_NEWLINE);
669 }
670
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100671 llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400672 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s' QoS: %s%s",
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100673 pdp->context_id, pdp->pdp_type, pdp->apn_str,
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400674 osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len),
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100675 VTY_NEWLINE);
676 }
677
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100678 /* print the expiration time of a subscriber */
679 if (subscr->expire_lu) {
680 strftime(expire_time, sizeof(expire_time),
681 "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
682 expire_time[sizeof(expire_time) - 1] = '\0';
683 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
684 }
685
686 if (subscr->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100687 vty_out(vty, " Flags: %s%s%s%s%s%s",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100688 subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ?
689 "FIRST_CONTACT " : "",
690 subscr->flags & GPRS_SUBSCRIBER_CANCELLED ?
691 "CANCELLED " : "",
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100692 subscr->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
693 "UPDATE_LOCATION_PENDING " : "",
694 subscr->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
695 "AUTH_INFO_PENDING " : "",
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100696 subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
697 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100698 VTY_NEWLINE);
699
700 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
701}
702
703DEFUN(show_subscr_cache,
704 show_subscr_cache_cmd,
705 "show subscriber cache",
706 SHOW_STR "Show information about subscribers\n"
707 "Display contents of subscriber cache\n")
708{
709 struct gsm_subscriber *subscr;
710
711 llist_for_each_entry(subscr, &active_subscribers, entry) {
712 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
713 subscr_dump_full_vty(vty, subscr, 0);
714 }
715
716 return CMD_SUCCESS;
717}
718
719#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
720#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
721 "Use the IMSI to select the subscriber\n" \
722 "The IMSI\n"
723
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100724#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
725
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100726DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
727 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
728 UPDATE_SUBSCR_HELP
729 UPDATE_SUBSCR_INSERT_HELP
730 "Update authentication triplet\n"
731 "Triplet index\n"
732 "Set SRES value\nSRES value (4 byte) in hex\n"
733 "Set RAND value\nRAND value (16 byte) in hex\n"
734 "Set Kc value\nKc value (8 byte) in hex\n")
735{
736 const char *imsi = argv[0];
737 const int cksn = atoi(argv[1]) - 1;
738 const char *sres_str = argv[2];
739 const char *rand_str = argv[3];
740 const char *kc_str = argv[4];
741 struct gsm_auth_tuple at = {0,};
742
743 struct gsm_subscriber *subscr;
744
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100745 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100746 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100747 vty_out(vty, "%% unable get subscriber record for %s%s",
748 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100749 return CMD_WARNING;
750 }
751
752 OSMO_ASSERT(subscr->sgsn_data);
753
Harald Welte121e9a42016-04-20 13:13:19 +0200754 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100755 vty_out(vty, "%% invalid SRES value '%s'%s",
756 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100757 goto failed;
758 }
Harald Welte121e9a42016-04-20 13:13:19 +0200759 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100760 vty_out(vty, "%% invalid RAND value '%s'%s",
761 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100762 goto failed;
763 }
Harald Welte121e9a42016-04-20 13:13:19 +0200764 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100765 vty_out(vty, "%% invalid Kc value '%s'%s",
766 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100767 goto failed;
768 }
769 at.key_seq = cksn;
770
771 subscr->sgsn_data->auth_triplets[cksn] = at;
772 subscr->sgsn_data->auth_triplets_updated = 1;
773
774 subscr_put(subscr);
775
776 return CMD_SUCCESS;
777
778failed:
779 subscr_put(subscr);
780 return CMD_SUCCESS;
781}
782
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100783DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100784 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100785 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100786 "Cancel (remove) subscriber record\n"
787 "The MS moved to another SGSN\n"
788 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100789{
790 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100791 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100792
793 struct gsm_subscriber *subscr;
794
795 subscr = gprs_subscr_get_by_imsi(imsi);
796 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100797 vty_out(vty, "%% no subscriber record for %s%s",
798 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100799 return CMD_WARNING;
800 }
801
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100802 if (strcmp(cancel_type, "update-procedure") == 0)
803 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
804 else
805 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
806
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100807 gprs_subscr_cancel(subscr);
808 subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100809
810 return CMD_SUCCESS;
811}
812
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100813DEFUN(update_subscr_create, update_subscr_create_cmd,
814 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100815 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100816 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100817{
818 const char *imsi = argv[0];
819
820 struct gsm_subscriber *subscr;
821
822 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100823 if (subscr) {
824 vty_out(vty, "%% subscriber record already exists for %s%s",
825 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100826 return CMD_WARNING;
827 }
828
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100829 subscr = gprs_subscr_get_or_create(imsi);
830 subscr->keep_in_ram = 1;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100831 subscr_put(subscr);
832
833 return CMD_SUCCESS;
834}
835
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100836DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
837 UPDATE_SUBSCR_STR "destroy",
838 UPDATE_SUBSCR_HELP
839 "Destroy a subscriber entry\n")
840{
841 const char *imsi = argv[0];
842
843 struct gsm_subscriber *subscr;
844
845 subscr = gprs_subscr_get_by_imsi(imsi);
846 if (!subscr) {
847 vty_out(vty, "%% subscriber record does not exist for %s%s",
848 imsi, VTY_NEWLINE);
849 return CMD_WARNING;
850 }
851
852 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100853 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100854 gprs_subscr_cancel(subscr);
855 if (subscr->use_count > 1)
856 vty_out(vty, "%% subscriber is still in use%s",
857 VTY_NEWLINE);
858 subscr_put(subscr);
859
860 return CMD_SUCCESS;
861}
862
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100863#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
864 "unknown-subscriber|roaming-not-allowed"
865
866#define UL_ERR_HELP \
867 "Force error code SystemFailure\n" \
868 "Force error code DataMissing\n" \
869 "Force error code UnexpectedDataValue\n" \
870 "Force error code UnknownSubscriber\n" \
871 "Force error code RoamingNotAllowed\n"
872
873DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
874 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
875 UPDATE_SUBSCR_HELP
876 "Complete the update location procedure\n"
877 "The update location request succeeded\n"
878 UL_ERR_HELP)
879{
880 const char *imsi = argv[0];
881 const char *ret_code_str = argv[1];
882
883 struct gsm_subscriber *subscr;
884
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100885 const struct value_string cause_mapping[] = {
886 { GMM_CAUSE_NET_FAIL, "system-failure" },
887 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
888 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
889 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
890 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
891 { 0, NULL }
892 };
893
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100894 subscr = gprs_subscr_get_by_imsi(imsi);
895 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100896 vty_out(vty, "%% unable to get subscriber record for %s%s",
897 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100898 return CMD_WARNING;
899 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100900
901 if (strcmp(ret_code_str, "ok") == 0) {
902 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100903 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100904 } else {
905 subscr->sgsn_data->error_cause =
906 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100907 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100908 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100909
910 gprs_subscr_update(subscr);
911
912 subscr_put(subscr);
913
914 return CMD_SUCCESS;
915}
916
917DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
918 UPDATE_SUBSCR_STR "update-auth-info",
919 UPDATE_SUBSCR_HELP
920 "Complete the send authentication info procedure\n")
921{
922 const char *imsi = argv[0];
923
924 struct gsm_subscriber *subscr;
925
926 subscr = gprs_subscr_get_by_imsi(imsi);
927 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100928 vty_out(vty, "%% unable to get subscriber record for %s%s",
929 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100930 return CMD_WARNING;
931 }
932
933 gprs_subscr_update_auth_info(subscr);
934
935 subscr_put(subscr);
936
937 return CMD_SUCCESS;
938}
939
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100940DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
941 "gsup remote-ip A.B.C.D",
942 "GSUP Parameters\n"
943 "Set the IP address of the remote GSUP server\n"
944 "IPv4 Address\n")
945{
946 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
947
948 return CMD_SUCCESS;
949}
950
951DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
952 "gsup remote-port <0-65535>",
953 "GSUP Parameters\n"
954 "Set the TCP port of the remote GSUP server\n"
955 "Remote TCP port\n")
956{
957 g_cfg->gsup_server_port = atoi(argv[0]);
958
959 return CMD_SUCCESS;
960}
961
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200962DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
963 "gsup oap-id <0-65535>",
964 "GSUP Parameters\n"
965 "Set the SGSN's OAP client ID\nOAP client ID (0 == disabled)\n")
966{
967 /* VTY ensures range */
968 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
969 return CMD_SUCCESS;
970}
971
972DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
973 "gsup oap-k K",
974 "GSUP Parameters\n"
975 "Set the OAP shared secret K\nK value (16 byte) hex\n")
976{
977 const char *k = argv[0];
978
979 g_cfg->oap.secret_k_present = 0;
980
981 if ((!k) || (strlen(k) == 0))
982 goto disable;
983
984 int k_len = osmo_hexparse(k,
985 g_cfg->oap.secret_k,
986 sizeof(g_cfg->oap.secret_k));
987 if (k_len != 16) {
988 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
989 k_len, VTY_NEWLINE);
990 goto disable;
991 }
992
993 g_cfg->oap.secret_k_present = 1;
994 return CMD_SUCCESS;
995
996disable:
997 if (g_cfg->oap.client_id > 0) {
998 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
999 VTY_NEWLINE);
1000 return CMD_WARNING;
1001 }
1002 return CMD_SUCCESS;
1003}
1004
1005DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
1006 "gsup oap-opc OPC",
1007 "GSUP Parameters\n"
1008 "Set the OAP shared secret OPC\nOPC value (16 byte) hex\n")
1009{
1010 const char *opc = argv[0];
1011
1012 g_cfg->oap.secret_opc_present = 0;
1013
1014 if ((!opc) || (strlen(opc) == 0))
1015 goto disable;
1016
1017 int opc_len = osmo_hexparse(opc,
1018 g_cfg->oap.secret_opc,
1019 sizeof(g_cfg->oap.secret_opc));
1020 if (opc_len != 16) {
1021 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1022 opc_len, VTY_NEWLINE);
1023 goto disable;
1024 }
1025
1026 g_cfg->oap.secret_opc_present = 1;
1027 return CMD_SUCCESS;
1028
1029disable:
1030 if (g_cfg->oap.client_id > 0) {
1031 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1032 VTY_NEWLINE);
1033 return CMD_WARNING;
1034 }
1035 return CMD_SUCCESS;
1036}
1037
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001038DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1039 "access-point-name NAME",
1040 "Configure a global list of allowed APNs\n"
1041 "Add this NAME to the list\n")
1042{
1043 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1044}
1045
1046DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1047 "no access-point-name NAME",
1048 NO_STR "Configure a global list of allowed APNs\n"
1049 "Remove entry with NAME\n")
1050{
1051 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1052 if (!apn_ctx)
1053 return CMD_SUCCESS;
1054
1055 sgsn_apn_ctx_free(apn_ctx);
1056 return CMD_SUCCESS;
1057}
1058
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001059DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1060 "cdr filename NAME",
1061 "CDR\nSet filename\nname\n")
1062{
1063 talloc_free(g_cfg->cdr.filename);
1064 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1065 return CMD_SUCCESS;
1066}
1067
1068DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1069 "no cdr filename",
1070 NO_STR "CDR\nDisable CDR generation\n")
1071{
1072 talloc_free(g_cfg->cdr.filename);
1073 g_cfg->cdr.filename = NULL;
1074 return CMD_SUCCESS;
1075}
1076
1077DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1078 "cdr interval <1-2147483647>",
1079 "CDR\nPDP periodic log interval\nSeconds\n")
1080{
1081 g_cfg->cdr.interval = atoi(argv[0]);
1082 return CMD_SUCCESS;
1083}
1084
Philippf1f34362016-08-26 17:00:21 +02001085#define COMPRESSION_STR "Configure compression\n"
1086DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
1087 "no compression rfc1144",
1088 NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n")
1089{
1090 g_cfg->pcomp_rfc1144.active = 0;
1091 g_cfg->pcomp_rfc1144.passive = 0;
1092 return CMD_SUCCESS;
1093}
1094
1095DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
1096 "compression rfc1144 active slots <1-256>",
1097 COMPRESSION_STR
1098 "RFC1144 Header compresion scheme\n"
1099 "Compression is actively proposed\n"
1100 "Number of compression state slots\n"
1101 "Number of compression state slots\n")
1102{
1103 g_cfg->pcomp_rfc1144.active = 1;
1104 g_cfg->pcomp_rfc1144.passive = 1;
1105 g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1;
1106 return CMD_SUCCESS;
1107}
1108
1109DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
1110 "compression rfc1144 passive",
1111 COMPRESSION_STR
1112 "RFC1144 Header compresion scheme\n"
1113 "Compression is available on request\n")
1114{
1115 g_cfg->pcomp_rfc1144.active = 0;
1116 g_cfg->pcomp_rfc1144.passive = 1;
1117 return CMD_SUCCESS;
1118}
1119
Harald Welte288be162010-05-01 16:48:27 +02001120int sgsn_vty_init(void)
1121{
Harald Welted193cb32010-05-17 22:58:03 +02001122 install_element_ve(&show_sgsn_cmd);
1123 //install_element_ve(&show_mmctx_tlli_cmd);
1124 install_element_ve(&show_mmctx_imsi_cmd);
1125 install_element_ve(&show_mmctx_all_cmd);
1126 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001127 install_element_ve(&show_subscr_cache_cmd);
1128
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001129 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001130 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001131 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001132 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001133 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1134 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001135
1136 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1137 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeck36722e12013-10-29 09:30:30 +01001138 vty_install_default(SGSN_NODE);
Harald Weltee300d002010-06-02 12:41:34 +02001139 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001140 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1141 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1142 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001143 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001144 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Max93408ae2016-06-28 14:10:16 +02001145 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001146 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1147 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001148 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1149 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1150 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001151 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1152 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001153 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1154 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001155 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1156 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
1157 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001158 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001159 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001160
Harald Welte94508822015-08-15 19:08:21 +02001161 install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd);
1162 install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd);
1163 install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd);
1164 install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd);
1165 install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd);
1166 install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd);
1167 install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd);
1168 install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd);
1169 install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd);
1170 install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd);
1171 install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd);
1172 install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd);
1173
Philippf1f34362016-08-26 17:00:21 +02001174 install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
1175 install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
1176 install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd);
1177
Harald Welte288be162010-05-01 16:48:27 +02001178 return 0;
1179}
1180
1181int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
1182{
1183 int rc;
1184
1185 g_cfg = cfg;
Harald Welte7f6da482013-03-19 11:00:13 +01001186
Harald Welte94508822015-08-15 19:08:21 +02001187 g_cfg->timers.T3312 = GSM0408_T3312_SECS;
1188 g_cfg->timers.T3322 = GSM0408_T3322_SECS;
1189 g_cfg->timers.T3350 = GSM0408_T3350_SECS;
1190 g_cfg->timers.T3360 = GSM0408_T3360_SECS;
1191 g_cfg->timers.T3370 = GSM0408_T3370_SECS;
1192 g_cfg->timers.T3313 = GSM0408_T3313_SECS;
1193 g_cfg->timers.T3314 = GSM0408_T3314_SECS;
1194 g_cfg->timers.T3316 = GSM0408_T3316_SECS;
1195 g_cfg->timers.T3385 = GSM0408_T3385_SECS;
1196 g_cfg->timers.T3386 = GSM0408_T3386_SECS;
1197 g_cfg->timers.T3395 = GSM0408_T3395_SECS;
1198 g_cfg->timers.T3397 = GSM0408_T3397_SECS;
1199
Harald Weltedcccb182010-05-16 20:52:23 +02001200 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001201 if (rc < 0) {
1202 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1203 return rc;
1204 }
1205
1206 return 0;
1207}