blob: 3f6116393651d859fa94ea05c02731d35a88fa8a [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 Welte288be162010-05-01 16:48:27 +020030
31#include <openbsc/debug.h>
32#include <openbsc/sgsn.h>
Harald Welteea34a4e2012-06-16 14:59:56 +080033#include <osmocom/gprs/gprs_ns.h>
Harald Welted193cb32010-05-17 22:58:03 +020034#include <openbsc/gprs_sgsn.h>
Harald Welte62ab20c2010-05-14 18:59:17 +020035#include <openbsc/vty.h>
Harald Weltec5d4a0c2010-07-02 22:47:59 +020036#include <openbsc/gsm_04_08_gprs.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>
Harald Welte288be162010-05-01 16:48:27 +020042
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
Harald Welte3dfb5492013-03-19 11:48:54 +0100213 vty_out(vty, " auth-policy %s%s",
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100214 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
215 VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100216 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
217 vty_out(vty, " gsup remote-ip %s%s",
218 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
219 if (g_cfg->gsup_server_port)
220 vty_out(vty, " gsup remote-port %d%s",
221 g_cfg->gsup_server_port, VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200222
223 vty_out(vty, " gsup oap-id %d%s",
224 (int)g_cfg->oap.client_id, VTY_NEWLINE);
225 if (g_cfg->oap.secret_k_present != 0)
226 vty_out(vty, " gsup oap-k %s%s",
227 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
228 VTY_NEWLINE);
229 if (g_cfg->oap.secret_opc_present != 0)
230 vty_out(vty, " gsup oap-opc %s%s",
231 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
232 VTY_NEWLINE);
233
Harald Welte7f6da482013-03-19 11:00:13 +0100234 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
235 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
236
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100237 if (llist_empty(&sgsn_apn_ctxts))
238 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
239 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
240 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200241 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100242 actx->name, actx->imsi_prefix, actx->ggsn->id,
243 VTY_NEWLINE);
244 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200245 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100246 actx->ggsn->id, VTY_NEWLINE);
247 }
248
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200249 if (g_cfg->cdr.filename)
250 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
251 else
252 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
253 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
254
Harald Welte94508822015-08-15 19:08:21 +0200255 vty_out(vty, " timer t3312 %d%s", g_cfg->timers.T3312, VTY_NEWLINE);
256 vty_out(vty, " timer t3322 %d%s", g_cfg->timers.T3322, VTY_NEWLINE);
257 vty_out(vty, " timer t3350 %d%s", g_cfg->timers.T3350, VTY_NEWLINE);
258 vty_out(vty, " timer t3360 %d%s", g_cfg->timers.T3360, VTY_NEWLINE);
259 vty_out(vty, " timer t3370 %d%s", g_cfg->timers.T3370, VTY_NEWLINE);
260 vty_out(vty, " timer t3313 %d%s", g_cfg->timers.T3313, VTY_NEWLINE);
261 vty_out(vty, " timer t3314 %d%s", g_cfg->timers.T3314, VTY_NEWLINE);
262 vty_out(vty, " timer t3316 %d%s", g_cfg->timers.T3316, VTY_NEWLINE);
263 vty_out(vty, " timer t3385 %d%s", g_cfg->timers.T3385, VTY_NEWLINE);
264 vty_out(vty, " timer t3386 %d%s", g_cfg->timers.T3386, VTY_NEWLINE);
265 vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE);
266 vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE);
267
Harald Welte288be162010-05-01 16:48:27 +0200268 return CMD_SUCCESS;
269}
270
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100271#define SGSN_STR "Configure the SGSN\n"
272#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200273
274DEFUN(cfg_sgsn, cfg_sgsn_cmd,
275 "sgsn",
276 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200277{
278 vty->node = SGSN_NODE;
279 return CMD_SUCCESS;
280}
281
Harald Weltee300d002010-06-02 12:41:34 +0200282DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
283 "gtp local-ip A.B.C.D",
284 "GTP Parameters\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100285 "Set the IP address for the local GTP bind\n"
286 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200287{
288 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
289
290 return CMD_SUCCESS;
291}
292
Harald Welted193cb32010-05-17 22:58:03 +0200293DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
294 "ggsn <0-255> remote-ip A.B.C.D",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100295 GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200296{
297 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200298 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200299
Harald Welted193cb32010-05-17 22:58:03 +0200300 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200301
Harald Welted193cb32010-05-17 22:58:03 +0200302 return CMD_SUCCESS;
303}
304
305#if 0
306DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
307 "ggsn <0-255> remote-port <0-65535>",
308 "")
309{
310 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200311 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200312 uint16_t port = atoi(argv[1]);
313
314}
315#endif
316
317DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
318 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100319 GGSN_STR "GGSN Number\n" "GTP Version\n"
320 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200321{
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
325 if (atoi(argv[1]))
326 ggc->gtp_version = 1;
327 else
328 ggc->gtp_version = 0;
329
330 return CMD_SUCCESS;
331}
332
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800333DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
334 "ggsn dynamic",
335 GGSN_STR "Enable dynamic GRX based look-up (requires restart)\n")
336{
337 sgsn->cfg.dynamic_lookup = 1;
338 return CMD_SUCCESS;
339}
340
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800341DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
342 "grx-dns-add A.B.C.D",
343 "Add DNS server\nIPv4 address\n")
344{
345 struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node);
346 node->family = AF_INET;
347 inet_aton(argv[0], &node->addr.addr4);
348
349 node->next = sgsn->ares_servers;
350 sgsn->ares_servers = node;
351 return CMD_SUCCESS;
352}
353
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100354#define APN_STR "Configure the information per APN\n"
355#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
356
357static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
358 const char *imsi_prefix, int ggsn_id)
359{
360 struct apn_ctx *actx;
361 struct sgsn_ggsn_ctx *ggsn;
362
363 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
364 if (ggsn == NULL) {
365 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
366 ggsn_id, VTY_NEWLINE);
367 return CMD_WARNING;
368 }
369
370 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
371 if (!actx) {
372 vty_out(vty, "%% unable to create APN context for %s/%s%s",
373 apn_str, imsi_prefix, VTY_NEWLINE);
374 return CMD_WARNING;
375 }
376
377 actx->ggsn = ggsn;
378
379 return CMD_SUCCESS;
380}
381
Harald Welted193cb32010-05-17 22:58:03 +0200382DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
383 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100384 APN_STR APN_GW_STR
385 "Select the GGSN to use when the APN gateway prefix matches\n"
386 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200387{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100388
389 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200390}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100391
392DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
393 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
394 APN_STR APN_GW_STR
395 "Restrict rule to a certain IMSI prefix\n"
396 "An IMSI prefix\n"
397 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
398 "The GGSN id")
399{
400
401 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
402}
Harald Welted193cb32010-05-17 22:58:03 +0200403
404const struct value_string gprs_mm_st_strs[] = {
405 { GMM_DEREGISTERED, "DEREGISTERED" },
406 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
407 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200408 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200409 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
410 { 0, NULL }
411};
412
413static void vty_dump_pdp(struct vty *vty, const char *pfx,
414 struct sgsn_pdp_ctx *pdp)
415{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200416 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welted193cb32010-05-17 22:58:03 +0200417 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200418 pfx, imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200419 vty_out(vty, "%s APN: %s%s", pfx,
420 gprs_apn2str(pdp->lib->apn_use.v, pdp->lib->apn_use.l),
421 VTY_NEWLINE);
422 vty_out(vty, "%s PDP Address: %s%s", pfx,
423 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
424 VTY_NEWLINE);
Harald Welteefbdee92010-06-10 00:20:12 +0200425 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200426}
427
428static void vty_dump_mmctx(struct vty *vty, const char *pfx,
429 struct sgsn_mm_ctx *mm, int pdp)
430{
431 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
432 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200433 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
434 pfx, mm->msisdn, mm->tlli, mm->hlr, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200435 vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, "
436 "Cell ID: %u%s", pfx,
437 get_value_string(gprs_mm_st_strs, mm->mm_state),
438 mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac,
439 mm->cell_id, VTY_NEWLINE);
440
Harald Welte8acd88f2010-05-18 10:57:45 +0200441 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
442
Harald Welted193cb32010-05-17 22:58:03 +0200443 if (pdp) {
444 struct sgsn_pdp_ctx *pdp;
445
446 llist_for_each_entry(pdp, &mm->pdp_list, list)
447 vty_dump_pdp(vty, " ", pdp);
448 }
449}
450
451DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
452 SHOW_STR "Display information about the SGSN")
453{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100454 if (sgsn->gsup_client) {
455 struct ipa_client_conn *link = sgsn->gsup_client->link;
456 vty_out(vty,
457 " Remote authorization: %sconnected to %s:%d via GSUP%s",
458 sgsn->gsup_client->is_connected ? "" : "not ",
459 link->addr, link->port,
460 VTY_NEWLINE);
461 }
Harald Welted193cb32010-05-17 22:58:03 +0200462 /* FIXME: statistics */
463 return CMD_SUCCESS;
464}
465
466#define MMCTX_STR "MM Context\n"
467#define INCLUDE_PDP_STR "Include PDP Context Information\n"
468
469#if 0
470DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
471 "show mm-context tlli HEX [pdp]",
472 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
473{
474 uint32_t tlli;
475 struct sgsn_mm_ctx *mm;
476
477 tlli = strtoul(argv[0], NULL, 16);
478 mm = sgsn_mm_ctx_by_tlli(tlli);
479 if (!mm) {
480 vty_out(vty, "No MM context for TLLI %08x%s",
481 tlli, VTY_NEWLINE);
482 return CMD_WARNING;
483 }
484 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
485 return CMD_SUCCESS;
486}
487#endif
488
489DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
490 "show mm-context imsi IMSI [pdp]",
491 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
492 INCLUDE_PDP_STR)
493{
494 struct sgsn_mm_ctx *mm;
495
496 mm = sgsn_mm_ctx_by_imsi(argv[0]);
497 if (!mm) {
498 vty_out(vty, "No MM context for IMSI %s%s",
499 argv[0], VTY_NEWLINE);
500 return CMD_WARNING;
501 }
502 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
503 return CMD_SUCCESS;
504}
505
506DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
507 "show mm-context all [pdp]",
508 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
509{
510 struct sgsn_mm_ctx *mm;
511
512 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
513 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
514
515 return CMD_SUCCESS;
516}
517
Harald Welted193cb32010-05-17 22:58:03 +0200518DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
519 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100520 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200521{
522 struct sgsn_pdp_ctx *pdp;
523
524 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
525 vty_dump_pdp(vty, "", pdp);
526
527 return CMD_SUCCESS;
528}
Harald Welte288be162010-05-01 16:48:27 +0200529
Harald Welte7f6da482013-03-19 11:00:13 +0100530
531DEFUN(imsi_acl, cfg_imsi_acl_cmd,
532 "imsi-acl (add|del) IMSI",
533 "Access Control List of foreign IMSIs\n"
534 "Add IMSI to ACL\n"
535 "Remove IMSI from ACL\n"
536 "IMSI of subscriber\n")
537{
538 const char *op = argv[0];
539 const char *imsi = argv[1];
540 int rc;
541
542 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200543 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100544 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200545 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100546
547 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100548 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
549
Harald Welte7f6da482013-03-19 11:00:13 +0100550 return CMD_WARNING;
551 }
552
553 return CMD_SUCCESS;
554}
555
Harald Welte3dfb5492013-03-19 11:48:54 +0100556DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100557 "auth-policy (accept-all|closed|acl-only|remote)",
Harald Welte3dfb5492013-03-19 11:48:54 +0100558 "Autorization Policy of SGSN\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100559 "Accept all IMSIs (DANGEROUS)\n"
560 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100561 "Accept only subscribers in the ACL\n"
562 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100563{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100564 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100565 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100566 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100567 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100568 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100569
570 return CMD_SUCCESS;
571}
572
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100573/* Subscriber */
574#include <openbsc/gsm_subscriber.h>
575
576static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending)
577{
578 char expire_time[200];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100579 struct gsm_auth_tuple *at;
580 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100581 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100582
583 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
584 subscr->authorized, VTY_NEWLINE);
585 if (strlen(subscr->name))
586 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
587 if (strlen(subscr->extension))
588 vty_out(vty, " Extension: %s%s", subscr->extension,
589 VTY_NEWLINE);
590 vty_out(vty, " LAC: %d/0x%x%s",
591 subscr->lac, subscr->lac, VTY_NEWLINE);
592 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
593 if (subscr->tmsi != GSM_RESERVED_TMSI)
594 vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
595 VTY_NEWLINE);
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400596 if (subscr->sgsn_data->msisdn_len > 0)
597 vty_out(vty, " MSISDN (BCD): %s%s",
598 osmo_hexdump(subscr->sgsn_data->msisdn,
599 subscr->sgsn_data->msisdn_len),
600 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100601
602 if (strlen(subscr->equipment.imei) > 0)
603 vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE);
604
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100605 for (at_idx = 0; at_idx < ARRAY_SIZE(subscr->sgsn_data->auth_triplets);
606 at_idx++) {
607 at = &subscr->sgsn_data->auth_triplets[at_idx];
608 if (at->key_seq == GSM_KEY_SEQ_INVAL)
609 continue;
610
611 vty_out(vty, " A3A8 tuple (used %d times): ",
612 at->use_count);
613 vty_out(vty, " seq # : %d, ",
614 at->key_seq);
615 vty_out(vty, " RAND : %s, ",
616 osmo_hexdump(at->rand, sizeof(at->rand)));
617 vty_out(vty, " SRES : %s, ",
618 osmo_hexdump(at->sres, sizeof(at->sres)));
619 vty_out(vty, " Kc : %s%s",
620 osmo_hexdump(at->kc, sizeof(at->kc)),
621 VTY_NEWLINE);
622 }
623
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100624 llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400625 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s' QoS: %s%s",
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100626 pdp->context_id, pdp->pdp_type, pdp->apn_str,
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400627 osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len),
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100628 VTY_NEWLINE);
629 }
630
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100631 /* print the expiration time of a subscriber */
632 if (subscr->expire_lu) {
633 strftime(expire_time, sizeof(expire_time),
634 "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
635 expire_time[sizeof(expire_time) - 1] = '\0';
636 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
637 }
638
639 if (subscr->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100640 vty_out(vty, " Flags: %s%s%s%s%s%s",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100641 subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ?
642 "FIRST_CONTACT " : "",
643 subscr->flags & GPRS_SUBSCRIBER_CANCELLED ?
644 "CANCELLED " : "",
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100645 subscr->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
646 "UPDATE_LOCATION_PENDING " : "",
647 subscr->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
648 "AUTH_INFO_PENDING " : "",
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100649 subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
650 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100651 VTY_NEWLINE);
652
653 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
654}
655
656DEFUN(show_subscr_cache,
657 show_subscr_cache_cmd,
658 "show subscriber cache",
659 SHOW_STR "Show information about subscribers\n"
660 "Display contents of subscriber cache\n")
661{
662 struct gsm_subscriber *subscr;
663
664 llist_for_each_entry(subscr, &active_subscribers, entry) {
665 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
666 subscr_dump_full_vty(vty, subscr, 0);
667 }
668
669 return CMD_SUCCESS;
670}
671
672#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
673#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
674 "Use the IMSI to select the subscriber\n" \
675 "The IMSI\n"
676
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100677#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
678
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100679DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
680 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
681 UPDATE_SUBSCR_HELP
682 UPDATE_SUBSCR_INSERT_HELP
683 "Update authentication triplet\n"
684 "Triplet index\n"
685 "Set SRES value\nSRES value (4 byte) in hex\n"
686 "Set RAND value\nRAND value (16 byte) in hex\n"
687 "Set Kc value\nKc value (8 byte) in hex\n")
688{
689 const char *imsi = argv[0];
690 const int cksn = atoi(argv[1]) - 1;
691 const char *sres_str = argv[2];
692 const char *rand_str = argv[3];
693 const char *kc_str = argv[4];
694 struct gsm_auth_tuple at = {0,};
695
696 struct gsm_subscriber *subscr;
697
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100698 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100699 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100700 vty_out(vty, "%% unable get subscriber record for %s%s",
701 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100702 return CMD_WARNING;
703 }
704
705 OSMO_ASSERT(subscr->sgsn_data);
706
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100707 if (osmo_hexparse(sres_str, &at.sres[0], sizeof(at.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100708 vty_out(vty, "%% invalid SRES value '%s'%s",
709 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100710 goto failed;
711 }
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100712 if (osmo_hexparse(rand_str, &at.rand[0], sizeof(at.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100713 vty_out(vty, "%% invalid RAND value '%s'%s",
714 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100715 goto failed;
716 }
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100717 if (osmo_hexparse(kc_str, &at.kc[0], sizeof(at.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100718 vty_out(vty, "%% invalid Kc value '%s'%s",
719 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100720 goto failed;
721 }
722 at.key_seq = cksn;
723
724 subscr->sgsn_data->auth_triplets[cksn] = at;
725 subscr->sgsn_data->auth_triplets_updated = 1;
726
727 subscr_put(subscr);
728
729 return CMD_SUCCESS;
730
731failed:
732 subscr_put(subscr);
733 return CMD_SUCCESS;
734}
735
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100736DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100737 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100738 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100739 "Cancel (remove) subscriber record\n"
740 "The MS moved to another SGSN\n"
741 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100742{
743 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100744 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100745
746 struct gsm_subscriber *subscr;
747
748 subscr = gprs_subscr_get_by_imsi(imsi);
749 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100750 vty_out(vty, "%% no subscriber record for %s%s",
751 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100752 return CMD_WARNING;
753 }
754
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100755 if (strcmp(cancel_type, "update-procedure") == 0)
756 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
757 else
758 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
759
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100760 gprs_subscr_cancel(subscr);
761 subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100762
763 return CMD_SUCCESS;
764}
765
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100766DEFUN(update_subscr_create, update_subscr_create_cmd,
767 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100768 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100769 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100770{
771 const char *imsi = argv[0];
772
773 struct gsm_subscriber *subscr;
774
775 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100776 if (subscr) {
777 vty_out(vty, "%% subscriber record already exists for %s%s",
778 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100779 return CMD_WARNING;
780 }
781
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100782 subscr = gprs_subscr_get_or_create(imsi);
783 subscr->keep_in_ram = 1;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100784 subscr_put(subscr);
785
786 return CMD_SUCCESS;
787}
788
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100789DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
790 UPDATE_SUBSCR_STR "destroy",
791 UPDATE_SUBSCR_HELP
792 "Destroy a subscriber entry\n")
793{
794 const char *imsi = argv[0];
795
796 struct gsm_subscriber *subscr;
797
798 subscr = gprs_subscr_get_by_imsi(imsi);
799 if (!subscr) {
800 vty_out(vty, "%% subscriber record does not exist for %s%s",
801 imsi, VTY_NEWLINE);
802 return CMD_WARNING;
803 }
804
805 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100806 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100807 gprs_subscr_cancel(subscr);
808 if (subscr->use_count > 1)
809 vty_out(vty, "%% subscriber is still in use%s",
810 VTY_NEWLINE);
811 subscr_put(subscr);
812
813 return CMD_SUCCESS;
814}
815
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100816#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
817 "unknown-subscriber|roaming-not-allowed"
818
819#define UL_ERR_HELP \
820 "Force error code SystemFailure\n" \
821 "Force error code DataMissing\n" \
822 "Force error code UnexpectedDataValue\n" \
823 "Force error code UnknownSubscriber\n" \
824 "Force error code RoamingNotAllowed\n"
825
826DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
827 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
828 UPDATE_SUBSCR_HELP
829 "Complete the update location procedure\n"
830 "The update location request succeeded\n"
831 UL_ERR_HELP)
832{
833 const char *imsi = argv[0];
834 const char *ret_code_str = argv[1];
835
836 struct gsm_subscriber *subscr;
837
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100838 const struct value_string cause_mapping[] = {
839 { GMM_CAUSE_NET_FAIL, "system-failure" },
840 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
841 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
842 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
843 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
844 { 0, NULL }
845 };
846
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100847 subscr = gprs_subscr_get_by_imsi(imsi);
848 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100849 vty_out(vty, "%% unable to get subscriber record for %s%s",
850 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100851 return CMD_WARNING;
852 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100853
854 if (strcmp(ret_code_str, "ok") == 0) {
855 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100856 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100857 } else {
858 subscr->sgsn_data->error_cause =
859 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100860 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100861 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100862
863 gprs_subscr_update(subscr);
864
865 subscr_put(subscr);
866
867 return CMD_SUCCESS;
868}
869
870DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
871 UPDATE_SUBSCR_STR "update-auth-info",
872 UPDATE_SUBSCR_HELP
873 "Complete the send authentication info procedure\n")
874{
875 const char *imsi = argv[0];
876
877 struct gsm_subscriber *subscr;
878
879 subscr = gprs_subscr_get_by_imsi(imsi);
880 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100881 vty_out(vty, "%% unable to get subscriber record for %s%s",
882 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100883 return CMD_WARNING;
884 }
885
886 gprs_subscr_update_auth_info(subscr);
887
888 subscr_put(subscr);
889
890 return CMD_SUCCESS;
891}
892
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100893DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
894 "gsup remote-ip A.B.C.D",
895 "GSUP Parameters\n"
896 "Set the IP address of the remote GSUP server\n"
897 "IPv4 Address\n")
898{
899 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
900
901 return CMD_SUCCESS;
902}
903
904DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
905 "gsup remote-port <0-65535>",
906 "GSUP Parameters\n"
907 "Set the TCP port of the remote GSUP server\n"
908 "Remote TCP port\n")
909{
910 g_cfg->gsup_server_port = atoi(argv[0]);
911
912 return CMD_SUCCESS;
913}
914
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200915DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
916 "gsup oap-id <0-65535>",
917 "GSUP Parameters\n"
918 "Set the SGSN's OAP client ID\nOAP client ID (0 == disabled)\n")
919{
920 /* VTY ensures range */
921 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
922 return CMD_SUCCESS;
923}
924
925DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
926 "gsup oap-k K",
927 "GSUP Parameters\n"
928 "Set the OAP shared secret K\nK value (16 byte) hex\n")
929{
930 const char *k = argv[0];
931
932 g_cfg->oap.secret_k_present = 0;
933
934 if ((!k) || (strlen(k) == 0))
935 goto disable;
936
937 int k_len = osmo_hexparse(k,
938 g_cfg->oap.secret_k,
939 sizeof(g_cfg->oap.secret_k));
940 if (k_len != 16) {
941 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
942 k_len, VTY_NEWLINE);
943 goto disable;
944 }
945
946 g_cfg->oap.secret_k_present = 1;
947 return CMD_SUCCESS;
948
949disable:
950 if (g_cfg->oap.client_id > 0) {
951 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
952 VTY_NEWLINE);
953 return CMD_WARNING;
954 }
955 return CMD_SUCCESS;
956}
957
958DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
959 "gsup oap-opc OPC",
960 "GSUP Parameters\n"
961 "Set the OAP shared secret OPC\nOPC value (16 byte) hex\n")
962{
963 const char *opc = argv[0];
964
965 g_cfg->oap.secret_opc_present = 0;
966
967 if ((!opc) || (strlen(opc) == 0))
968 goto disable;
969
970 int opc_len = osmo_hexparse(opc,
971 g_cfg->oap.secret_opc,
972 sizeof(g_cfg->oap.secret_opc));
973 if (opc_len != 16) {
974 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
975 opc_len, VTY_NEWLINE);
976 goto disable;
977 }
978
979 g_cfg->oap.secret_opc_present = 1;
980 return CMD_SUCCESS;
981
982disable:
983 if (g_cfg->oap.client_id > 0) {
984 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
985 VTY_NEWLINE);
986 return CMD_WARNING;
987 }
988 return CMD_SUCCESS;
989}
990
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +0100991DEFUN(cfg_apn_name, cfg_apn_name_cmd,
992 "access-point-name NAME",
993 "Configure a global list of allowed APNs\n"
994 "Add this NAME to the list\n")
995{
996 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
997}
998
999DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1000 "no access-point-name NAME",
1001 NO_STR "Configure a global list of allowed APNs\n"
1002 "Remove entry with NAME\n")
1003{
1004 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1005 if (!apn_ctx)
1006 return CMD_SUCCESS;
1007
1008 sgsn_apn_ctx_free(apn_ctx);
1009 return CMD_SUCCESS;
1010}
1011
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001012DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1013 "cdr filename NAME",
1014 "CDR\nSet filename\nname\n")
1015{
1016 talloc_free(g_cfg->cdr.filename);
1017 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1018 return CMD_SUCCESS;
1019}
1020
1021DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1022 "no cdr filename",
1023 NO_STR "CDR\nDisable CDR generation\n")
1024{
1025 talloc_free(g_cfg->cdr.filename);
1026 g_cfg->cdr.filename = NULL;
1027 return CMD_SUCCESS;
1028}
1029
1030DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1031 "cdr interval <1-2147483647>",
1032 "CDR\nPDP periodic log interval\nSeconds\n")
1033{
1034 g_cfg->cdr.interval = atoi(argv[0]);
1035 return CMD_SUCCESS;
1036}
1037
Harald Welte288be162010-05-01 16:48:27 +02001038int sgsn_vty_init(void)
1039{
Harald Welted193cb32010-05-17 22:58:03 +02001040 install_element_ve(&show_sgsn_cmd);
1041 //install_element_ve(&show_mmctx_tlli_cmd);
1042 install_element_ve(&show_mmctx_imsi_cmd);
1043 install_element_ve(&show_mmctx_all_cmd);
1044 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001045 install_element_ve(&show_subscr_cache_cmd);
1046
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001047 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001048 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001049 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001050 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001051 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1052 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001053
1054 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1055 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeck36722e12013-10-29 09:30:30 +01001056 vty_install_default(SGSN_NODE);
Harald Weltee300d002010-06-02 12:41:34 +02001057 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001058 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1059 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1060 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001061 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001062 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001063 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1064 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001065 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1066 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1067 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001068 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1069 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001070 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1071 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001072 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1073 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
1074 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001075 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001076 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001077
Harald Welte94508822015-08-15 19:08:21 +02001078 install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd);
1079 install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd);
1080 install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd);
1081 install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd);
1082 install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd);
1083 install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd);
1084 install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd);
1085 install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd);
1086 install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd);
1087 install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd);
1088 install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd);
1089 install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd);
1090
Harald Welte288be162010-05-01 16:48:27 +02001091 return 0;
1092}
1093
1094int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
1095{
1096 int rc;
1097
1098 g_cfg = cfg;
Harald Welte7f6da482013-03-19 11:00:13 +01001099
Harald Welte94508822015-08-15 19:08:21 +02001100 g_cfg->timers.T3312 = GSM0408_T3312_SECS;
1101 g_cfg->timers.T3322 = GSM0408_T3322_SECS;
1102 g_cfg->timers.T3350 = GSM0408_T3350_SECS;
1103 g_cfg->timers.T3360 = GSM0408_T3360_SECS;
1104 g_cfg->timers.T3370 = GSM0408_T3370_SECS;
1105 g_cfg->timers.T3313 = GSM0408_T3313_SECS;
1106 g_cfg->timers.T3314 = GSM0408_T3314_SECS;
1107 g_cfg->timers.T3316 = GSM0408_T3316_SECS;
1108 g_cfg->timers.T3385 = GSM0408_T3385_SECS;
1109 g_cfg->timers.T3386 = GSM0408_T3386_SECS;
1110 g_cfg->timers.T3395 = GSM0408_T3395_SECS;
1111 g_cfg->timers.T3397 = GSM0408_T3397_SECS;
1112
Harald Weltedcccb182010-05-16 20:52:23 +02001113 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001114 if (rc < 0) {
1115 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1116 return rc;
1117 }
1118
1119 return 0;
1120}