blob: 3a73c9f553f605651bd2a5cd513a57c5355ab2a0 [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 */
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);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200217
218 vty_out(vty, " gsup oap-id %d%s",
219 (int)g_cfg->oap.client_id, VTY_NEWLINE);
220 if (g_cfg->oap.secret_k_present != 0)
221 vty_out(vty, " gsup oap-k %s%s",
222 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
223 VTY_NEWLINE);
224 if (g_cfg->oap.secret_opc_present != 0)
225 vty_out(vty, " gsup oap-opc %s%s",
226 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
227 VTY_NEWLINE);
228
Harald Welte7f6da482013-03-19 11:00:13 +0100229 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
230 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
231
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100232 if (llist_empty(&sgsn_apn_ctxts))
233 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
234 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
235 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200236 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100237 actx->name, actx->imsi_prefix, actx->ggsn->id,
238 VTY_NEWLINE);
239 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200240 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100241 actx->ggsn->id, VTY_NEWLINE);
242 }
243
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200244 if (g_cfg->cdr.filename)
245 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
246 else
247 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
248 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
249
Harald Welte94508822015-08-15 19:08:21 +0200250 vty_out(vty, " timer t3312 %d%s", g_cfg->timers.T3312, VTY_NEWLINE);
251 vty_out(vty, " timer t3322 %d%s", g_cfg->timers.T3322, VTY_NEWLINE);
252 vty_out(vty, " timer t3350 %d%s", g_cfg->timers.T3350, VTY_NEWLINE);
253 vty_out(vty, " timer t3360 %d%s", g_cfg->timers.T3360, VTY_NEWLINE);
254 vty_out(vty, " timer t3370 %d%s", g_cfg->timers.T3370, VTY_NEWLINE);
255 vty_out(vty, " timer t3313 %d%s", g_cfg->timers.T3313, VTY_NEWLINE);
256 vty_out(vty, " timer t3314 %d%s", g_cfg->timers.T3314, VTY_NEWLINE);
257 vty_out(vty, " timer t3316 %d%s", g_cfg->timers.T3316, VTY_NEWLINE);
258 vty_out(vty, " timer t3385 %d%s", g_cfg->timers.T3385, VTY_NEWLINE);
259 vty_out(vty, " timer t3386 %d%s", g_cfg->timers.T3386, VTY_NEWLINE);
260 vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE);
261 vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE);
262
Harald Welte288be162010-05-01 16:48:27 +0200263 return CMD_SUCCESS;
264}
265
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100266#define SGSN_STR "Configure the SGSN\n"
267#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200268
269DEFUN(cfg_sgsn, cfg_sgsn_cmd,
270 "sgsn",
271 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200272{
273 vty->node = SGSN_NODE;
274 return CMD_SUCCESS;
275}
276
Harald Weltee300d002010-06-02 12:41:34 +0200277DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
278 "gtp local-ip A.B.C.D",
279 "GTP Parameters\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100280 "Set the IP address for the local GTP bind\n"
281 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200282{
283 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
284
285 return CMD_SUCCESS;
286}
287
Harald Welted193cb32010-05-17 22:58:03 +0200288DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
289 "ggsn <0-255> remote-ip A.B.C.D",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100290 GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200291{
292 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200293 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200294
Harald Welted193cb32010-05-17 22:58:03 +0200295 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200296
Harald Welted193cb32010-05-17 22:58:03 +0200297 return CMD_SUCCESS;
298}
299
300#if 0
301DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
302 "ggsn <0-255> remote-port <0-65535>",
303 "")
304{
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 uint16_t port = atoi(argv[1]);
308
309}
310#endif
311
312DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
313 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100314 GGSN_STR "GGSN Number\n" "GTP Version\n"
315 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200316{
317 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200318 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200319
320 if (atoi(argv[1]))
321 ggc->gtp_version = 1;
322 else
323 ggc->gtp_version = 0;
324
325 return CMD_SUCCESS;
326}
327
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800328DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
329 "ggsn dynamic",
330 GGSN_STR "Enable dynamic GRX based look-up (requires restart)\n")
331{
332 sgsn->cfg.dynamic_lookup = 1;
333 return CMD_SUCCESS;
334}
335
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800336DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
337 "grx-dns-add A.B.C.D",
338 "Add DNS server\nIPv4 address\n")
339{
340 struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node);
341 node->family = AF_INET;
342 inet_aton(argv[0], &node->addr.addr4);
343
344 node->next = sgsn->ares_servers;
345 sgsn->ares_servers = node;
346 return CMD_SUCCESS;
347}
348
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100349#define APN_STR "Configure the information per APN\n"
350#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
351
352static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
353 const char *imsi_prefix, int ggsn_id)
354{
355 struct apn_ctx *actx;
356 struct sgsn_ggsn_ctx *ggsn;
357
358 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
359 if (ggsn == NULL) {
360 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
361 ggsn_id, VTY_NEWLINE);
362 return CMD_WARNING;
363 }
364
365 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
366 if (!actx) {
367 vty_out(vty, "%% unable to create APN context for %s/%s%s",
368 apn_str, imsi_prefix, VTY_NEWLINE);
369 return CMD_WARNING;
370 }
371
372 actx->ggsn = ggsn;
373
374 return CMD_SUCCESS;
375}
376
Harald Welted193cb32010-05-17 22:58:03 +0200377DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
378 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100379 APN_STR APN_GW_STR
380 "Select the GGSN to use when the APN gateway prefix matches\n"
381 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200382{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100383
384 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200385}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100386
387DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
388 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
389 APN_STR APN_GW_STR
390 "Restrict rule to a certain IMSI prefix\n"
391 "An IMSI prefix\n"
392 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
393 "The GGSN id")
394{
395
396 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
397}
Harald Welted193cb32010-05-17 22:58:03 +0200398
399const struct value_string gprs_mm_st_strs[] = {
400 { GMM_DEREGISTERED, "DEREGISTERED" },
401 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
402 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200403 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200404 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
405 { 0, NULL }
406};
407
408static void vty_dump_pdp(struct vty *vty, const char *pfx,
409 struct sgsn_pdp_ctx *pdp)
410{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200411 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welted193cb32010-05-17 22:58:03 +0200412 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200413 pfx, imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200414 vty_out(vty, "%s APN: %s%s", pfx,
415 gprs_apn2str(pdp->lib->apn_use.v, pdp->lib->apn_use.l),
416 VTY_NEWLINE);
417 vty_out(vty, "%s PDP Address: %s%s", pfx,
418 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
419 VTY_NEWLINE);
Harald Welteefbdee92010-06-10 00:20:12 +0200420 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200421}
422
423static void vty_dump_mmctx(struct vty *vty, const char *pfx,
424 struct sgsn_mm_ctx *mm, int pdp)
425{
426 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
427 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200428 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
429 pfx, mm->msisdn, mm->tlli, mm->hlr, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200430 vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, "
431 "Cell ID: %u%s", pfx,
432 get_value_string(gprs_mm_st_strs, mm->mm_state),
433 mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac,
434 mm->cell_id, VTY_NEWLINE);
435
Harald Welte8acd88f2010-05-18 10:57:45 +0200436 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
437
Harald Welted193cb32010-05-17 22:58:03 +0200438 if (pdp) {
439 struct sgsn_pdp_ctx *pdp;
440
441 llist_for_each_entry(pdp, &mm->pdp_list, list)
442 vty_dump_pdp(vty, " ", pdp);
443 }
444}
445
446DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
447 SHOW_STR "Display information about the SGSN")
448{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100449 if (sgsn->gsup_client) {
450 struct ipa_client_conn *link = sgsn->gsup_client->link;
451 vty_out(vty,
452 " Remote authorization: %sconnected to %s:%d via GSUP%s",
453 sgsn->gsup_client->is_connected ? "" : "not ",
454 link->addr, link->port,
455 VTY_NEWLINE);
456 }
Harald Welted193cb32010-05-17 22:58:03 +0200457 /* FIXME: statistics */
458 return CMD_SUCCESS;
459}
460
461#define MMCTX_STR "MM Context\n"
462#define INCLUDE_PDP_STR "Include PDP Context Information\n"
463
464#if 0
465DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
466 "show mm-context tlli HEX [pdp]",
467 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
468{
469 uint32_t tlli;
470 struct sgsn_mm_ctx *mm;
471
472 tlli = strtoul(argv[0], NULL, 16);
473 mm = sgsn_mm_ctx_by_tlli(tlli);
474 if (!mm) {
475 vty_out(vty, "No MM context for TLLI %08x%s",
476 tlli, VTY_NEWLINE);
477 return CMD_WARNING;
478 }
479 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
480 return CMD_SUCCESS;
481}
482#endif
483
484DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
485 "show mm-context imsi IMSI [pdp]",
486 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
487 INCLUDE_PDP_STR)
488{
489 struct sgsn_mm_ctx *mm;
490
491 mm = sgsn_mm_ctx_by_imsi(argv[0]);
492 if (!mm) {
493 vty_out(vty, "No MM context for IMSI %s%s",
494 argv[0], VTY_NEWLINE);
495 return CMD_WARNING;
496 }
497 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
498 return CMD_SUCCESS;
499}
500
501DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
502 "show mm-context all [pdp]",
503 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
504{
505 struct sgsn_mm_ctx *mm;
506
507 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
508 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
509
510 return CMD_SUCCESS;
511}
512
Harald Welted193cb32010-05-17 22:58:03 +0200513DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
514 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100515 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200516{
517 struct sgsn_pdp_ctx *pdp;
518
519 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
520 vty_dump_pdp(vty, "", pdp);
521
522 return CMD_SUCCESS;
523}
Harald Welte288be162010-05-01 16:48:27 +0200524
Harald Welte7f6da482013-03-19 11:00:13 +0100525
526DEFUN(imsi_acl, cfg_imsi_acl_cmd,
527 "imsi-acl (add|del) IMSI",
528 "Access Control List of foreign IMSIs\n"
529 "Add IMSI to ACL\n"
530 "Remove IMSI from ACL\n"
531 "IMSI of subscriber\n")
532{
533 const char *op = argv[0];
534 const char *imsi = argv[1];
535 int rc;
536
537 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200538 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100539 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200540 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100541
542 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100543 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
544
Harald Welte7f6da482013-03-19 11:00:13 +0100545 return CMD_WARNING;
546 }
547
548 return CMD_SUCCESS;
549}
550
Harald Welte3dfb5492013-03-19 11:48:54 +0100551DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100552 "auth-policy (accept-all|closed|acl-only|remote)",
Harald Welte3dfb5492013-03-19 11:48:54 +0100553 "Autorization Policy of SGSN\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100554 "Accept all IMSIs (DANGEROUS)\n"
555 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100556 "Accept only subscribers in the ACL\n"
557 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100558{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100559 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100560 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100561 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100562 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100563 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100564
565 return CMD_SUCCESS;
566}
567
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100568/* Subscriber */
569#include <openbsc/gsm_subscriber.h>
570
571static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending)
572{
573 char expire_time[200];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100574 struct gsm_auth_tuple *at;
575 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100576 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100577
578 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
579 subscr->authorized, VTY_NEWLINE);
580 if (strlen(subscr->name))
581 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
582 if (strlen(subscr->extension))
583 vty_out(vty, " Extension: %s%s", subscr->extension,
584 VTY_NEWLINE);
585 vty_out(vty, " LAC: %d/0x%x%s",
586 subscr->lac, subscr->lac, VTY_NEWLINE);
587 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
588 if (subscr->tmsi != GSM_RESERVED_TMSI)
589 vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
590 VTY_NEWLINE);
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400591 if (subscr->sgsn_data->msisdn_len > 0)
592 vty_out(vty, " MSISDN (BCD): %s%s",
593 osmo_hexdump(subscr->sgsn_data->msisdn,
594 subscr->sgsn_data->msisdn_len),
595 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100596
597 if (strlen(subscr->equipment.imei) > 0)
598 vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE);
599
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100600 for (at_idx = 0; at_idx < ARRAY_SIZE(subscr->sgsn_data->auth_triplets);
601 at_idx++) {
602 at = &subscr->sgsn_data->auth_triplets[at_idx];
603 if (at->key_seq == GSM_KEY_SEQ_INVAL)
604 continue;
605
606 vty_out(vty, " A3A8 tuple (used %d times): ",
607 at->use_count);
608 vty_out(vty, " seq # : %d, ",
609 at->key_seq);
610 vty_out(vty, " RAND : %s, ",
611 osmo_hexdump(at->rand, sizeof(at->rand)));
612 vty_out(vty, " SRES : %s, ",
613 osmo_hexdump(at->sres, sizeof(at->sres)));
614 vty_out(vty, " Kc : %s%s",
615 osmo_hexdump(at->kc, sizeof(at->kc)),
616 VTY_NEWLINE);
617 }
618
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100619 llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400620 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s' QoS: %s%s",
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100621 pdp->context_id, pdp->pdp_type, pdp->apn_str,
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400622 osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len),
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100623 VTY_NEWLINE);
624 }
625
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100626 /* print the expiration time of a subscriber */
627 if (subscr->expire_lu) {
628 strftime(expire_time, sizeof(expire_time),
629 "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
630 expire_time[sizeof(expire_time) - 1] = '\0';
631 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
632 }
633
634 if (subscr->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100635 vty_out(vty, " Flags: %s%s%s%s%s%s",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100636 subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ?
637 "FIRST_CONTACT " : "",
638 subscr->flags & GPRS_SUBSCRIBER_CANCELLED ?
639 "CANCELLED " : "",
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100640 subscr->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
641 "UPDATE_LOCATION_PENDING " : "",
642 subscr->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
643 "AUTH_INFO_PENDING " : "",
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100644 subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
645 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100646 VTY_NEWLINE);
647
648 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
649}
650
651DEFUN(show_subscr_cache,
652 show_subscr_cache_cmd,
653 "show subscriber cache",
654 SHOW_STR "Show information about subscribers\n"
655 "Display contents of subscriber cache\n")
656{
657 struct gsm_subscriber *subscr;
658
659 llist_for_each_entry(subscr, &active_subscribers, entry) {
660 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
661 subscr_dump_full_vty(vty, subscr, 0);
662 }
663
664 return CMD_SUCCESS;
665}
666
667#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
668#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
669 "Use the IMSI to select the subscriber\n" \
670 "The IMSI\n"
671
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100672#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
673
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100674DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
675 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
676 UPDATE_SUBSCR_HELP
677 UPDATE_SUBSCR_INSERT_HELP
678 "Update authentication triplet\n"
679 "Triplet index\n"
680 "Set SRES value\nSRES value (4 byte) in hex\n"
681 "Set RAND value\nRAND value (16 byte) in hex\n"
682 "Set Kc value\nKc value (8 byte) in hex\n")
683{
684 const char *imsi = argv[0];
685 const int cksn = atoi(argv[1]) - 1;
686 const char *sres_str = argv[2];
687 const char *rand_str = argv[3];
688 const char *kc_str = argv[4];
689 struct gsm_auth_tuple at = {0,};
690
691 struct gsm_subscriber *subscr;
692
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100693 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100694 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100695 vty_out(vty, "%% unable get subscriber record for %s%s",
696 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100697 return CMD_WARNING;
698 }
699
700 OSMO_ASSERT(subscr->sgsn_data);
701
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100702 if (osmo_hexparse(sres_str, &at.sres[0], sizeof(at.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100703 vty_out(vty, "%% invalid SRES value '%s'%s",
704 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100705 goto failed;
706 }
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100707 if (osmo_hexparse(rand_str, &at.rand[0], sizeof(at.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100708 vty_out(vty, "%% invalid RAND value '%s'%s",
709 rand_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(kc_str, &at.kc[0], sizeof(at.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100713 vty_out(vty, "%% invalid Kc value '%s'%s",
714 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100715 goto failed;
716 }
717 at.key_seq = cksn;
718
719 subscr->sgsn_data->auth_triplets[cksn] = at;
720 subscr->sgsn_data->auth_triplets_updated = 1;
721
722 subscr_put(subscr);
723
724 return CMD_SUCCESS;
725
726failed:
727 subscr_put(subscr);
728 return CMD_SUCCESS;
729}
730
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100731DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100732 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100733 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100734 "Cancel (remove) subscriber record\n"
735 "The MS moved to another SGSN\n"
736 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100737{
738 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100739 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100740
741 struct gsm_subscriber *subscr;
742
743 subscr = gprs_subscr_get_by_imsi(imsi);
744 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100745 vty_out(vty, "%% no subscriber record for %s%s",
746 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100747 return CMD_WARNING;
748 }
749
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100750 if (strcmp(cancel_type, "update-procedure") == 0)
751 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
752 else
753 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
754
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100755 gprs_subscr_cancel(subscr);
756 subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100757
758 return CMD_SUCCESS;
759}
760
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100761DEFUN(update_subscr_create, update_subscr_create_cmd,
762 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100763 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100764 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100765{
766 const char *imsi = argv[0];
767
768 struct gsm_subscriber *subscr;
769
770 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100771 if (subscr) {
772 vty_out(vty, "%% subscriber record already exists for %s%s",
773 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100774 return CMD_WARNING;
775 }
776
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100777 subscr = gprs_subscr_get_or_create(imsi);
778 subscr->keep_in_ram = 1;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100779 subscr_put(subscr);
780
781 return CMD_SUCCESS;
782}
783
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100784DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
785 UPDATE_SUBSCR_STR "destroy",
786 UPDATE_SUBSCR_HELP
787 "Destroy a subscriber entry\n")
788{
789 const char *imsi = argv[0];
790
791 struct gsm_subscriber *subscr;
792
793 subscr = gprs_subscr_get_by_imsi(imsi);
794 if (!subscr) {
795 vty_out(vty, "%% subscriber record does not exist for %s%s",
796 imsi, VTY_NEWLINE);
797 return CMD_WARNING;
798 }
799
800 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100801 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100802 gprs_subscr_cancel(subscr);
803 if (subscr->use_count > 1)
804 vty_out(vty, "%% subscriber is still in use%s",
805 VTY_NEWLINE);
806 subscr_put(subscr);
807
808 return CMD_SUCCESS;
809}
810
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100811#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
812 "unknown-subscriber|roaming-not-allowed"
813
814#define UL_ERR_HELP \
815 "Force error code SystemFailure\n" \
816 "Force error code DataMissing\n" \
817 "Force error code UnexpectedDataValue\n" \
818 "Force error code UnknownSubscriber\n" \
819 "Force error code RoamingNotAllowed\n"
820
821DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
822 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
823 UPDATE_SUBSCR_HELP
824 "Complete the update location procedure\n"
825 "The update location request succeeded\n"
826 UL_ERR_HELP)
827{
828 const char *imsi = argv[0];
829 const char *ret_code_str = argv[1];
830
831 struct gsm_subscriber *subscr;
832
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100833 const struct value_string cause_mapping[] = {
834 { GMM_CAUSE_NET_FAIL, "system-failure" },
835 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
836 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
837 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
838 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
839 { 0, NULL }
840 };
841
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100842 subscr = gprs_subscr_get_by_imsi(imsi);
843 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100844 vty_out(vty, "%% unable to get subscriber record for %s%s",
845 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100846 return CMD_WARNING;
847 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100848
849 if (strcmp(ret_code_str, "ok") == 0) {
850 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100851 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100852 } else {
853 subscr->sgsn_data->error_cause =
854 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100855 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100856 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100857
858 gprs_subscr_update(subscr);
859
860 subscr_put(subscr);
861
862 return CMD_SUCCESS;
863}
864
865DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
866 UPDATE_SUBSCR_STR "update-auth-info",
867 UPDATE_SUBSCR_HELP
868 "Complete the send authentication info procedure\n")
869{
870 const char *imsi = argv[0];
871
872 struct gsm_subscriber *subscr;
873
874 subscr = gprs_subscr_get_by_imsi(imsi);
875 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100876 vty_out(vty, "%% unable to get subscriber record for %s%s",
877 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100878 return CMD_WARNING;
879 }
880
881 gprs_subscr_update_auth_info(subscr);
882
883 subscr_put(subscr);
884
885 return CMD_SUCCESS;
886}
887
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100888DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
889 "gsup remote-ip A.B.C.D",
890 "GSUP Parameters\n"
891 "Set the IP address of the remote GSUP server\n"
892 "IPv4 Address\n")
893{
894 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
895
896 return CMD_SUCCESS;
897}
898
899DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
900 "gsup remote-port <0-65535>",
901 "GSUP Parameters\n"
902 "Set the TCP port of the remote GSUP server\n"
903 "Remote TCP port\n")
904{
905 g_cfg->gsup_server_port = atoi(argv[0]);
906
907 return CMD_SUCCESS;
908}
909
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200910DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
911 "gsup oap-id <0-65535>",
912 "GSUP Parameters\n"
913 "Set the SGSN's OAP client ID\nOAP client ID (0 == disabled)\n")
914{
915 /* VTY ensures range */
916 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
917 return CMD_SUCCESS;
918}
919
920DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
921 "gsup oap-k K",
922 "GSUP Parameters\n"
923 "Set the OAP shared secret K\nK value (16 byte) hex\n")
924{
925 const char *k = argv[0];
926
927 g_cfg->oap.secret_k_present = 0;
928
929 if ((!k) || (strlen(k) == 0))
930 goto disable;
931
932 int k_len = osmo_hexparse(k,
933 g_cfg->oap.secret_k,
934 sizeof(g_cfg->oap.secret_k));
935 if (k_len != 16) {
936 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
937 k_len, VTY_NEWLINE);
938 goto disable;
939 }
940
941 g_cfg->oap.secret_k_present = 1;
942 return CMD_SUCCESS;
943
944disable:
945 if (g_cfg->oap.client_id > 0) {
946 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
947 VTY_NEWLINE);
948 return CMD_WARNING;
949 }
950 return CMD_SUCCESS;
951}
952
953DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
954 "gsup oap-opc OPC",
955 "GSUP Parameters\n"
956 "Set the OAP shared secret OPC\nOPC value (16 byte) hex\n")
957{
958 const char *opc = argv[0];
959
960 g_cfg->oap.secret_opc_present = 0;
961
962 if ((!opc) || (strlen(opc) == 0))
963 goto disable;
964
965 int opc_len = osmo_hexparse(opc,
966 g_cfg->oap.secret_opc,
967 sizeof(g_cfg->oap.secret_opc));
968 if (opc_len != 16) {
969 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
970 opc_len, VTY_NEWLINE);
971 goto disable;
972 }
973
974 g_cfg->oap.secret_opc_present = 1;
975 return CMD_SUCCESS;
976
977disable:
978 if (g_cfg->oap.client_id > 0) {
979 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
980 VTY_NEWLINE);
981 return CMD_WARNING;
982 }
983 return CMD_SUCCESS;
984}
985
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +0100986DEFUN(cfg_apn_name, cfg_apn_name_cmd,
987 "access-point-name NAME",
988 "Configure a global list of allowed APNs\n"
989 "Add this NAME to the list\n")
990{
991 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
992}
993
994DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
995 "no access-point-name NAME",
996 NO_STR "Configure a global list of allowed APNs\n"
997 "Remove entry with NAME\n")
998{
999 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1000 if (!apn_ctx)
1001 return CMD_SUCCESS;
1002
1003 sgsn_apn_ctx_free(apn_ctx);
1004 return CMD_SUCCESS;
1005}
1006
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001007DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1008 "cdr filename NAME",
1009 "CDR\nSet filename\nname\n")
1010{
1011 talloc_free(g_cfg->cdr.filename);
1012 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1013 return CMD_SUCCESS;
1014}
1015
1016DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1017 "no cdr filename",
1018 NO_STR "CDR\nDisable CDR generation\n")
1019{
1020 talloc_free(g_cfg->cdr.filename);
1021 g_cfg->cdr.filename = NULL;
1022 return CMD_SUCCESS;
1023}
1024
1025DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1026 "cdr interval <1-2147483647>",
1027 "CDR\nPDP periodic log interval\nSeconds\n")
1028{
1029 g_cfg->cdr.interval = atoi(argv[0]);
1030 return CMD_SUCCESS;
1031}
1032
Harald Welte288be162010-05-01 16:48:27 +02001033int sgsn_vty_init(void)
1034{
Harald Welted193cb32010-05-17 22:58:03 +02001035 install_element_ve(&show_sgsn_cmd);
1036 //install_element_ve(&show_mmctx_tlli_cmd);
1037 install_element_ve(&show_mmctx_imsi_cmd);
1038 install_element_ve(&show_mmctx_all_cmd);
1039 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001040 install_element_ve(&show_subscr_cache_cmd);
1041
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001042 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001043 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001044 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001045 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001046 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1047 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001048
1049 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1050 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeck36722e12013-10-29 09:30:30 +01001051 vty_install_default(SGSN_NODE);
Harald Weltee300d002010-06-02 12:41:34 +02001052 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001053 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1054 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1055 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001056 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001057 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001058 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1059 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001060 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1061 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1062 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001063 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1064 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001065 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1066 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001067 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1068 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
1069 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001070 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001071 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001072
Harald Welte94508822015-08-15 19:08:21 +02001073 install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd);
1074 install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd);
1075 install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd);
1076 install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd);
1077 install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd);
1078 install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd);
1079 install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd);
1080 install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd);
1081 install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd);
1082 install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd);
1083 install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd);
1084 install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd);
1085
Harald Welte288be162010-05-01 16:48:27 +02001086 return 0;
1087}
1088
1089int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
1090{
1091 int rc;
1092
1093 g_cfg = cfg;
Harald Welte7f6da482013-03-19 11:00:13 +01001094
Harald Welte94508822015-08-15 19:08:21 +02001095 g_cfg->timers.T3312 = GSM0408_T3312_SECS;
1096 g_cfg->timers.T3322 = GSM0408_T3322_SECS;
1097 g_cfg->timers.T3350 = GSM0408_T3350_SECS;
1098 g_cfg->timers.T3360 = GSM0408_T3360_SECS;
1099 g_cfg->timers.T3370 = GSM0408_T3370_SECS;
1100 g_cfg->timers.T3313 = GSM0408_T3313_SECS;
1101 g_cfg->timers.T3314 = GSM0408_T3314_SECS;
1102 g_cfg->timers.T3316 = GSM0408_T3316_SECS;
1103 g_cfg->timers.T3385 = GSM0408_T3385_SECS;
1104 g_cfg->timers.T3386 = GSM0408_T3386_SECS;
1105 g_cfg->timers.T3395 = GSM0408_T3395_SECS;
1106 g_cfg->timers.T3397 = GSM0408_T3397_SECS;
1107
Harald Weltedcccb182010-05-16 20:52:23 +02001108 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001109 if (rc < 0) {
1110 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1111 return rc;
1112 }
1113
1114 return 0;
1115}