blob: b74d01a425648abdf0580225e1d51c4210cde0cd [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" \
82 doc "Timer Value in seconds\n") \
83{ \
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)")
97DECLARE_TIMER(3322, "Detach reqest -> accept timer (s)")
98DECLARE_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)")
104DECLARE_TIMER(3316, "")
105
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 */
113static char *gprs_apn2str(uint8_t *apn, unsigned int len)
114{
115 static char apnbuf[GSM48_MAX_APN_LEN+1];
Holger Hans Peter Freyther80e03652013-07-04 18:44:16 +0200116 unsigned int i = 0;
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200117
118 if (!apn)
119 return "";
120
121 if (len > sizeof(apnbuf)-1)
122 len = sizeof(apnbuf)-1;
123
124 memcpy(apnbuf, apn, len);
125 apnbuf[len] = '\0';
126
127 /* replace the domain name step sizes with dots */
128 while (i < len) {
129 unsigned int step = apnbuf[i];
130 apnbuf[i] = '.';
131 i += step+1;
132 }
133
134 return apnbuf+1;
135}
136
Holger Hans Peter Freythera2730302014-03-23 18:08:26 +0100137char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200138{
139 static char str[INET6_ADDRSTRLEN + 10];
140
141 if (!pdpa || len < 2)
142 return "none";
143
144 switch (pdpa[0] & 0x0f) {
145 case PDP_TYPE_ORG_IETF:
146 switch (pdpa[1]) {
147 case PDP_TYPE_N_IETF_IPv4:
148 if (len < 2 + 4)
149 break;
150 strcpy(str, "IPv4 ");
151 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
152 return str;
153 case PDP_TYPE_N_IETF_IPv6:
154 if (len < 2 + 8)
155 break;
156 strcpy(str, "IPv6 ");
157 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
158 return str;
159 default:
160 break;
161 }
162 break;
163 case PDP_TYPE_ORG_ETSI:
164 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
165 return "PPP";
166 break;
167 default:
168 break;
169 }
170
171 return "invalid";
172}
173
Harald Welte288be162010-05-01 16:48:27 +0200174static struct cmd_node sgsn_node = {
175 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200176 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200177 1,
178};
179
180static int config_write_sgsn(struct vty *vty)
181{
Harald Welte77289c22010-05-18 14:32:29 +0200182 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100183 struct imsi_acl_entry *acl;
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100184 struct apn_ctx *actx;
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800185 struct ares_addr_node *server;
Harald Welte288be162010-05-01 16:48:27 +0200186
187 vty_out(vty, "sgsn%s", VTY_NEWLINE);
188
Harald Weltee300d002010-06-02 12:41:34 +0200189 vty_out(vty, " gtp local-ip %s%s",
190 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
191
Harald Welted193cb32010-05-17 22:58:03 +0200192 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800193 if (gctx->id == UINT32_MAX)
194 continue;
195
Harald Welteff3bde82010-05-19 15:09:09 +0200196 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200197 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200198 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200199 gctx->gtp_version, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200200 }
201
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800202 if (sgsn->cfg.dynamic_lookup)
203 vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE);
204
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800205 for (server = sgsn->ares_servers; server; server = server->next)
206 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
207
Harald Welte3dfb5492013-03-19 11:48:54 +0100208 vty_out(vty, " auth-policy %s%s",
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100209 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
210 VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100211 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
212 vty_out(vty, " gsup remote-ip %s%s",
213 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
214 if (g_cfg->gsup_server_port)
215 vty_out(vty, " gsup remote-port %d%s",
216 g_cfg->gsup_server_port, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100217 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
218 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
219
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100220 if (llist_empty(&sgsn_apn_ctxts))
221 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
222 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
223 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200224 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100225 actx->name, actx->imsi_prefix, actx->ggsn->id,
226 VTY_NEWLINE);
227 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200228 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100229 actx->ggsn->id, VTY_NEWLINE);
230 }
231
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200232 if (g_cfg->cdr.filename)
233 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
234 else
235 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
236 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
237
Harald Welte94508822015-08-15 19:08:21 +0200238 vty_out(vty, " timer t3312 %d%s", g_cfg->timers.T3312, VTY_NEWLINE);
239 vty_out(vty, " timer t3322 %d%s", g_cfg->timers.T3322, VTY_NEWLINE);
240 vty_out(vty, " timer t3350 %d%s", g_cfg->timers.T3350, VTY_NEWLINE);
241 vty_out(vty, " timer t3360 %d%s", g_cfg->timers.T3360, VTY_NEWLINE);
242 vty_out(vty, " timer t3370 %d%s", g_cfg->timers.T3370, VTY_NEWLINE);
243 vty_out(vty, " timer t3313 %d%s", g_cfg->timers.T3313, VTY_NEWLINE);
244 vty_out(vty, " timer t3314 %d%s", g_cfg->timers.T3314, VTY_NEWLINE);
245 vty_out(vty, " timer t3316 %d%s", g_cfg->timers.T3316, VTY_NEWLINE);
246 vty_out(vty, " timer t3385 %d%s", g_cfg->timers.T3385, VTY_NEWLINE);
247 vty_out(vty, " timer t3386 %d%s", g_cfg->timers.T3386, VTY_NEWLINE);
248 vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE);
249 vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE);
250
Harald Welte288be162010-05-01 16:48:27 +0200251 return CMD_SUCCESS;
252}
253
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100254#define SGSN_STR "Configure the SGSN\n"
255#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200256
257DEFUN(cfg_sgsn, cfg_sgsn_cmd,
258 "sgsn",
259 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200260{
261 vty->node = SGSN_NODE;
262 return CMD_SUCCESS;
263}
264
Harald Weltee300d002010-06-02 12:41:34 +0200265DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
266 "gtp local-ip A.B.C.D",
267 "GTP Parameters\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100268 "Set the IP address for the local GTP bind\n"
269 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200270{
271 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
272
273 return CMD_SUCCESS;
274}
275
Harald Welted193cb32010-05-17 22:58:03 +0200276DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
277 "ggsn <0-255> remote-ip A.B.C.D",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100278 GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200279{
280 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200281 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200282
Harald Welted193cb32010-05-17 22:58:03 +0200283 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200284
Harald Welted193cb32010-05-17 22:58:03 +0200285 return CMD_SUCCESS;
286}
287
288#if 0
289DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
290 "ggsn <0-255> remote-port <0-65535>",
291 "")
292{
293 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200294 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200295 uint16_t port = atoi(argv[1]);
296
297}
298#endif
299
300DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
301 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100302 GGSN_STR "GGSN Number\n" "GTP Version\n"
303 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200304{
305 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200306 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200307
308 if (atoi(argv[1]))
309 ggc->gtp_version = 1;
310 else
311 ggc->gtp_version = 0;
312
313 return CMD_SUCCESS;
314}
315
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800316DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
317 "ggsn dynamic",
318 GGSN_STR "Enable dynamic GRX based look-up (requires restart)\n")
319{
320 sgsn->cfg.dynamic_lookup = 1;
321 return CMD_SUCCESS;
322}
323
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800324DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
325 "grx-dns-add A.B.C.D",
326 "Add DNS server\nIPv4 address\n")
327{
328 struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node);
329 node->family = AF_INET;
330 inet_aton(argv[0], &node->addr.addr4);
331
332 node->next = sgsn->ares_servers;
333 sgsn->ares_servers = node;
334 return CMD_SUCCESS;
335}
336
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100337#define APN_STR "Configure the information per APN\n"
338#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
339
340static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
341 const char *imsi_prefix, int ggsn_id)
342{
343 struct apn_ctx *actx;
344 struct sgsn_ggsn_ctx *ggsn;
345
346 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
347 if (ggsn == NULL) {
348 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
349 ggsn_id, VTY_NEWLINE);
350 return CMD_WARNING;
351 }
352
353 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
354 if (!actx) {
355 vty_out(vty, "%% unable to create APN context for %s/%s%s",
356 apn_str, imsi_prefix, VTY_NEWLINE);
357 return CMD_WARNING;
358 }
359
360 actx->ggsn = ggsn;
361
362 return CMD_SUCCESS;
363}
364
Harald Welted193cb32010-05-17 22:58:03 +0200365DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
366 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100367 APN_STR APN_GW_STR
368 "Select the GGSN to use when the APN gateway prefix matches\n"
369 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200370{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100371
372 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200373}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100374
375DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
376 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
377 APN_STR APN_GW_STR
378 "Restrict rule to a certain IMSI prefix\n"
379 "An IMSI prefix\n"
380 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
381 "The GGSN id")
382{
383
384 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
385}
Harald Welted193cb32010-05-17 22:58:03 +0200386
387const struct value_string gprs_mm_st_strs[] = {
388 { GMM_DEREGISTERED, "DEREGISTERED" },
389 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
390 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200391 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200392 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
393 { 0, NULL }
394};
395
396static void vty_dump_pdp(struct vty *vty, const char *pfx,
397 struct sgsn_pdp_ctx *pdp)
398{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200399 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welted193cb32010-05-17 22:58:03 +0200400 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200401 pfx, imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200402 vty_out(vty, "%s APN: %s%s", pfx,
403 gprs_apn2str(pdp->lib->apn_use.v, pdp->lib->apn_use.l),
404 VTY_NEWLINE);
405 vty_out(vty, "%s PDP Address: %s%s", pfx,
406 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
407 VTY_NEWLINE);
Harald Welteefbdee92010-06-10 00:20:12 +0200408 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200409}
410
411static void vty_dump_mmctx(struct vty *vty, const char *pfx,
412 struct sgsn_mm_ctx *mm, int pdp)
413{
414 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
415 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200416 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
417 pfx, mm->msisdn, mm->tlli, mm->hlr, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200418 vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, "
419 "Cell ID: %u%s", pfx,
420 get_value_string(gprs_mm_st_strs, mm->mm_state),
421 mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac,
422 mm->cell_id, VTY_NEWLINE);
423
Harald Welte8acd88f2010-05-18 10:57:45 +0200424 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
425
Harald Welted193cb32010-05-17 22:58:03 +0200426 if (pdp) {
427 struct sgsn_pdp_ctx *pdp;
428
429 llist_for_each_entry(pdp, &mm->pdp_list, list)
430 vty_dump_pdp(vty, " ", pdp);
431 }
432}
433
434DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
435 SHOW_STR "Display information about the SGSN")
436{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100437 if (sgsn->gsup_client) {
438 struct ipa_client_conn *link = sgsn->gsup_client->link;
439 vty_out(vty,
440 " Remote authorization: %sconnected to %s:%d via GSUP%s",
441 sgsn->gsup_client->is_connected ? "" : "not ",
442 link->addr, link->port,
443 VTY_NEWLINE);
444 }
Harald Welted193cb32010-05-17 22:58:03 +0200445 /* FIXME: statistics */
446 return CMD_SUCCESS;
447}
448
449#define MMCTX_STR "MM Context\n"
450#define INCLUDE_PDP_STR "Include PDP Context Information\n"
451
452#if 0
453DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
454 "show mm-context tlli HEX [pdp]",
455 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
456{
457 uint32_t tlli;
458 struct sgsn_mm_ctx *mm;
459
460 tlli = strtoul(argv[0], NULL, 16);
461 mm = sgsn_mm_ctx_by_tlli(tlli);
462 if (!mm) {
463 vty_out(vty, "No MM context for TLLI %08x%s",
464 tlli, VTY_NEWLINE);
465 return CMD_WARNING;
466 }
467 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
468 return CMD_SUCCESS;
469}
470#endif
471
472DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
473 "show mm-context imsi IMSI [pdp]",
474 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
475 INCLUDE_PDP_STR)
476{
477 struct sgsn_mm_ctx *mm;
478
479 mm = sgsn_mm_ctx_by_imsi(argv[0]);
480 if (!mm) {
481 vty_out(vty, "No MM context for IMSI %s%s",
482 argv[0], VTY_NEWLINE);
483 return CMD_WARNING;
484 }
485 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
486 return CMD_SUCCESS;
487}
488
489DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
490 "show mm-context all [pdp]",
491 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
492{
493 struct sgsn_mm_ctx *mm;
494
495 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
496 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
497
498 return CMD_SUCCESS;
499}
500
Harald Welted193cb32010-05-17 22:58:03 +0200501DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
502 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100503 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200504{
505 struct sgsn_pdp_ctx *pdp;
506
507 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
508 vty_dump_pdp(vty, "", pdp);
509
510 return CMD_SUCCESS;
511}
Harald Welte288be162010-05-01 16:48:27 +0200512
Harald Welte7f6da482013-03-19 11:00:13 +0100513
514DEFUN(imsi_acl, cfg_imsi_acl_cmd,
515 "imsi-acl (add|del) IMSI",
516 "Access Control List of foreign IMSIs\n"
517 "Add IMSI to ACL\n"
518 "Remove IMSI from ACL\n"
519 "IMSI of subscriber\n")
520{
521 const char *op = argv[0];
522 const char *imsi = argv[1];
523 int rc;
524
525 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200526 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100527 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200528 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100529
530 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100531 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
532
Harald Welte7f6da482013-03-19 11:00:13 +0100533 return CMD_WARNING;
534 }
535
536 return CMD_SUCCESS;
537}
538
Harald Welte3dfb5492013-03-19 11:48:54 +0100539DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100540 "auth-policy (accept-all|closed|acl-only|remote)",
Harald Welte3dfb5492013-03-19 11:48:54 +0100541 "Autorization Policy of SGSN\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100542 "Accept all IMSIs (DANGEROUS)\n"
543 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100544 "Accept only subscribers in the ACL\n"
545 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100546{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100547 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100548 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100549 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100550 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100551 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100552
553 return CMD_SUCCESS;
554}
555
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100556/* Subscriber */
557#include <openbsc/gsm_subscriber.h>
558
559static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending)
560{
561 char expire_time[200];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100562 struct gsm_auth_tuple *at;
563 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100564 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100565
566 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
567 subscr->authorized, VTY_NEWLINE);
568 if (strlen(subscr->name))
569 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
570 if (strlen(subscr->extension))
571 vty_out(vty, " Extension: %s%s", subscr->extension,
572 VTY_NEWLINE);
573 vty_out(vty, " LAC: %d/0x%x%s",
574 subscr->lac, subscr->lac, VTY_NEWLINE);
575 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
576 if (subscr->tmsi != GSM_RESERVED_TMSI)
577 vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
578 VTY_NEWLINE);
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400579 if (subscr->sgsn_data->msisdn_len > 0)
580 vty_out(vty, " MSISDN (BCD): %s%s",
581 osmo_hexdump(subscr->sgsn_data->msisdn,
582 subscr->sgsn_data->msisdn_len),
583 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100584
585 if (strlen(subscr->equipment.imei) > 0)
586 vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE);
587
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100588 for (at_idx = 0; at_idx < ARRAY_SIZE(subscr->sgsn_data->auth_triplets);
589 at_idx++) {
590 at = &subscr->sgsn_data->auth_triplets[at_idx];
591 if (at->key_seq == GSM_KEY_SEQ_INVAL)
592 continue;
593
594 vty_out(vty, " A3A8 tuple (used %d times): ",
595 at->use_count);
596 vty_out(vty, " seq # : %d, ",
597 at->key_seq);
598 vty_out(vty, " RAND : %s, ",
599 osmo_hexdump(at->rand, sizeof(at->rand)));
600 vty_out(vty, " SRES : %s, ",
601 osmo_hexdump(at->sres, sizeof(at->sres)));
602 vty_out(vty, " Kc : %s%s",
603 osmo_hexdump(at->kc, sizeof(at->kc)),
604 VTY_NEWLINE);
605 }
606
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100607 llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400608 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s' QoS: %s%s",
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100609 pdp->context_id, pdp->pdp_type, pdp->apn_str,
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400610 osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len),
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100611 VTY_NEWLINE);
612 }
613
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100614 /* print the expiration time of a subscriber */
615 if (subscr->expire_lu) {
616 strftime(expire_time, sizeof(expire_time),
617 "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
618 expire_time[sizeof(expire_time) - 1] = '\0';
619 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
620 }
621
622 if (subscr->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100623 vty_out(vty, " Flags: %s%s%s%s%s%s",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100624 subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ?
625 "FIRST_CONTACT " : "",
626 subscr->flags & GPRS_SUBSCRIBER_CANCELLED ?
627 "CANCELLED " : "",
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100628 subscr->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
629 "UPDATE_LOCATION_PENDING " : "",
630 subscr->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
631 "AUTH_INFO_PENDING " : "",
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100632 subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
633 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100634 VTY_NEWLINE);
635
636 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
637}
638
639DEFUN(show_subscr_cache,
640 show_subscr_cache_cmd,
641 "show subscriber cache",
642 SHOW_STR "Show information about subscribers\n"
643 "Display contents of subscriber cache\n")
644{
645 struct gsm_subscriber *subscr;
646
647 llist_for_each_entry(subscr, &active_subscribers, entry) {
648 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
649 subscr_dump_full_vty(vty, subscr, 0);
650 }
651
652 return CMD_SUCCESS;
653}
654
655#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
656#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
657 "Use the IMSI to select the subscriber\n" \
658 "The IMSI\n"
659
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100660#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
661
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100662DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
663 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
664 UPDATE_SUBSCR_HELP
665 UPDATE_SUBSCR_INSERT_HELP
666 "Update authentication triplet\n"
667 "Triplet index\n"
668 "Set SRES value\nSRES value (4 byte) in hex\n"
669 "Set RAND value\nRAND value (16 byte) in hex\n"
670 "Set Kc value\nKc value (8 byte) in hex\n")
671{
672 const char *imsi = argv[0];
673 const int cksn = atoi(argv[1]) - 1;
674 const char *sres_str = argv[2];
675 const char *rand_str = argv[3];
676 const char *kc_str = argv[4];
677 struct gsm_auth_tuple at = {0,};
678
679 struct gsm_subscriber *subscr;
680
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100681 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100682 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100683 vty_out(vty, "%% unable get subscriber record for %s%s",
684 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100685 return CMD_WARNING;
686 }
687
688 OSMO_ASSERT(subscr->sgsn_data);
689
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100690 if (osmo_hexparse(sres_str, &at.sres[0], sizeof(at.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100691 vty_out(vty, "%% invalid SRES value '%s'%s",
692 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100693 goto failed;
694 }
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100695 if (osmo_hexparse(rand_str, &at.rand[0], sizeof(at.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100696 vty_out(vty, "%% invalid RAND value '%s'%s",
697 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100698 goto failed;
699 }
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100700 if (osmo_hexparse(kc_str, &at.kc[0], sizeof(at.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100701 vty_out(vty, "%% invalid Kc value '%s'%s",
702 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100703 goto failed;
704 }
705 at.key_seq = cksn;
706
707 subscr->sgsn_data->auth_triplets[cksn] = at;
708 subscr->sgsn_data->auth_triplets_updated = 1;
709
710 subscr_put(subscr);
711
712 return CMD_SUCCESS;
713
714failed:
715 subscr_put(subscr);
716 return CMD_SUCCESS;
717}
718
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100719DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100720 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100721 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100722 "Cancel (remove) subscriber record\n"
723 "The MS moved to another SGSN\n"
724 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100725{
726 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100727 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100728
729 struct gsm_subscriber *subscr;
730
731 subscr = gprs_subscr_get_by_imsi(imsi);
732 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100733 vty_out(vty, "%% no subscriber record for %s%s",
734 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100735 return CMD_WARNING;
736 }
737
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100738 if (strcmp(cancel_type, "update-procedure") == 0)
739 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
740 else
741 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
742
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100743 gprs_subscr_cancel(subscr);
744 subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100745
746 return CMD_SUCCESS;
747}
748
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100749DEFUN(update_subscr_create, update_subscr_create_cmd,
750 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100751 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100752 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100753{
754 const char *imsi = argv[0];
755
756 struct gsm_subscriber *subscr;
757
758 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100759 if (subscr) {
760 vty_out(vty, "%% subscriber record already exists for %s%s",
761 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100762 return CMD_WARNING;
763 }
764
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100765 subscr = gprs_subscr_get_or_create(imsi);
766 subscr->keep_in_ram = 1;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100767 subscr_put(subscr);
768
769 return CMD_SUCCESS;
770}
771
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100772DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
773 UPDATE_SUBSCR_STR "destroy",
774 UPDATE_SUBSCR_HELP
775 "Destroy a subscriber entry\n")
776{
777 const char *imsi = argv[0];
778
779 struct gsm_subscriber *subscr;
780
781 subscr = gprs_subscr_get_by_imsi(imsi);
782 if (!subscr) {
783 vty_out(vty, "%% subscriber record does not exist for %s%s",
784 imsi, VTY_NEWLINE);
785 return CMD_WARNING;
786 }
787
788 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100789 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100790 gprs_subscr_cancel(subscr);
791 if (subscr->use_count > 1)
792 vty_out(vty, "%% subscriber is still in use%s",
793 VTY_NEWLINE);
794 subscr_put(subscr);
795
796 return CMD_SUCCESS;
797}
798
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100799#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
800 "unknown-subscriber|roaming-not-allowed"
801
802#define UL_ERR_HELP \
803 "Force error code SystemFailure\n" \
804 "Force error code DataMissing\n" \
805 "Force error code UnexpectedDataValue\n" \
806 "Force error code UnknownSubscriber\n" \
807 "Force error code RoamingNotAllowed\n"
808
809DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
810 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
811 UPDATE_SUBSCR_HELP
812 "Complete the update location procedure\n"
813 "The update location request succeeded\n"
814 UL_ERR_HELP)
815{
816 const char *imsi = argv[0];
817 const char *ret_code_str = argv[1];
818
819 struct gsm_subscriber *subscr;
820
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100821 const struct value_string cause_mapping[] = {
822 { GMM_CAUSE_NET_FAIL, "system-failure" },
823 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
824 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
825 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
826 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
827 { 0, NULL }
828 };
829
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100830 subscr = gprs_subscr_get_by_imsi(imsi);
831 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100832 vty_out(vty, "%% unable to get subscriber record for %s%s",
833 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100834 return CMD_WARNING;
835 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100836
837 if (strcmp(ret_code_str, "ok") == 0) {
838 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100839 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100840 } else {
841 subscr->sgsn_data->error_cause =
842 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100843 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100844 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100845
846 gprs_subscr_update(subscr);
847
848 subscr_put(subscr);
849
850 return CMD_SUCCESS;
851}
852
853DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
854 UPDATE_SUBSCR_STR "update-auth-info",
855 UPDATE_SUBSCR_HELP
856 "Complete the send authentication info procedure\n")
857{
858 const char *imsi = argv[0];
859
860 struct gsm_subscriber *subscr;
861
862 subscr = gprs_subscr_get_by_imsi(imsi);
863 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100864 vty_out(vty, "%% unable to get subscriber record for %s%s",
865 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100866 return CMD_WARNING;
867 }
868
869 gprs_subscr_update_auth_info(subscr);
870
871 subscr_put(subscr);
872
873 return CMD_SUCCESS;
874}
875
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100876DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
877 "gsup remote-ip A.B.C.D",
878 "GSUP Parameters\n"
879 "Set the IP address of the remote GSUP server\n"
880 "IPv4 Address\n")
881{
882 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
883
884 return CMD_SUCCESS;
885}
886
887DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
888 "gsup remote-port <0-65535>",
889 "GSUP Parameters\n"
890 "Set the TCP port of the remote GSUP server\n"
891 "Remote TCP port\n")
892{
893 g_cfg->gsup_server_port = atoi(argv[0]);
894
895 return CMD_SUCCESS;
896}
897
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +0100898DEFUN(cfg_apn_name, cfg_apn_name_cmd,
899 "access-point-name NAME",
900 "Configure a global list of allowed APNs\n"
901 "Add this NAME to the list\n")
902{
903 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
904}
905
906DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
907 "no access-point-name NAME",
908 NO_STR "Configure a global list of allowed APNs\n"
909 "Remove entry with NAME\n")
910{
911 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
912 if (!apn_ctx)
913 return CMD_SUCCESS;
914
915 sgsn_apn_ctx_free(apn_ctx);
916 return CMD_SUCCESS;
917}
918
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200919DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
920 "cdr filename NAME",
921 "CDR\nSet filename\nname\n")
922{
923 talloc_free(g_cfg->cdr.filename);
924 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
925 return CMD_SUCCESS;
926}
927
928DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
929 "no cdr filename",
930 NO_STR "CDR\nDisable CDR generation\n")
931{
932 talloc_free(g_cfg->cdr.filename);
933 g_cfg->cdr.filename = NULL;
934 return CMD_SUCCESS;
935}
936
937DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
938 "cdr interval <1-2147483647>",
939 "CDR\nPDP periodic log interval\nSeconds\n")
940{
941 g_cfg->cdr.interval = atoi(argv[0]);
942 return CMD_SUCCESS;
943}
944
Harald Welte288be162010-05-01 16:48:27 +0200945int sgsn_vty_init(void)
946{
Harald Welted193cb32010-05-17 22:58:03 +0200947 install_element_ve(&show_sgsn_cmd);
948 //install_element_ve(&show_mmctx_tlli_cmd);
949 install_element_ve(&show_mmctx_imsi_cmd);
950 install_element_ve(&show_mmctx_all_cmd);
951 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100952 install_element_ve(&show_subscr_cache_cmd);
953
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100954 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100955 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100956 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100957 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100958 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
959 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Harald Welte288be162010-05-01 16:48:27 +0200960
961 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
962 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeck36722e12013-10-29 09:30:30 +0100963 vty_install_default(SGSN_NODE);
Harald Weltee300d002010-06-02 12:41:34 +0200964 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +0200965 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
966 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
967 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +0100968 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +0100969 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100970 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
971 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100972 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
973 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +0100974 install_element(SGSN_NODE, &cfg_apn_name_cmd);
975 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200976 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
977 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
978 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800979 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800980 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +0200981
Harald Welte94508822015-08-15 19:08:21 +0200982 install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd);
983 install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd);
984 install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd);
985 install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd);
986 install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd);
987 install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd);
988 install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd);
989 install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd);
990 install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd);
991 install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd);
992 install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd);
993 install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd);
994
Harald Welte288be162010-05-01 16:48:27 +0200995 return 0;
996}
997
998int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
999{
1000 int rc;
1001
1002 g_cfg = cfg;
Harald Welte7f6da482013-03-19 11:00:13 +01001003
Harald Welte94508822015-08-15 19:08:21 +02001004 g_cfg->timers.T3312 = GSM0408_T3312_SECS;
1005 g_cfg->timers.T3322 = GSM0408_T3322_SECS;
1006 g_cfg->timers.T3350 = GSM0408_T3350_SECS;
1007 g_cfg->timers.T3360 = GSM0408_T3360_SECS;
1008 g_cfg->timers.T3370 = GSM0408_T3370_SECS;
1009 g_cfg->timers.T3313 = GSM0408_T3313_SECS;
1010 g_cfg->timers.T3314 = GSM0408_T3314_SECS;
1011 g_cfg->timers.T3316 = GSM0408_T3316_SECS;
1012 g_cfg->timers.T3385 = GSM0408_T3385_SECS;
1013 g_cfg->timers.T3386 = GSM0408_T3386_SECS;
1014 g_cfg->timers.T3395 = GSM0408_T3395_SECS;
1015 g_cfg->timers.T3397 = GSM0408_T3397_SECS;
1016
Harald Weltedcccb182010-05-16 20:52:23 +02001017 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001018 if (rc < 0) {
1019 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1020 return rc;
1021 }
1022
1023 return 0;
1024}