blob: 99c59853bdfbe948fae6ea1536e9e6d87d0709a0 [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>
Harald Welte288be162010-05-01 16:48:27 +020036
Harald Welte4b037e42010-05-19 19:45:32 +020037#include <osmocom/vty/command.h>
38#include <osmocom/vty/vty.h>
Pablo Neira Ayuso6110a3f2011-03-28 19:35:00 +020039#include <osmocom/vty/misc.h>
Harald Welte288be162010-05-01 16:48:27 +020040
Harald Welted193cb32010-05-17 22:58:03 +020041#include <pdp.h>
42
Harald Welte288be162010-05-01 16:48:27 +020043static struct sgsn_config *g_cfg = NULL;
44
Jacob Erlbeck106f5472014-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 Erlbeckbe2c8d92014-11-12 10:18:09 +010049 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeck106f5472014-11-04 10:08:37 +010050 { 0, NULL }
51};
52
53
Harald Weltec5d4a0c2010-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 Freyther80e03652013-07-04 18:44:16 +020058 unsigned int i = 0;
Harald Weltec5d4a0c2010-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 Freythera2730302014-03-23 18:08:26 +010079char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
Harald Weltec5d4a0c2010-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 Welte288be162010-05-01 16:48:27 +0200116static struct cmd_node sgsn_node = {
117 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200118 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200119 1,
120};
121
122static int config_write_sgsn(struct vty *vty)
123{
Harald Welte77289c22010-05-18 14:32:29 +0200124 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100125 struct imsi_acl_entry *acl;
Harald Welte288be162010-05-01 16:48:27 +0200126
127 vty_out(vty, "sgsn%s", VTY_NEWLINE);
128
Harald Weltee300d002010-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 Welted193cb32010-05-17 22:58:03 +0200132 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Harald Welteff3bde82010-05-19 15:09:09 +0200133 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200134 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200135 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200136 gctx->gtp_version, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200137 }
138
Harald Welte3dfb5492013-03-19 11:48:54 +0100139 vty_out(vty, " auth-policy %s%s",
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100140 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
141 VTY_NEWLINE);
Harald Welte7f6da482013-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 Welte288be162010-05-01 16:48:27 +0200145 return CMD_SUCCESS;
146}
147
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100148#define SGSN_STR "Configure the SGSN\n"
149#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200150
151DEFUN(cfg_sgsn, cfg_sgsn_cmd,
152 "sgsn",
153 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200154{
155 vty->node = SGSN_NODE;
156 return CMD_SUCCESS;
157}
158
Harald Weltee300d002010-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 Freyther1491f2e2011-11-05 15:21:16 +0100162 "Set the IP address for the local GTP bind\n"
163 "IPv4 Address\n")
Harald Weltee300d002010-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 Welted193cb32010-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 Freyther1491f2e2011-11-05 15:21:16 +0100172 GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200173{
174 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200175 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200176
Harald Welted193cb32010-05-17 22:58:03 +0200177 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200178
Harald Welted193cb32010-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 Welte77289c22010-05-18 14:32:29 +0200188 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-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 Freyther1491f2e2011-11-05 15:21:16 +0100196 GGSN_STR "GGSN Number\n" "GTP Version\n"
197 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200198{
199 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200200 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-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 Weltebffeff82010-06-09 15:50:45 +0200223 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-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 Erlbeck99985b52014-10-13 10:32:00 +0200231 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welted193cb32010-05-17 22:58:03 +0200232 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200233 pfx, imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
Harald Weltec5d4a0c2010-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 Welteefbdee92010-06-10 00:20:12 +0200240 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-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 Welte8acd88f2010-05-18 10:57:45 +0200256 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
257
Harald Welted193cb32010-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 Welted193cb32010-05-17 22:58:03 +0200325DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
326 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100327 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-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 Welte288be162010-05-01 16:48:27 +0200336
Harald Welte7f6da482013-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 Erlbeck3b5d4072014-10-24 15:11:03 +0200350 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100351 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200352 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-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 Welte3dfb5492013-03-19 11:48:54 +0100362DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100363 "auth-policy (accept-all|closed|acl-only|remote)",
Harald Welte3dfb5492013-03-19 11:48:54 +0100364 "Autorization Policy of SGSN\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100365 "Accept all IMSIs (DANGEROUS)\n"
366 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100367 "Accept only subscribers in the ACL\n"
368 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100369{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100370 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100371 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100372 g_cfg->auth_policy = val;
Harald Welte3dfb5492013-03-19 11:48:54 +0100373
374 return CMD_SUCCESS;
375}
376
Jacob Erlbeck207f4a52014-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 Erlbeck7921ab12014-12-08 15:52:00 +0100383 struct gsm_auth_tuple *at;
384 int at_idx;
Jacob Erlbeck207f4a52014-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 Erlbeck7921ab12014-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 Erlbeck207f4a52014-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 Erlbeck7921ab12014-12-08 15:52:00 +0100464#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
465
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100466DEFUN(update_subscr_insert, update_subscr_insert_cmd,
Jacob Erlbeck2e5e94c2014-12-08 15:26:47 +0100467 UPDATE_SUBSCR_STR "insert (authorized|authenticate) (0|1)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100468 UPDATE_SUBSCR_HELP
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100469 UPDATE_SUBSCR_INSERT_HELP
Jacob Erlbeck207f4a52014-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 Erlbeck2e5e94c2014-12-08 15:26:47 +0100474 const char *option = argv[1];
475 const char *value = argv[2];
Jacob Erlbeck207f4a52014-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 Erlbeck2e5e94c2014-12-08 15:26:47 +0100487 else
488 subscr->sgsn_data->authenticate = atoi(value);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100489
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100490 subscr_put(subscr);
491
492 return CMD_SUCCESS;
493}
494
Jacob Erlbeck7921ab12014-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 Erlbeck207f4a52014-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 Welte288be162010-05-01 16:48:27 +0200590int sgsn_vty_init(void)
591{
Harald Welted193cb32010-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 Erlbeck207f4a52014-11-11 14:01:48 +0100597 install_element_ve(&show_subscr_cache_cmd);
598
599 install_element(ENABLE_NODE, &update_subscr_insert_cmd);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100600 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100601 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
602 install_element(ENABLE_NODE, &update_subscr_commit_cmd);
Harald Welte288be162010-05-01 16:48:27 +0200603
604 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
605 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeck36722e12013-10-29 09:30:30 +0100606 vty_install_default(SGSN_NODE);
Harald Weltee300d002010-06-02 12:41:34 +0200607 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-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 Welte7f6da482013-03-19 11:00:13 +0100611 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +0100612 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Harald Welte288be162010-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 Welte7f6da482013-03-19 11:00:13 +0100622
Harald Weltedcccb182010-05-16 20:52:23 +0200623 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-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}