blob: 84fd5ef522298cdedf90ff16520e511e35689012 [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
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01007 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
Harald Welte288be162010-05-01 16:48:27 +02009 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Harald Welte288be162010-05-01 16:48:27 +020015 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte288be162010-05-01 16:48:27 +020018 *
19 */
20
Harald Welte288be162010-05-01 16:48:27 +020021#include <sys/socket.h>
22#include <netinet/in.h>
23#include <arpa/inet.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +010024#include <time.h>
Harald Welte288be162010-05-01 16:48:27 +020025
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010026#include <osmocom/core/talloc.h>
27#include <osmocom/core/utils.h>
28#include <osmocom/core/rate_ctr.h>
Harald Welte288be162010-05-01 16:48:27 +020029
30#include <openbsc/debug.h>
31#include <openbsc/sgsn.h>
Harald Welteea34a4e2012-06-16 14:59:56 +080032#include <osmocom/gprs/gprs_ns.h>
Harald Welted193cb32010-05-17 22:58:03 +020033#include <openbsc/gprs_sgsn.h>
Harald Welte62ab20c2010-05-14 18:59:17 +020034#include <openbsc/vty.h>
Harald Weltec5d4a0c2010-07-02 22:47:59 +020035#include <openbsc/gsm_04_08_gprs.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010036#include <openbsc/gprs_gsup_client.h>
Harald Welte288be162010-05-01 16:48:27 +020037
Harald Welte4b037e42010-05-19 19:45:32 +020038#include <osmocom/vty/command.h>
39#include <osmocom/vty/vty.h>
Pablo Neira Ayuso6110a3f2011-03-28 19:35:00 +020040#include <osmocom/vty/misc.h>
Harald Welte288be162010-05-01 16:48:27 +020041
Jacob Erlbeck80547992014-12-19 19:19:46 +010042#include <osmocom/abis/ipa.h>
43
Harald Welted193cb32010-05-17 22:58:03 +020044#include <pdp.h>
45
Harald Welte288be162010-05-01 16:48:27 +020046static struct sgsn_config *g_cfg = NULL;
47
Jacob Erlbeck106f5472014-11-04 10:08:37 +010048const struct value_string sgsn_auth_pol_strs[] = {
49 { SGSN_AUTH_POLICY_OPEN, "accept-all" },
50 { SGSN_AUTH_POLICY_CLOSED, "closed" },
51 { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" },
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +010052 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeck106f5472014-11-04 10:08:37 +010053 { 0, NULL }
54};
55
56
Harald Weltec5d4a0c2010-07-02 22:47:59 +020057#define GSM48_MAX_APN_LEN 102 /* 10.5.6.1 */
58static char *gprs_apn2str(uint8_t *apn, unsigned int len)
59{
60 static char apnbuf[GSM48_MAX_APN_LEN+1];
Holger Hans Peter Freyther80e03652013-07-04 18:44:16 +020061 unsigned int i = 0;
Harald Weltec5d4a0c2010-07-02 22:47:59 +020062
63 if (!apn)
64 return "";
65
66 if (len > sizeof(apnbuf)-1)
67 len = sizeof(apnbuf)-1;
68
69 memcpy(apnbuf, apn, len);
70 apnbuf[len] = '\0';
71
72 /* replace the domain name step sizes with dots */
73 while (i < len) {
74 unsigned int step = apnbuf[i];
75 apnbuf[i] = '.';
76 i += step+1;
77 }
78
79 return apnbuf+1;
80}
81
Holger Hans Peter Freythera2730302014-03-23 18:08:26 +010082char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
Harald Weltec5d4a0c2010-07-02 22:47:59 +020083{
84 static char str[INET6_ADDRSTRLEN + 10];
85
86 if (!pdpa || len < 2)
87 return "none";
88
89 switch (pdpa[0] & 0x0f) {
90 case PDP_TYPE_ORG_IETF:
91 switch (pdpa[1]) {
92 case PDP_TYPE_N_IETF_IPv4:
93 if (len < 2 + 4)
94 break;
95 strcpy(str, "IPv4 ");
96 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
97 return str;
98 case PDP_TYPE_N_IETF_IPv6:
99 if (len < 2 + 8)
100 break;
101 strcpy(str, "IPv6 ");
102 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
103 return str;
104 default:
105 break;
106 }
107 break;
108 case PDP_TYPE_ORG_ETSI:
109 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
110 return "PPP";
111 break;
112 default:
113 break;
114 }
115
116 return "invalid";
117}
118
Harald Welte288be162010-05-01 16:48:27 +0200119static struct cmd_node sgsn_node = {
120 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200121 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200122 1,
123};
124
125static int config_write_sgsn(struct vty *vty)
126{
Harald Welte77289c22010-05-18 14:32:29 +0200127 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100128 struct imsi_acl_entry *acl;
Harald Welte288be162010-05-01 16:48:27 +0200129
130 vty_out(vty, "sgsn%s", VTY_NEWLINE);
131
Harald Weltee300d002010-06-02 12:41:34 +0200132 vty_out(vty, " gtp local-ip %s%s",
133 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
134
Harald Welted193cb32010-05-17 22:58:03 +0200135 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Harald Welteff3bde82010-05-19 15:09:09 +0200136 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200137 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200138 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200139 gctx->gtp_version, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200140 }
141
Harald Welte3dfb5492013-03-19 11:48:54 +0100142 vty_out(vty, " auth-policy %s%s",
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100143 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
144 VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100145 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
146 vty_out(vty, " gsup remote-ip %s%s",
147 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
148 if (g_cfg->gsup_server_port)
149 vty_out(vty, " gsup remote-port %d%s",
150 g_cfg->gsup_server_port, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100151 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
152 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
153
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100154 if (g_cfg->subscriber_expiry_timeout != SGSN_TIMEOUT_NEVER)
155 vty_out(vty, " subscriber-expiry-timeout %d%s",
156 g_cfg->subscriber_expiry_timeout, VTY_NEWLINE);
157
Harald Welte288be162010-05-01 16:48:27 +0200158 return CMD_SUCCESS;
159}
160
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100161#define SGSN_STR "Configure the SGSN\n"
162#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200163
164DEFUN(cfg_sgsn, cfg_sgsn_cmd,
165 "sgsn",
166 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200167{
168 vty->node = SGSN_NODE;
169 return CMD_SUCCESS;
170}
171
Harald Weltee300d002010-06-02 12:41:34 +0200172DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
173 "gtp local-ip A.B.C.D",
174 "GTP Parameters\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100175 "Set the IP address for the local GTP bind\n"
176 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200177{
178 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
179
180 return CMD_SUCCESS;
181}
182
Harald Welted193cb32010-05-17 22:58:03 +0200183DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
184 "ggsn <0-255> remote-ip A.B.C.D",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100185 GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200186{
187 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200188 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200189
Harald Welted193cb32010-05-17 22:58:03 +0200190 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200191
Harald Welted193cb32010-05-17 22:58:03 +0200192 return CMD_SUCCESS;
193}
194
195#if 0
196DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
197 "ggsn <0-255> remote-port <0-65535>",
198 "")
199{
200 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200201 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200202 uint16_t port = atoi(argv[1]);
203
204}
205#endif
206
207DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
208 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100209 GGSN_STR "GGSN Number\n" "GTP Version\n"
210 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200211{
212 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200213 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200214
215 if (atoi(argv[1]))
216 ggc->gtp_version = 1;
217 else
218 ggc->gtp_version = 0;
219
220 return CMD_SUCCESS;
221}
222
223#if 0
224DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
225 "apn APNAME ggsn <0-255>",
226 "")
227{
228 struct apn_ctx **
229}
230#endif
231
232const struct value_string gprs_mm_st_strs[] = {
233 { GMM_DEREGISTERED, "DEREGISTERED" },
234 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
235 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200236 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200237 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
238 { 0, NULL }
239};
240
241static void vty_dump_pdp(struct vty *vty, const char *pfx,
242 struct sgsn_pdp_ctx *pdp)
243{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200244 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welted193cb32010-05-17 22:58:03 +0200245 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200246 pfx, imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200247 vty_out(vty, "%s APN: %s%s", pfx,
248 gprs_apn2str(pdp->lib->apn_use.v, pdp->lib->apn_use.l),
249 VTY_NEWLINE);
250 vty_out(vty, "%s PDP Address: %s%s", pfx,
251 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
252 VTY_NEWLINE);
Harald Welteefbdee92010-06-10 00:20:12 +0200253 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200254}
255
256static void vty_dump_mmctx(struct vty *vty, const char *pfx,
257 struct sgsn_mm_ctx *mm, int pdp)
258{
259 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
260 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
261 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s", pfx, mm->msisdn,
262 mm->tlli, VTY_NEWLINE);
263 vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, "
264 "Cell ID: %u%s", pfx,
265 get_value_string(gprs_mm_st_strs, mm->mm_state),
266 mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac,
267 mm->cell_id, VTY_NEWLINE);
268
Harald Welte8acd88f2010-05-18 10:57:45 +0200269 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
270
Harald Welted193cb32010-05-17 22:58:03 +0200271 if (pdp) {
272 struct sgsn_pdp_ctx *pdp;
273
274 llist_for_each_entry(pdp, &mm->pdp_list, list)
275 vty_dump_pdp(vty, " ", pdp);
276 }
277}
278
279DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
280 SHOW_STR "Display information about the SGSN")
281{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100282 if (sgsn->gsup_client) {
283 struct ipa_client_conn *link = sgsn->gsup_client->link;
284 vty_out(vty,
285 " Remote authorization: %sconnected to %s:%d via GSUP%s",
286 sgsn->gsup_client->is_connected ? "" : "not ",
287 link->addr, link->port,
288 VTY_NEWLINE);
289 }
Harald Welted193cb32010-05-17 22:58:03 +0200290 /* FIXME: statistics */
291 return CMD_SUCCESS;
292}
293
294#define MMCTX_STR "MM Context\n"
295#define INCLUDE_PDP_STR "Include PDP Context Information\n"
296
297#if 0
298DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
299 "show mm-context tlli HEX [pdp]",
300 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
301{
302 uint32_t tlli;
303 struct sgsn_mm_ctx *mm;
304
305 tlli = strtoul(argv[0], NULL, 16);
306 mm = sgsn_mm_ctx_by_tlli(tlli);
307 if (!mm) {
308 vty_out(vty, "No MM context for TLLI %08x%s",
309 tlli, VTY_NEWLINE);
310 return CMD_WARNING;
311 }
312 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
313 return CMD_SUCCESS;
314}
315#endif
316
317DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
318 "show mm-context imsi IMSI [pdp]",
319 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
320 INCLUDE_PDP_STR)
321{
322 struct sgsn_mm_ctx *mm;
323
324 mm = sgsn_mm_ctx_by_imsi(argv[0]);
325 if (!mm) {
326 vty_out(vty, "No MM context for IMSI %s%s",
327 argv[0], VTY_NEWLINE);
328 return CMD_WARNING;
329 }
330 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
331 return CMD_SUCCESS;
332}
333
334DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
335 "show mm-context all [pdp]",
336 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
337{
338 struct sgsn_mm_ctx *mm;
339
340 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
341 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
342
343 return CMD_SUCCESS;
344}
345
Harald Welted193cb32010-05-17 22:58:03 +0200346DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
347 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100348 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200349{
350 struct sgsn_pdp_ctx *pdp;
351
352 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
353 vty_dump_pdp(vty, "", pdp);
354
355 return CMD_SUCCESS;
356}
Harald Welte288be162010-05-01 16:48:27 +0200357
Harald Welte7f6da482013-03-19 11:00:13 +0100358
359DEFUN(imsi_acl, cfg_imsi_acl_cmd,
360 "imsi-acl (add|del) IMSI",
361 "Access Control List of foreign IMSIs\n"
362 "Add IMSI to ACL\n"
363 "Remove IMSI from ACL\n"
364 "IMSI of subscriber\n")
365{
366 const char *op = argv[0];
367 const char *imsi = argv[1];
368 int rc;
369
370 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200371 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100372 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200373 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100374
375 if (rc < 0) {
376 vty_out(vty, "%% unable to %s ACL\n", op);
377 return CMD_WARNING;
378 }
379
380 return CMD_SUCCESS;
381}
382
Harald Welte3dfb5492013-03-19 11:48:54 +0100383DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100384 "auth-policy (accept-all|closed|acl-only|remote)",
Harald Welte3dfb5492013-03-19 11:48:54 +0100385 "Autorization Policy of SGSN\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100386 "Accept all IMSIs (DANGEROUS)\n"
387 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100388 "Accept only subscribers in the ACL\n"
389 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100390{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100391 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100392 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100393 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100394 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100395 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100396
397 return CMD_SUCCESS;
398}
399
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100400/* Subscriber */
401#include <openbsc/gsm_subscriber.h>
402
403static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending)
404{
405 char expire_time[200];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100406 struct gsm_auth_tuple *at;
407 int at_idx;
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100408 struct timeval tv;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100409
410 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
411 subscr->authorized, VTY_NEWLINE);
412 if (strlen(subscr->name))
413 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
414 if (strlen(subscr->extension))
415 vty_out(vty, " Extension: %s%s", subscr->extension,
416 VTY_NEWLINE);
417 vty_out(vty, " LAC: %d/0x%x%s",
418 subscr->lac, subscr->lac, VTY_NEWLINE);
419 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
420 if (subscr->tmsi != GSM_RESERVED_TMSI)
421 vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
422 VTY_NEWLINE);
423
424 if (strlen(subscr->equipment.imei) > 0)
425 vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE);
426
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100427 for (at_idx = 0; at_idx < ARRAY_SIZE(subscr->sgsn_data->auth_triplets);
428 at_idx++) {
429 at = &subscr->sgsn_data->auth_triplets[at_idx];
430 if (at->key_seq == GSM_KEY_SEQ_INVAL)
431 continue;
432
433 vty_out(vty, " A3A8 tuple (used %d times): ",
434 at->use_count);
435 vty_out(vty, " seq # : %d, ",
436 at->key_seq);
437 vty_out(vty, " RAND : %s, ",
438 osmo_hexdump(at->rand, sizeof(at->rand)));
439 vty_out(vty, " SRES : %s, ",
440 osmo_hexdump(at->sres, sizeof(at->sres)));
441 vty_out(vty, " Kc : %s%s",
442 osmo_hexdump(at->kc, sizeof(at->kc)),
443 VTY_NEWLINE);
444 }
445
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100446 /* print the expiration time of a subscriber */
447 if (subscr->expire_lu) {
448 strftime(expire_time, sizeof(expire_time),
449 "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
450 expire_time[sizeof(expire_time) - 1] = '\0';
451 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
452 }
453
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100454 /* print the expiration time if the timer is active */
455 if (osmo_timer_pending(&subscr->sgsn_data->timer)) {
456 osmo_timer_remaining(&subscr->sgsn_data->timer, NULL, &tv);
457 strftime(expire_time, sizeof(expire_time),
458 "%a, %d %b %Y %T %z",
459 localtime(&subscr->sgsn_data->timer.timeout.tv_sec));
460 expire_time[sizeof(expire_time) - 1] = '\0';
461 vty_out(vty, " Expires in: %ds (%s)%s",
462 (int)tv.tv_sec, expire_time, VTY_NEWLINE);
463 }
464
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100465 if (subscr->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100466 vty_out(vty, " Flags: %s%s%s%s%s%s",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100467 subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ?
468 "FIRST_CONTACT " : "",
469 subscr->flags & GPRS_SUBSCRIBER_CANCELLED ?
470 "CANCELLED " : "",
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100471 subscr->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
472 "UPDATE_LOCATION_PENDING " : "",
473 subscr->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
474 "AUTH_INFO_PENDING " : "",
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100475 subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
476 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100477 VTY_NEWLINE);
478
479 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
480}
481
482DEFUN(show_subscr_cache,
483 show_subscr_cache_cmd,
484 "show subscriber cache",
485 SHOW_STR "Show information about subscribers\n"
486 "Display contents of subscriber cache\n")
487{
488 struct gsm_subscriber *subscr;
489
490 llist_for_each_entry(subscr, &active_subscribers, entry) {
491 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
492 subscr_dump_full_vty(vty, subscr, 0);
493 }
494
495 return CMD_SUCCESS;
496}
497
498#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
499#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
500 "Use the IMSI to select the subscriber\n" \
501 "The IMSI\n"
502
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100503#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
504
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100505DEFUN(update_subscr_insert, update_subscr_insert_cmd,
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100506 UPDATE_SUBSCR_STR "insert authorized <0-1>)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100507 UPDATE_SUBSCR_HELP
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100508 UPDATE_SUBSCR_INSERT_HELP
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100509 "Authorize the subscriber to attach\n"
510 "New option value\n")
511{
512 const char *imsi = argv[0];
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100513 const char *value = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100514
515 struct gsm_subscriber *subscr;
516
517 subscr = gprs_subscr_get_or_create(imsi);
518 if (!subscr) {
519 vty_out(vty, "%% unable get subscriber record for %s\n", imsi);
520 return CMD_WARNING;
521 }
522
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100523 subscr->authorized = atoi(value);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100524
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100525 subscr_put(subscr);
526
527 return CMD_SUCCESS;
528}
529
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100530DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
531 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
532 UPDATE_SUBSCR_HELP
533 UPDATE_SUBSCR_INSERT_HELP
534 "Update authentication triplet\n"
535 "Triplet index\n"
536 "Set SRES value\nSRES value (4 byte) in hex\n"
537 "Set RAND value\nRAND value (16 byte) in hex\n"
538 "Set Kc value\nKc value (8 byte) in hex\n")
539{
540 const char *imsi = argv[0];
541 const int cksn = atoi(argv[1]) - 1;
542 const char *sres_str = argv[2];
543 const char *rand_str = argv[3];
544 const char *kc_str = argv[4];
545 struct gsm_auth_tuple at = {0,};
546
547 struct gsm_subscriber *subscr;
548
549 subscr = gprs_subscr_get_or_create(imsi);
550 if (!subscr) {
551 vty_out(vty, "%% unable get subscriber record for %s\n", imsi);
552 return CMD_WARNING;
553 }
554
555 OSMO_ASSERT(subscr->sgsn_data);
556
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100557 if (osmo_hexparse(sres_str, &at.sres[0], sizeof(at.sres)) < 0) {
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100558 vty_out(vty, "%% invalid SRES value '%s'\n", sres_str);
559 goto failed;
560 }
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100561 if (osmo_hexparse(rand_str, &at.rand[0], sizeof(at.rand)) < 0) {
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100562 vty_out(vty, "%% invalid RAND value '%s'\n", rand_str);
563 goto failed;
564 }
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100565 if (osmo_hexparse(kc_str, &at.kc[0], sizeof(at.kc)) < 0) {
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100566 vty_out(vty, "%% invalid Kc value '%s'\n", kc_str);
567 goto failed;
568 }
569 at.key_seq = cksn;
570
571 subscr->sgsn_data->auth_triplets[cksn] = at;
572 subscr->sgsn_data->auth_triplets_updated = 1;
573
574 subscr_put(subscr);
575
576 return CMD_SUCCESS;
577
578failed:
579 subscr_put(subscr);
580 return CMD_SUCCESS;
581}
582
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100583DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
584 UPDATE_SUBSCR_STR "cancel",
585 UPDATE_SUBSCR_HELP
586 "Cancel (remove) subscriber record\n")
587{
588 const char *imsi = argv[0];
589
590 struct gsm_subscriber *subscr;
591
592 subscr = gprs_subscr_get_by_imsi(imsi);
593 if (!subscr) {
594 vty_out(vty, "%% no subscriber record for %s\n", imsi);
595 return CMD_WARNING;
596 }
597
598 gprs_subscr_put_and_cancel(subscr);
599
600 return CMD_SUCCESS;
601}
602
603DEFUN(update_subscr_commit, update_subscr_commit_cmd,
604 UPDATE_SUBSCR_STR "commit",
605 UPDATE_SUBSCR_HELP
606 "Apply the changes made by the insert commands\n")
607{
608 const char *imsi = argv[0];
609
610 struct gsm_subscriber *subscr;
611
612 subscr = gprs_subscr_get_by_imsi(imsi);
613 if (!subscr) {
614 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
615 return CMD_WARNING;
616 }
617
618 gprs_subscr_update(subscr);
619
620 subscr_put(subscr);
621
622 return CMD_SUCCESS;
623}
624
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100625#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
626 "unknown-subscriber|roaming-not-allowed"
627
628#define UL_ERR_HELP \
629 "Force error code SystemFailure\n" \
630 "Force error code DataMissing\n" \
631 "Force error code UnexpectedDataValue\n" \
632 "Force error code UnknownSubscriber\n" \
633 "Force error code RoamingNotAllowed\n"
634
635DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
636 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
637 UPDATE_SUBSCR_HELP
638 "Complete the update location procedure\n"
639 "The update location request succeeded\n"
640 UL_ERR_HELP)
641{
642 const char *imsi = argv[0];
643 const char *ret_code_str = argv[1];
644
645 struct gsm_subscriber *subscr;
646
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100647 const struct value_string cause_mapping[] = {
648 { GMM_CAUSE_NET_FAIL, "system-failure" },
649 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
650 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
651 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
652 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
653 { 0, NULL }
654 };
655
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100656 subscr = gprs_subscr_get_by_imsi(imsi);
657 if (!subscr) {
658 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
659 return CMD_WARNING;
660 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100661
662 if (strcmp(ret_code_str, "ok") == 0) {
663 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100664 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100665 } else {
666 subscr->sgsn_data->error_cause =
667 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100668 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100669 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100670
671 gprs_subscr_update(subscr);
672
673 subscr_put(subscr);
674
675 return CMD_SUCCESS;
676}
677
678DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
679 UPDATE_SUBSCR_STR "update-auth-info",
680 UPDATE_SUBSCR_HELP
681 "Complete the send authentication info procedure\n")
682{
683 const char *imsi = argv[0];
684
685 struct gsm_subscriber *subscr;
686
687 subscr = gprs_subscr_get_by_imsi(imsi);
688 if (!subscr) {
689 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
690 return CMD_WARNING;
691 }
692
693 gprs_subscr_update_auth_info(subscr);
694
695 subscr_put(subscr);
696
697 return CMD_SUCCESS;
698}
699
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100700DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
701 "gsup remote-ip A.B.C.D",
702 "GSUP Parameters\n"
703 "Set the IP address of the remote GSUP server\n"
704 "IPv4 Address\n")
705{
706 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
707
708 return CMD_SUCCESS;
709}
710
711DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
712 "gsup remote-port <0-65535>",
713 "GSUP Parameters\n"
714 "Set the TCP port of the remote GSUP server\n"
715 "Remote TCP port\n")
716{
717 g_cfg->gsup_server_port = atoi(argv[0]);
718
719 return CMD_SUCCESS;
720}
721
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100722DEFUN(cfg_subscriber_expiry_timeout, cfg_subscriber_expiry_timeout_cmd,
723 "subscriber-expiry-timeout <0-999999>",
724 "Set the expiry time for unused subscriber entries\n"
725 "Expiry time in seconds\n")
726{
727 g_cfg->subscriber_expiry_timeout = atoi(argv[0]);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100728
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100729 return CMD_SUCCESS;
730}
731
732DEFUN(cfg_no_subscriber_expiry_timeout, cfg_no_subscriber_expiry_timeout_cmd,
733 "no subscriber-expiry-timeout",
734 NO_STR "Set the expiry time for unused subscriber entries\n")
735{
736 g_cfg->subscriber_expiry_timeout = atoi(argv[0]);
737
738 return CMD_SUCCESS;
739}
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100740
Harald Welte288be162010-05-01 16:48:27 +0200741int sgsn_vty_init(void)
742{
Harald Welted193cb32010-05-17 22:58:03 +0200743 install_element_ve(&show_sgsn_cmd);
744 //install_element_ve(&show_mmctx_tlli_cmd);
745 install_element_ve(&show_mmctx_imsi_cmd);
746 install_element_ve(&show_mmctx_all_cmd);
747 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100748 install_element_ve(&show_subscr_cache_cmd);
749
750 install_element(ENABLE_NODE, &update_subscr_insert_cmd);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100751 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100752 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
753 install_element(ENABLE_NODE, &update_subscr_commit_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100754 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
755 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Harald Welte288be162010-05-01 16:48:27 +0200756
757 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
758 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeck36722e12013-10-29 09:30:30 +0100759 vty_install_default(SGSN_NODE);
Harald Weltee300d002010-06-02 12:41:34 +0200760 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +0200761 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
762 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
763 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +0100764 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +0100765 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100766 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
767 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100768 install_element(SGSN_NODE, &cfg_subscriber_expiry_timeout_cmd);
769 install_element(SGSN_NODE, &cfg_no_subscriber_expiry_timeout_cmd);
Harald Welte288be162010-05-01 16:48:27 +0200770
771 return 0;
772}
773
774int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
775{
776 int rc;
777
778 g_cfg = cfg;
Harald Welte7f6da482013-03-19 11:00:13 +0100779
Harald Weltedcccb182010-05-16 20:52:23 +0200780 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +0200781 if (rc < 0) {
782 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
783 return rc;
784 }
785
786 return 0;
787}