blob: 9b925a8cb1d8584e1acddcbd9318503e97e5044f [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)
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100431 vty_out(vty, " Flags: %s%s%s%s%s",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100432 subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ?
433 "FIRST_CONTACT " : "",
434 subscr->flags & GPRS_SUBSCRIBER_CANCELLED ?
435 "CANCELLED " : "",
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100436 subscr->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
437 "UPDATE_LOCATION_PENDING " : "",
438 subscr->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
439 "AUTH_INFO_PENDING " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100440 VTY_NEWLINE);
441
442 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
443}
444
445DEFUN(show_subscr_cache,
446 show_subscr_cache_cmd,
447 "show subscriber cache",
448 SHOW_STR "Show information about subscribers\n"
449 "Display contents of subscriber cache\n")
450{
451 struct gsm_subscriber *subscr;
452
453 llist_for_each_entry(subscr, &active_subscribers, entry) {
454 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
455 subscr_dump_full_vty(vty, subscr, 0);
456 }
457
458 return CMD_SUCCESS;
459}
460
461#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
462#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
463 "Use the IMSI to select the subscriber\n" \
464 "The IMSI\n"
465
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100466#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
467
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100468DEFUN(update_subscr_insert, update_subscr_insert_cmd,
Jacob Erlbeck2e5e94c2014-12-08 15:26:47 +0100469 UPDATE_SUBSCR_STR "insert (authorized|authenticate) (0|1)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100470 UPDATE_SUBSCR_HELP
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100471 UPDATE_SUBSCR_INSERT_HELP
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100472 "Authorize the subscriber to attach\n"
473 "New option value\n")
474{
475 const char *imsi = argv[0];
Jacob Erlbeck2e5e94c2014-12-08 15:26:47 +0100476 const char *option = argv[1];
477 const char *value = argv[2];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100478
479 struct gsm_subscriber *subscr;
480
481 subscr = gprs_subscr_get_or_create(imsi);
482 if (!subscr) {
483 vty_out(vty, "%% unable get subscriber record for %s\n", imsi);
484 return CMD_WARNING;
485 }
486
487 if (!strcmp(option, "authorized"))
488 subscr->authorized = atoi(value);
Jacob Erlbeck2e5e94c2014-12-08 15:26:47 +0100489 else
490 subscr->sgsn_data->authenticate = atoi(value);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100491
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100492 subscr_put(subscr);
493
494 return CMD_SUCCESS;
495}
496
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100497DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
498 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
499 UPDATE_SUBSCR_HELP
500 UPDATE_SUBSCR_INSERT_HELP
501 "Update authentication triplet\n"
502 "Triplet index\n"
503 "Set SRES value\nSRES value (4 byte) in hex\n"
504 "Set RAND value\nRAND value (16 byte) in hex\n"
505 "Set Kc value\nKc value (8 byte) in hex\n")
506{
507 const char *imsi = argv[0];
508 const int cksn = atoi(argv[1]) - 1;
509 const char *sres_str = argv[2];
510 const char *rand_str = argv[3];
511 const char *kc_str = argv[4];
512 struct gsm_auth_tuple at = {0,};
513
514 struct gsm_subscriber *subscr;
515
516 subscr = gprs_subscr_get_or_create(imsi);
517 if (!subscr) {
518 vty_out(vty, "%% unable get subscriber record for %s\n", imsi);
519 return CMD_WARNING;
520 }
521
522 OSMO_ASSERT(subscr->sgsn_data);
523
524 if (!osmo_hexparse(sres_str, &at.sres[0], sizeof(at.sres)) < 0) {
525 vty_out(vty, "%% invalid SRES value '%s'\n", sres_str);
526 goto failed;
527 }
528 if (!osmo_hexparse(rand_str, &at.rand[0], sizeof(at.rand)) < 0) {
529 vty_out(vty, "%% invalid RAND value '%s'\n", rand_str);
530 goto failed;
531 }
532 if (!osmo_hexparse(kc_str, &at.kc[0], sizeof(at.kc)) < 0) {
533 vty_out(vty, "%% invalid Kc value '%s'\n", kc_str);
534 goto failed;
535 }
536 at.key_seq = cksn;
537
538 subscr->sgsn_data->auth_triplets[cksn] = at;
539 subscr->sgsn_data->auth_triplets_updated = 1;
540
541 subscr_put(subscr);
542
543 return CMD_SUCCESS;
544
545failed:
546 subscr_put(subscr);
547 return CMD_SUCCESS;
548}
549
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100550DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
551 UPDATE_SUBSCR_STR "cancel",
552 UPDATE_SUBSCR_HELP
553 "Cancel (remove) subscriber record\n")
554{
555 const char *imsi = argv[0];
556
557 struct gsm_subscriber *subscr;
558
559 subscr = gprs_subscr_get_by_imsi(imsi);
560 if (!subscr) {
561 vty_out(vty, "%% no subscriber record for %s\n", imsi);
562 return CMD_WARNING;
563 }
564
565 gprs_subscr_put_and_cancel(subscr);
566
567 return CMD_SUCCESS;
568}
569
570DEFUN(update_subscr_commit, update_subscr_commit_cmd,
571 UPDATE_SUBSCR_STR "commit",
572 UPDATE_SUBSCR_HELP
573 "Apply the changes made by the insert commands\n")
574{
575 const char *imsi = argv[0];
576
577 struct gsm_subscriber *subscr;
578
579 subscr = gprs_subscr_get_by_imsi(imsi);
580 if (!subscr) {
581 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
582 return CMD_WARNING;
583 }
584
585 gprs_subscr_update(subscr);
586
587 subscr_put(subscr);
588
589 return CMD_SUCCESS;
590}
591
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100592#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
593 "unknown-subscriber|roaming-not-allowed"
594
595#define UL_ERR_HELP \
596 "Force error code SystemFailure\n" \
597 "Force error code DataMissing\n" \
598 "Force error code UnexpectedDataValue\n" \
599 "Force error code UnknownSubscriber\n" \
600 "Force error code RoamingNotAllowed\n"
601
602DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
603 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
604 UPDATE_SUBSCR_HELP
605 "Complete the update location procedure\n"
606 "The update location request succeeded\n"
607 UL_ERR_HELP)
608{
609 const char *imsi = argv[0];
610 const char *ret_code_str = argv[1];
611
612 struct gsm_subscriber *subscr;
613
614 subscr = gprs_subscr_get_by_imsi(imsi);
615 if (!subscr) {
616 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
617 return CMD_WARNING;
618 }
619 if (strcmp(ret_code_str, "ok") == 0)
620 subscr->authorized = 1;
621 else
622 subscr->authorized = 0;
623
624 gprs_subscr_update(subscr);
625
626 subscr_put(subscr);
627
628 return CMD_SUCCESS;
629}
630
631DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
632 UPDATE_SUBSCR_STR "update-auth-info",
633 UPDATE_SUBSCR_HELP
634 "Complete the send authentication info procedure\n")
635{
636 const char *imsi = argv[0];
637
638 struct gsm_subscriber *subscr;
639
640 subscr = gprs_subscr_get_by_imsi(imsi);
641 if (!subscr) {
642 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
643 return CMD_WARNING;
644 }
645
646 gprs_subscr_update_auth_info(subscr);
647
648 subscr_put(subscr);
649
650 return CMD_SUCCESS;
651}
652
653
Harald Welte288be162010-05-01 16:48:27 +0200654int sgsn_vty_init(void)
655{
Harald Welted193cb32010-05-17 22:58:03 +0200656 install_element_ve(&show_sgsn_cmd);
657 //install_element_ve(&show_mmctx_tlli_cmd);
658 install_element_ve(&show_mmctx_imsi_cmd);
659 install_element_ve(&show_mmctx_all_cmd);
660 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100661 install_element_ve(&show_subscr_cache_cmd);
662
663 install_element(ENABLE_NODE, &update_subscr_insert_cmd);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100664 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100665 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
666 install_element(ENABLE_NODE, &update_subscr_commit_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100667 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
668 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Harald Welte288be162010-05-01 16:48:27 +0200669
670 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
671 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeck36722e12013-10-29 09:30:30 +0100672 vty_install_default(SGSN_NODE);
Harald Weltee300d002010-06-02 12:41:34 +0200673 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +0200674 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
675 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
676 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +0100677 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +0100678 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Harald Welte288be162010-05-01 16:48:27 +0200679
680 return 0;
681}
682
683int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
684{
685 int rc;
686
687 g_cfg = cfg;
Harald Welte7f6da482013-03-19 11:00:13 +0100688
Harald Weltedcccb182010-05-16 20:52:23 +0200689 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +0200690 if (rc < 0) {
691 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
692 return rc;
693 }
694
695 return 0;
696}