blob: 3ca1570b95136d1de62dae85865b5f2cb581f861 [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);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100142 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
143 vty_out(vty, " gsup remote-ip %s%s",
144 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
145 if (g_cfg->gsup_server_port)
146 vty_out(vty, " gsup remote-port %d%s",
147 g_cfg->gsup_server_port, VTY_NEWLINE);
Harald Welte7f6da482013-03-19 11:00:13 +0100148 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
149 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
150
Harald Welte288be162010-05-01 16:48:27 +0200151 return CMD_SUCCESS;
152}
153
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100154#define SGSN_STR "Configure the SGSN\n"
155#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200156
157DEFUN(cfg_sgsn, cfg_sgsn_cmd,
158 "sgsn",
159 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200160{
161 vty->node = SGSN_NODE;
162 return CMD_SUCCESS;
163}
164
Harald Weltee300d002010-06-02 12:41:34 +0200165DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
166 "gtp local-ip A.B.C.D",
167 "GTP Parameters\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100168 "Set the IP address for the local GTP bind\n"
169 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200170{
171 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
172
173 return CMD_SUCCESS;
174}
175
Harald Welted193cb32010-05-17 22:58:03 +0200176DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
177 "ggsn <0-255> remote-ip A.B.C.D",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100178 GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200179{
180 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200181 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200182
Harald Welted193cb32010-05-17 22:58:03 +0200183 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200184
Harald Welted193cb32010-05-17 22:58:03 +0200185 return CMD_SUCCESS;
186}
187
188#if 0
189DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
190 "ggsn <0-255> remote-port <0-65535>",
191 "")
192{
193 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200194 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200195 uint16_t port = atoi(argv[1]);
196
197}
198#endif
199
200DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
201 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100202 GGSN_STR "GGSN Number\n" "GTP Version\n"
203 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200204{
205 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200206 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200207
208 if (atoi(argv[1]))
209 ggc->gtp_version = 1;
210 else
211 ggc->gtp_version = 0;
212
213 return CMD_SUCCESS;
214}
215
216#if 0
217DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
218 "apn APNAME ggsn <0-255>",
219 "")
220{
221 struct apn_ctx **
222}
223#endif
224
225const struct value_string gprs_mm_st_strs[] = {
226 { GMM_DEREGISTERED, "DEREGISTERED" },
227 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
228 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200229 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200230 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
231 { 0, NULL }
232};
233
234static void vty_dump_pdp(struct vty *vty, const char *pfx,
235 struct sgsn_pdp_ctx *pdp)
236{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200237 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welted193cb32010-05-17 22:58:03 +0200238 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200239 pfx, imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200240 vty_out(vty, "%s APN: %s%s", pfx,
241 gprs_apn2str(pdp->lib->apn_use.v, pdp->lib->apn_use.l),
242 VTY_NEWLINE);
243 vty_out(vty, "%s PDP Address: %s%s", pfx,
244 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
245 VTY_NEWLINE);
Harald Welteefbdee92010-06-10 00:20:12 +0200246 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200247}
248
249static void vty_dump_mmctx(struct vty *vty, const char *pfx,
250 struct sgsn_mm_ctx *mm, int pdp)
251{
252 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
253 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
254 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s", pfx, mm->msisdn,
255 mm->tlli, VTY_NEWLINE);
256 vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, "
257 "Cell ID: %u%s", pfx,
258 get_value_string(gprs_mm_st_strs, mm->mm_state),
259 mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac,
260 mm->cell_id, VTY_NEWLINE);
261
Harald Welte8acd88f2010-05-18 10:57:45 +0200262 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
263
Harald Welted193cb32010-05-17 22:58:03 +0200264 if (pdp) {
265 struct sgsn_pdp_ctx *pdp;
266
267 llist_for_each_entry(pdp, &mm->pdp_list, list)
268 vty_dump_pdp(vty, " ", pdp);
269 }
270}
271
272DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
273 SHOW_STR "Display information about the SGSN")
274{
275 /* FIXME: statistics */
276 return CMD_SUCCESS;
277}
278
279#define MMCTX_STR "MM Context\n"
280#define INCLUDE_PDP_STR "Include PDP Context Information\n"
281
282#if 0
283DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
284 "show mm-context tlli HEX [pdp]",
285 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
286{
287 uint32_t tlli;
288 struct sgsn_mm_ctx *mm;
289
290 tlli = strtoul(argv[0], NULL, 16);
291 mm = sgsn_mm_ctx_by_tlli(tlli);
292 if (!mm) {
293 vty_out(vty, "No MM context for TLLI %08x%s",
294 tlli, VTY_NEWLINE);
295 return CMD_WARNING;
296 }
297 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
298 return CMD_SUCCESS;
299}
300#endif
301
302DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
303 "show mm-context imsi IMSI [pdp]",
304 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
305 INCLUDE_PDP_STR)
306{
307 struct sgsn_mm_ctx *mm;
308
309 mm = sgsn_mm_ctx_by_imsi(argv[0]);
310 if (!mm) {
311 vty_out(vty, "No MM context for IMSI %s%s",
312 argv[0], VTY_NEWLINE);
313 return CMD_WARNING;
314 }
315 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
316 return CMD_SUCCESS;
317}
318
319DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
320 "show mm-context all [pdp]",
321 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
322{
323 struct sgsn_mm_ctx *mm;
324
325 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
326 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
327
328 return CMD_SUCCESS;
329}
330
Harald Welted193cb32010-05-17 22:58:03 +0200331DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
332 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100333 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200334{
335 struct sgsn_pdp_ctx *pdp;
336
337 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
338 vty_dump_pdp(vty, "", pdp);
339
340 return CMD_SUCCESS;
341}
Harald Welte288be162010-05-01 16:48:27 +0200342
Harald Welte7f6da482013-03-19 11:00:13 +0100343
344DEFUN(imsi_acl, cfg_imsi_acl_cmd,
345 "imsi-acl (add|del) IMSI",
346 "Access Control List of foreign IMSIs\n"
347 "Add IMSI to ACL\n"
348 "Remove IMSI from ACL\n"
349 "IMSI of subscriber\n")
350{
351 const char *op = argv[0];
352 const char *imsi = argv[1];
353 int rc;
354
355 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200356 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100357 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200358 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100359
360 if (rc < 0) {
361 vty_out(vty, "%% unable to %s ACL\n", op);
362 return CMD_WARNING;
363 }
364
365 return CMD_SUCCESS;
366}
367
Harald Welte3dfb5492013-03-19 11:48:54 +0100368DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100369 "auth-policy (accept-all|closed|acl-only|remote)",
Harald Welte3dfb5492013-03-19 11:48:54 +0100370 "Autorization Policy of SGSN\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100371 "Accept all IMSIs (DANGEROUS)\n"
372 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100373 "Accept only subscribers in the ACL\n"
374 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100375{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100376 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100377 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100378 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100379 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100380
381 return CMD_SUCCESS;
382}
383
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100384/* Subscriber */
385#include <openbsc/gsm_subscriber.h>
386
387static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending)
388{
389 char expire_time[200];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100390 struct gsm_auth_tuple *at;
391 int at_idx;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100392
393 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
394 subscr->authorized, VTY_NEWLINE);
395 if (strlen(subscr->name))
396 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
397 if (strlen(subscr->extension))
398 vty_out(vty, " Extension: %s%s", subscr->extension,
399 VTY_NEWLINE);
400 vty_out(vty, " LAC: %d/0x%x%s",
401 subscr->lac, subscr->lac, VTY_NEWLINE);
402 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
403 if (subscr->tmsi != GSM_RESERVED_TMSI)
404 vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
405 VTY_NEWLINE);
406
407 if (strlen(subscr->equipment.imei) > 0)
408 vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE);
409
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100410 for (at_idx = 0; at_idx < ARRAY_SIZE(subscr->sgsn_data->auth_triplets);
411 at_idx++) {
412 at = &subscr->sgsn_data->auth_triplets[at_idx];
413 if (at->key_seq == GSM_KEY_SEQ_INVAL)
414 continue;
415
416 vty_out(vty, " A3A8 tuple (used %d times): ",
417 at->use_count);
418 vty_out(vty, " seq # : %d, ",
419 at->key_seq);
420 vty_out(vty, " RAND : %s, ",
421 osmo_hexdump(at->rand, sizeof(at->rand)));
422 vty_out(vty, " SRES : %s, ",
423 osmo_hexdump(at->sres, sizeof(at->sres)));
424 vty_out(vty, " Kc : %s%s",
425 osmo_hexdump(at->kc, sizeof(at->kc)),
426 VTY_NEWLINE);
427 }
428
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100429 /* print the expiration time of a subscriber */
430 if (subscr->expire_lu) {
431 strftime(expire_time, sizeof(expire_time),
432 "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
433 expire_time[sizeof(expire_time) - 1] = '\0';
434 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
435 }
436
437 if (subscr->flags)
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100438 vty_out(vty, " Flags: %s%s%s%s%s",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100439 subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ?
440 "FIRST_CONTACT " : "",
441 subscr->flags & GPRS_SUBSCRIBER_CANCELLED ?
442 "CANCELLED " : "",
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100443 subscr->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
444 "UPDATE_LOCATION_PENDING " : "",
445 subscr->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
446 "AUTH_INFO_PENDING " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100447 VTY_NEWLINE);
448
449 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
450}
451
452DEFUN(show_subscr_cache,
453 show_subscr_cache_cmd,
454 "show subscriber cache",
455 SHOW_STR "Show information about subscribers\n"
456 "Display contents of subscriber cache\n")
457{
458 struct gsm_subscriber *subscr;
459
460 llist_for_each_entry(subscr, &active_subscribers, entry) {
461 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
462 subscr_dump_full_vty(vty, subscr, 0);
463 }
464
465 return CMD_SUCCESS;
466}
467
468#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
469#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
470 "Use the IMSI to select the subscriber\n" \
471 "The IMSI\n"
472
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100473#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
474
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100475DEFUN(update_subscr_insert, update_subscr_insert_cmd,
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100476 UPDATE_SUBSCR_STR "insert authorized <0-1>)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100477 UPDATE_SUBSCR_HELP
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100478 UPDATE_SUBSCR_INSERT_HELP
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100479 "Authorize the subscriber to attach\n"
480 "New option value\n")
481{
482 const char *imsi = argv[0];
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100483 const char *value = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100484
485 struct gsm_subscriber *subscr;
486
487 subscr = gprs_subscr_get_or_create(imsi);
488 if (!subscr) {
489 vty_out(vty, "%% unable get subscriber record for %s\n", imsi);
490 return CMD_WARNING;
491 }
492
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100493 subscr->authorized = atoi(value);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100494
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100495 subscr_put(subscr);
496
497 return CMD_SUCCESS;
498}
499
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100500DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
501 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
502 UPDATE_SUBSCR_HELP
503 UPDATE_SUBSCR_INSERT_HELP
504 "Update authentication triplet\n"
505 "Triplet index\n"
506 "Set SRES value\nSRES value (4 byte) in hex\n"
507 "Set RAND value\nRAND value (16 byte) in hex\n"
508 "Set Kc value\nKc value (8 byte) in hex\n")
509{
510 const char *imsi = argv[0];
511 const int cksn = atoi(argv[1]) - 1;
512 const char *sres_str = argv[2];
513 const char *rand_str = argv[3];
514 const char *kc_str = argv[4];
515 struct gsm_auth_tuple at = {0,};
516
517 struct gsm_subscriber *subscr;
518
519 subscr = gprs_subscr_get_or_create(imsi);
520 if (!subscr) {
521 vty_out(vty, "%% unable get subscriber record for %s\n", imsi);
522 return CMD_WARNING;
523 }
524
525 OSMO_ASSERT(subscr->sgsn_data);
526
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100527 if (osmo_hexparse(sres_str, &at.sres[0], sizeof(at.sres)) < 0) {
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100528 vty_out(vty, "%% invalid SRES value '%s'\n", sres_str);
529 goto failed;
530 }
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100531 if (osmo_hexparse(rand_str, &at.rand[0], sizeof(at.rand)) < 0) {
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100532 vty_out(vty, "%% invalid RAND value '%s'\n", rand_str);
533 goto failed;
534 }
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100535 if (osmo_hexparse(kc_str, &at.kc[0], sizeof(at.kc)) < 0) {
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100536 vty_out(vty, "%% invalid Kc value '%s'\n", kc_str);
537 goto failed;
538 }
539 at.key_seq = cksn;
540
541 subscr->sgsn_data->auth_triplets[cksn] = at;
542 subscr->sgsn_data->auth_triplets_updated = 1;
543
544 subscr_put(subscr);
545
546 return CMD_SUCCESS;
547
548failed:
549 subscr_put(subscr);
550 return CMD_SUCCESS;
551}
552
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100553DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
554 UPDATE_SUBSCR_STR "cancel",
555 UPDATE_SUBSCR_HELP
556 "Cancel (remove) subscriber record\n")
557{
558 const char *imsi = argv[0];
559
560 struct gsm_subscriber *subscr;
561
562 subscr = gprs_subscr_get_by_imsi(imsi);
563 if (!subscr) {
564 vty_out(vty, "%% no subscriber record for %s\n", imsi);
565 return CMD_WARNING;
566 }
567
568 gprs_subscr_put_and_cancel(subscr);
569
570 return CMD_SUCCESS;
571}
572
573DEFUN(update_subscr_commit, update_subscr_commit_cmd,
574 UPDATE_SUBSCR_STR "commit",
575 UPDATE_SUBSCR_HELP
576 "Apply the changes made by the insert commands\n")
577{
578 const char *imsi = argv[0];
579
580 struct gsm_subscriber *subscr;
581
582 subscr = gprs_subscr_get_by_imsi(imsi);
583 if (!subscr) {
584 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
585 return CMD_WARNING;
586 }
587
588 gprs_subscr_update(subscr);
589
590 subscr_put(subscr);
591
592 return CMD_SUCCESS;
593}
594
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100595#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
596 "unknown-subscriber|roaming-not-allowed"
597
598#define UL_ERR_HELP \
599 "Force error code SystemFailure\n" \
600 "Force error code DataMissing\n" \
601 "Force error code UnexpectedDataValue\n" \
602 "Force error code UnknownSubscriber\n" \
603 "Force error code RoamingNotAllowed\n"
604
605DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
606 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
607 UPDATE_SUBSCR_HELP
608 "Complete the update location procedure\n"
609 "The update location request succeeded\n"
610 UL_ERR_HELP)
611{
612 const char *imsi = argv[0];
613 const char *ret_code_str = argv[1];
614
615 struct gsm_subscriber *subscr;
616
617 subscr = gprs_subscr_get_by_imsi(imsi);
618 if (!subscr) {
619 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
620 return CMD_WARNING;
621 }
622 if (strcmp(ret_code_str, "ok") == 0)
623 subscr->authorized = 1;
624 else
625 subscr->authorized = 0;
626
627 gprs_subscr_update(subscr);
628
629 subscr_put(subscr);
630
631 return CMD_SUCCESS;
632}
633
634DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
635 UPDATE_SUBSCR_STR "update-auth-info",
636 UPDATE_SUBSCR_HELP
637 "Complete the send authentication info procedure\n")
638{
639 const char *imsi = argv[0];
640
641 struct gsm_subscriber *subscr;
642
643 subscr = gprs_subscr_get_by_imsi(imsi);
644 if (!subscr) {
645 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
646 return CMD_WARNING;
647 }
648
649 gprs_subscr_update_auth_info(subscr);
650
651 subscr_put(subscr);
652
653 return CMD_SUCCESS;
654}
655
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100656DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
657 "gsup remote-ip A.B.C.D",
658 "GSUP Parameters\n"
659 "Set the IP address of the remote GSUP server\n"
660 "IPv4 Address\n")
661{
662 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
663
664 return CMD_SUCCESS;
665}
666
667DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
668 "gsup remote-port <0-65535>",
669 "GSUP Parameters\n"
670 "Set the TCP port of the remote GSUP server\n"
671 "Remote TCP port\n")
672{
673 g_cfg->gsup_server_port = atoi(argv[0]);
674
675 return CMD_SUCCESS;
676}
677
678
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100679
Harald Welte288be162010-05-01 16:48:27 +0200680int sgsn_vty_init(void)
681{
Harald Welted193cb32010-05-17 22:58:03 +0200682 install_element_ve(&show_sgsn_cmd);
683 //install_element_ve(&show_mmctx_tlli_cmd);
684 install_element_ve(&show_mmctx_imsi_cmd);
685 install_element_ve(&show_mmctx_all_cmd);
686 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100687 install_element_ve(&show_subscr_cache_cmd);
688
689 install_element(ENABLE_NODE, &update_subscr_insert_cmd);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100690 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100691 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
692 install_element(ENABLE_NODE, &update_subscr_commit_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100693 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
694 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Harald Welte288be162010-05-01 16:48:27 +0200695
696 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
697 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeck36722e12013-10-29 09:30:30 +0100698 vty_install_default(SGSN_NODE);
Harald Weltee300d002010-06-02 12:41:34 +0200699 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +0200700 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
701 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
702 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +0100703 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +0100704 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100705 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
706 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Harald Welte288be162010-05-01 16:48:27 +0200707
708 return 0;
709}
710
711int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
712{
713 int rc;
714
715 g_cfg = cfg;
Harald Welte7f6da482013-03-19 11:00:13 +0100716
Harald Weltedcccb182010-05-16 20:52:23 +0200717 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +0200718 if (rc < 0) {
719 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
720 return rc;
721 }
722
723 return 0;
724}