blob: 99c59853bdfbe948fae6ea1536e9e6d87d0709a0 [file] [log] [blame]
Harald Welte55fe0552010-05-01 16:48:27 +02001/*
Harald Weltea0879c12013-03-19 11:00:13 +01002 * (C) 2010-2013 by Harald Welte <laforge@gnumonks.org>
Harald Welte55fe0552010-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 Welte0e3e88e2011-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 Welte55fe0552010-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 Welte0e3e88e2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Harald Welte55fe0552010-05-01 16:48:27 +020015 *
Harald Welte0e3e88e2011-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 Welte55fe0552010-05-01 16:48:27 +020018 *
19 */
20
Harald Welte55fe0552010-05-01 16:48:27 +020021#include <sys/socket.h>
22#include <netinet/in.h>
23#include <arpa/inet.h>
Jacob Erlbeckc16c3502014-11-11 14:01:48 +010024#include <time.h>
Harald Welte55fe0552010-05-01 16:48:27 +020025
Pablo Neira Ayusodd5fff42011-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 Welte55fe0552010-05-01 16:48:27 +020029
30#include <openbsc/debug.h>
31#include <openbsc/sgsn.h>
Harald Weltecfb6b282012-06-16 14:59:56 +080032#include <osmocom/gprs/gprs_ns.h>
Harald Weltec1f6bfe2010-05-17 22:58:03 +020033#include <openbsc/gprs_sgsn.h>
Harald Welte58ed1cb2010-05-14 18:59:17 +020034#include <openbsc/vty.h>
Harald Welte493ba622010-07-02 22:47:59 +020035#include <openbsc/gsm_04_08_gprs.h>
Harald Welte55fe0552010-05-01 16:48:27 +020036
Harald Weltebd9591f2010-05-19 19:45:32 +020037#include <osmocom/vty/command.h>
38#include <osmocom/vty/vty.h>
Pablo Neira Ayuso3d31c3a2011-03-28 19:35:00 +020039#include <osmocom/vty/misc.h>
Harald Welte55fe0552010-05-01 16:48:27 +020040
Harald Weltec1f6bfe2010-05-17 22:58:03 +020041#include <pdp.h>
42
Harald Welte55fe0552010-05-01 16:48:27 +020043static struct sgsn_config *g_cfg = NULL;
44
Jacob Erlbeckd7b77732014-11-04 10:08:37 +010045const struct value_string sgsn_auth_pol_strs[] = {
46 { SGSN_AUTH_POLICY_OPEN, "accept-all" },
47 { SGSN_AUTH_POLICY_CLOSED, "closed" },
48 { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" },
Jacob Erlbeckd04f7cc2014-11-12 10:18:09 +010049 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeckd7b77732014-11-04 10:08:37 +010050 { 0, NULL }
51};
52
53
Harald Welte493ba622010-07-02 22:47:59 +020054#define GSM48_MAX_APN_LEN 102 /* 10.5.6.1 */
55static char *gprs_apn2str(uint8_t *apn, unsigned int len)
56{
57 static char apnbuf[GSM48_MAX_APN_LEN+1];
Holger Hans Peter Freyther41514d92013-07-04 18:44:16 +020058 unsigned int i = 0;
Harald Welte493ba622010-07-02 22:47:59 +020059
60 if (!apn)
61 return "";
62
63 if (len > sizeof(apnbuf)-1)
64 len = sizeof(apnbuf)-1;
65
66 memcpy(apnbuf, apn, len);
67 apnbuf[len] = '\0';
68
69 /* replace the domain name step sizes with dots */
70 while (i < len) {
71 unsigned int step = apnbuf[i];
72 apnbuf[i] = '.';
73 i += step+1;
74 }
75
76 return apnbuf+1;
77}
78
Holger Hans Peter Freythere8e5ef22014-03-23 18:08:26 +010079char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
Harald Welte493ba622010-07-02 22:47:59 +020080{
81 static char str[INET6_ADDRSTRLEN + 10];
82
83 if (!pdpa || len < 2)
84 return "none";
85
86 switch (pdpa[0] & 0x0f) {
87 case PDP_TYPE_ORG_IETF:
88 switch (pdpa[1]) {
89 case PDP_TYPE_N_IETF_IPv4:
90 if (len < 2 + 4)
91 break;
92 strcpy(str, "IPv4 ");
93 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
94 return str;
95 case PDP_TYPE_N_IETF_IPv6:
96 if (len < 2 + 8)
97 break;
98 strcpy(str, "IPv6 ");
99 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
100 return str;
101 default:
102 break;
103 }
104 break;
105 case PDP_TYPE_ORG_ETSI:
106 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
107 return "PPP";
108 break;
109 default:
110 break;
111 }
112
113 return "invalid";
114}
115
Harald Welte55fe0552010-05-01 16:48:27 +0200116static struct cmd_node sgsn_node = {
117 SGSN_NODE,
Harald Welte45362bb2012-08-17 13:16:10 +0200118 "%s(config-sgsn)# ",
Harald Welte55fe0552010-05-01 16:48:27 +0200119 1,
120};
121
122static int config_write_sgsn(struct vty *vty)
123{
Harald Welteeb471c92010-05-18 14:32:29 +0200124 struct sgsn_ggsn_ctx *gctx;
Harald Weltea0879c12013-03-19 11:00:13 +0100125 struct imsi_acl_entry *acl;
Harald Welte55fe0552010-05-01 16:48:27 +0200126
127 vty_out(vty, "sgsn%s", VTY_NEWLINE);
128
Harald Weltee0aea392010-06-02 12:41:34 +0200129 vty_out(vty, " gtp local-ip %s%s",
130 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
131
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200132 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Harald Welte31f0a232010-05-19 15:09:09 +0200133 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200134 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welte31f0a232010-05-19 15:09:09 +0200135 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200136 gctx->gtp_version, VTY_NEWLINE);
Harald Welte55fe0552010-05-01 16:48:27 +0200137 }
138
Harald Welte2b9693d2013-03-19 11:48:54 +0100139 vty_out(vty, " auth-policy %s%s",
Jacob Erlbeckd7b77732014-11-04 10:08:37 +0100140 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
141 VTY_NEWLINE);
Harald Weltea0879c12013-03-19 11:00:13 +0100142 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
143 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
144
Harald Welte55fe0552010-05-01 16:48:27 +0200145 return CMD_SUCCESS;
146}
147
Holger Hans Peter Freytherf403c482011-11-05 15:21:16 +0100148#define SGSN_STR "Configure the SGSN\n"
149#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee0aea392010-06-02 12:41:34 +0200150
151DEFUN(cfg_sgsn, cfg_sgsn_cmd,
152 "sgsn",
153 SGSN_STR)
Harald Welte55fe0552010-05-01 16:48:27 +0200154{
155 vty->node = SGSN_NODE;
156 return CMD_SUCCESS;
157}
158
Harald Weltee0aea392010-06-02 12:41:34 +0200159DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
160 "gtp local-ip A.B.C.D",
161 "GTP Parameters\n"
Holger Hans Peter Freytherf403c482011-11-05 15:21:16 +0100162 "Set the IP address for the local GTP bind\n"
163 "IPv4 Address\n")
Harald Weltee0aea392010-06-02 12:41:34 +0200164{
165 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
166
167 return CMD_SUCCESS;
168}
169
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200170DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
171 "ggsn <0-255> remote-ip A.B.C.D",
Holger Hans Peter Freytherf403c482011-11-05 15:21:16 +0100172 GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n")
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200173{
174 uint32_t id = atoi(argv[0]);
Harald Welteeb471c92010-05-18 14:32:29 +0200175 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte55fe0552010-05-01 16:48:27 +0200176
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200177 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte55fe0552010-05-01 16:48:27 +0200178
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200179 return CMD_SUCCESS;
180}
181
182#if 0
183DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
184 "ggsn <0-255> remote-port <0-65535>",
185 "")
186{
187 uint32_t id = atoi(argv[0]);
Harald Welteeb471c92010-05-18 14:32:29 +0200188 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200189 uint16_t port = atoi(argv[1]);
190
191}
192#endif
193
194DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
195 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freytherf403c482011-11-05 15:21:16 +0100196 GGSN_STR "GGSN Number\n" "GTP Version\n"
197 "Version 0\n" "Version 1\n")
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200198{
199 uint32_t id = atoi(argv[0]);
Harald Welteeb471c92010-05-18 14:32:29 +0200200 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200201
202 if (atoi(argv[1]))
203 ggc->gtp_version = 1;
204 else
205 ggc->gtp_version = 0;
206
207 return CMD_SUCCESS;
208}
209
210#if 0
211DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
212 "apn APNAME ggsn <0-255>",
213 "")
214{
215 struct apn_ctx **
216}
217#endif
218
219const struct value_string gprs_mm_st_strs[] = {
220 { GMM_DEREGISTERED, "DEREGISTERED" },
221 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
222 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Welte3ba2ce12010-06-09 15:50:45 +0200223 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200224 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
225 { 0, NULL }
226};
227
228static void vty_dump_pdp(struct vty *vty, const char *pfx,
229 struct sgsn_pdp_ctx *pdp)
230{
Jacob Erlbeckd781c7a2014-10-13 10:32:00 +0200231 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200232 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
Jacob Erlbeckd781c7a2014-10-13 10:32:00 +0200233 pfx, imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
Harald Welte493ba622010-07-02 22:47:59 +0200234 vty_out(vty, "%s APN: %s%s", pfx,
235 gprs_apn2str(pdp->lib->apn_use.v, pdp->lib->apn_use.l),
236 VTY_NEWLINE);
237 vty_out(vty, "%s PDP Address: %s%s", pfx,
238 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
239 VTY_NEWLINE);
Harald Welte0fe506b2010-06-10 00:20:12 +0200240 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200241}
242
243static void vty_dump_mmctx(struct vty *vty, const char *pfx,
244 struct sgsn_mm_ctx *mm, int pdp)
245{
246 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
247 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
248 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s", pfx, mm->msisdn,
249 mm->tlli, VTY_NEWLINE);
250 vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, "
251 "Cell ID: %u%s", pfx,
252 get_value_string(gprs_mm_st_strs, mm->mm_state),
253 mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac,
254 mm->cell_id, VTY_NEWLINE);
255
Harald Welte8a035af2010-05-18 10:57:45 +0200256 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
257
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200258 if (pdp) {
259 struct sgsn_pdp_ctx *pdp;
260
261 llist_for_each_entry(pdp, &mm->pdp_list, list)
262 vty_dump_pdp(vty, " ", pdp);
263 }
264}
265
266DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
267 SHOW_STR "Display information about the SGSN")
268{
269 /* FIXME: statistics */
270 return CMD_SUCCESS;
271}
272
273#define MMCTX_STR "MM Context\n"
274#define INCLUDE_PDP_STR "Include PDP Context Information\n"
275
276#if 0
277DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
278 "show mm-context tlli HEX [pdp]",
279 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
280{
281 uint32_t tlli;
282 struct sgsn_mm_ctx *mm;
283
284 tlli = strtoul(argv[0], NULL, 16);
285 mm = sgsn_mm_ctx_by_tlli(tlli);
286 if (!mm) {
287 vty_out(vty, "No MM context for TLLI %08x%s",
288 tlli, VTY_NEWLINE);
289 return CMD_WARNING;
290 }
291 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
292 return CMD_SUCCESS;
293}
294#endif
295
296DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
297 "show mm-context imsi IMSI [pdp]",
298 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
299 INCLUDE_PDP_STR)
300{
301 struct sgsn_mm_ctx *mm;
302
303 mm = sgsn_mm_ctx_by_imsi(argv[0]);
304 if (!mm) {
305 vty_out(vty, "No MM context for IMSI %s%s",
306 argv[0], VTY_NEWLINE);
307 return CMD_WARNING;
308 }
309 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
310 return CMD_SUCCESS;
311}
312
313DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
314 "show mm-context all [pdp]",
315 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
316{
317 struct sgsn_mm_ctx *mm;
318
319 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
320 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
321
322 return CMD_SUCCESS;
323}
324
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200325DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
326 "show pdp-context all",
Holger Hans Peter Freytherf403c482011-11-05 15:21:16 +0100327 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200328{
329 struct sgsn_pdp_ctx *pdp;
330
331 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
332 vty_dump_pdp(vty, "", pdp);
333
334 return CMD_SUCCESS;
335}
Harald Welte55fe0552010-05-01 16:48:27 +0200336
Harald Weltea0879c12013-03-19 11:00:13 +0100337
338DEFUN(imsi_acl, cfg_imsi_acl_cmd,
339 "imsi-acl (add|del) IMSI",
340 "Access Control List of foreign IMSIs\n"
341 "Add IMSI to ACL\n"
342 "Remove IMSI from ACL\n"
343 "IMSI of subscriber\n")
344{
345 const char *op = argv[0];
346 const char *imsi = argv[1];
347 int rc;
348
349 if (!strcmp(op, "add"))
Jacob Erlbeck4760eae2014-10-24 15:11:03 +0200350 rc = sgsn_acl_add(imsi, g_cfg);
Harald Weltea0879c12013-03-19 11:00:13 +0100351 else
Jacob Erlbeck4760eae2014-10-24 15:11:03 +0200352 rc = sgsn_acl_del(imsi, g_cfg);
Harald Weltea0879c12013-03-19 11:00:13 +0100353
354 if (rc < 0) {
355 vty_out(vty, "%% unable to %s ACL\n", op);
356 return CMD_WARNING;
357 }
358
359 return CMD_SUCCESS;
360}
361
Harald Welte2b9693d2013-03-19 11:48:54 +0100362DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckd04f7cc2014-11-12 10:18:09 +0100363 "auth-policy (accept-all|closed|acl-only|remote)",
Harald Welte2b9693d2013-03-19 11:48:54 +0100364 "Autorization Policy of SGSN\n"
Jacob Erlbeckd7b77732014-11-04 10:08:37 +0100365 "Accept all IMSIs (DANGEROUS)\n"
366 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckd04f7cc2014-11-12 10:18:09 +0100367 "Accept only subscribers in the ACL\n"
368 "Use remote subscription data only (HLR)\n")
Harald Welte2b9693d2013-03-19 11:48:54 +0100369{
Jacob Erlbeckd7b77732014-11-04 10:08:37 +0100370 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckd04f7cc2014-11-12 10:18:09 +0100371 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeckd7b77732014-11-04 10:08:37 +0100372 g_cfg->auth_policy = val;
Harald Welte2b9693d2013-03-19 11:48:54 +0100373
374 return CMD_SUCCESS;
375}
376
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100377/* Subscriber */
378#include <openbsc/gsm_subscriber.h>
379
380static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending)
381{
382 char expire_time[200];
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100383 struct gsm_auth_tuple *at;
384 int at_idx;
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100385
386 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
387 subscr->authorized, VTY_NEWLINE);
388 if (strlen(subscr->name))
389 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
390 if (strlen(subscr->extension))
391 vty_out(vty, " Extension: %s%s", subscr->extension,
392 VTY_NEWLINE);
393 vty_out(vty, " LAC: %d/0x%x%s",
394 subscr->lac, subscr->lac, VTY_NEWLINE);
395 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
396 if (subscr->tmsi != GSM_RESERVED_TMSI)
397 vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
398 VTY_NEWLINE);
399
400 if (strlen(subscr->equipment.imei) > 0)
401 vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE);
402
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100403 for (at_idx = 0; at_idx < ARRAY_SIZE(subscr->sgsn_data->auth_triplets);
404 at_idx++) {
405 at = &subscr->sgsn_data->auth_triplets[at_idx];
406 if (at->key_seq == GSM_KEY_SEQ_INVAL)
407 continue;
408
409 vty_out(vty, " A3A8 tuple (used %d times): ",
410 at->use_count);
411 vty_out(vty, " seq # : %d, ",
412 at->key_seq);
413 vty_out(vty, " RAND : %s, ",
414 osmo_hexdump(at->rand, sizeof(at->rand)));
415 vty_out(vty, " SRES : %s, ",
416 osmo_hexdump(at->sres, sizeof(at->sres)));
417 vty_out(vty, " Kc : %s%s",
418 osmo_hexdump(at->kc, sizeof(at->kc)),
419 VTY_NEWLINE);
420 }
421
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100422 /* print the expiration time of a subscriber */
423 if (subscr->expire_lu) {
424 strftime(expire_time, sizeof(expire_time),
425 "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
426 expire_time[sizeof(expire_time) - 1] = '\0';
427 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
428 }
429
430 if (subscr->flags)
431 vty_out(vty, " Flags: %s%s%s%s",
432 subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ?
433 "FIRST_CONTACT " : "",
434 subscr->flags & GPRS_SUBSCRIBER_CANCELLED ?
435 "CANCELLED " : "",
436 subscr->flags & GPRS_SUBSCRIBER_UPDATE_PENDING ?
437 "UPDATE_PENDING " : "",
438 VTY_NEWLINE);
439
440 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
441}
442
443DEFUN(show_subscr_cache,
444 show_subscr_cache_cmd,
445 "show subscriber cache",
446 SHOW_STR "Show information about subscribers\n"
447 "Display contents of subscriber cache\n")
448{
449 struct gsm_subscriber *subscr;
450
451 llist_for_each_entry(subscr, &active_subscribers, entry) {
452 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
453 subscr_dump_full_vty(vty, subscr, 0);
454 }
455
456 return CMD_SUCCESS;
457}
458
459#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
460#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
461 "Use the IMSI to select the subscriber\n" \
462 "The IMSI\n"
463
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100464#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
465
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100466DEFUN(update_subscr_insert, update_subscr_insert_cmd,
Jacob Erlbeckd8126992014-12-08 15:26:47 +0100467 UPDATE_SUBSCR_STR "insert (authorized|authenticate) (0|1)",
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100468 UPDATE_SUBSCR_HELP
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100469 UPDATE_SUBSCR_INSERT_HELP
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100470 "Authorize the subscriber to attach\n"
471 "New option value\n")
472{
473 const char *imsi = argv[0];
Jacob Erlbeckd8126992014-12-08 15:26:47 +0100474 const char *option = argv[1];
475 const char *value = argv[2];
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100476
477 struct gsm_subscriber *subscr;
478
479 subscr = gprs_subscr_get_or_create(imsi);
480 if (!subscr) {
481 vty_out(vty, "%% unable get subscriber record for %s\n", imsi);
482 return CMD_WARNING;
483 }
484
485 if (!strcmp(option, "authorized"))
486 subscr->authorized = atoi(value);
Jacob Erlbeckd8126992014-12-08 15:26:47 +0100487 else
488 subscr->sgsn_data->authenticate = atoi(value);
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100489
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100490 subscr_put(subscr);
491
492 return CMD_SUCCESS;
493}
494
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100495DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
496 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
497 UPDATE_SUBSCR_HELP
498 UPDATE_SUBSCR_INSERT_HELP
499 "Update authentication triplet\n"
500 "Triplet index\n"
501 "Set SRES value\nSRES value (4 byte) in hex\n"
502 "Set RAND value\nRAND value (16 byte) in hex\n"
503 "Set Kc value\nKc value (8 byte) in hex\n")
504{
505 const char *imsi = argv[0];
506 const int cksn = atoi(argv[1]) - 1;
507 const char *sres_str = argv[2];
508 const char *rand_str = argv[3];
509 const char *kc_str = argv[4];
510 struct gsm_auth_tuple at = {0,};
511
512 struct gsm_subscriber *subscr;
513
514 subscr = gprs_subscr_get_or_create(imsi);
515 if (!subscr) {
516 vty_out(vty, "%% unable get subscriber record for %s\n", imsi);
517 return CMD_WARNING;
518 }
519
520 OSMO_ASSERT(subscr->sgsn_data);
521
522 if (!osmo_hexparse(sres_str, &at.sres[0], sizeof(at.sres)) < 0) {
523 vty_out(vty, "%% invalid SRES value '%s'\n", sres_str);
524 goto failed;
525 }
526 if (!osmo_hexparse(rand_str, &at.rand[0], sizeof(at.rand)) < 0) {
527 vty_out(vty, "%% invalid RAND value '%s'\n", rand_str);
528 goto failed;
529 }
530 if (!osmo_hexparse(kc_str, &at.kc[0], sizeof(at.kc)) < 0) {
531 vty_out(vty, "%% invalid Kc value '%s'\n", kc_str);
532 goto failed;
533 }
534 at.key_seq = cksn;
535
536 subscr->sgsn_data->auth_triplets[cksn] = at;
537 subscr->sgsn_data->auth_triplets_updated = 1;
538
539 subscr_put(subscr);
540
541 return CMD_SUCCESS;
542
543failed:
544 subscr_put(subscr);
545 return CMD_SUCCESS;
546}
547
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100548DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
549 UPDATE_SUBSCR_STR "cancel",
550 UPDATE_SUBSCR_HELP
551 "Cancel (remove) subscriber record\n")
552{
553 const char *imsi = argv[0];
554
555 struct gsm_subscriber *subscr;
556
557 subscr = gprs_subscr_get_by_imsi(imsi);
558 if (!subscr) {
559 vty_out(vty, "%% no subscriber record for %s\n", imsi);
560 return CMD_WARNING;
561 }
562
563 gprs_subscr_put_and_cancel(subscr);
564
565 return CMD_SUCCESS;
566}
567
568DEFUN(update_subscr_commit, update_subscr_commit_cmd,
569 UPDATE_SUBSCR_STR "commit",
570 UPDATE_SUBSCR_HELP
571 "Apply the changes made by the insert commands\n")
572{
573 const char *imsi = argv[0];
574
575 struct gsm_subscriber *subscr;
576
577 subscr = gprs_subscr_get_by_imsi(imsi);
578 if (!subscr) {
579 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
580 return CMD_WARNING;
581 }
582
583 gprs_subscr_update(subscr);
584
585 subscr_put(subscr);
586
587 return CMD_SUCCESS;
588}
589
Harald Welte55fe0552010-05-01 16:48:27 +0200590int sgsn_vty_init(void)
591{
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200592 install_element_ve(&show_sgsn_cmd);
593 //install_element_ve(&show_mmctx_tlli_cmd);
594 install_element_ve(&show_mmctx_imsi_cmd);
595 install_element_ve(&show_mmctx_all_cmd);
596 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100597 install_element_ve(&show_subscr_cache_cmd);
598
599 install_element(ENABLE_NODE, &update_subscr_insert_cmd);
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100600 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100601 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
602 install_element(ENABLE_NODE, &update_subscr_commit_cmd);
Harald Welte55fe0552010-05-01 16:48:27 +0200603
604 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
605 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeckf414e852013-10-29 09:30:30 +0100606 vty_install_default(SGSN_NODE);
Harald Weltee0aea392010-06-02 12:41:34 +0200607 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200608 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
609 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
610 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Harald Weltea0879c12013-03-19 11:00:13 +0100611 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte2b9693d2013-03-19 11:48:54 +0100612 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Harald Welte55fe0552010-05-01 16:48:27 +0200613
614 return 0;
615}
616
617int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
618{
619 int rc;
620
621 g_cfg = cfg;
Harald Weltea0879c12013-03-19 11:00:13 +0100622
Harald Welte40152872010-05-16 20:52:23 +0200623 rc = vty_read_config_file(config_file, NULL);
Harald Welte55fe0552010-05-01 16:48:27 +0200624 if (rc < 0) {
625 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
626 return rc;
627 }
628
629 return 0;
630}