blob: d847d9173c6eef4f78a1e1af63260fb304bf0041 [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);
Jacob Erlbeck233715c2014-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 Weltea0879c12013-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 Welte55fe0552010-05-01 16:48:27 +0200151 return CMD_SUCCESS;
152}
153
Holger Hans Peter Freytherf403c482011-11-05 15:21:16 +0100154#define SGSN_STR "Configure the SGSN\n"
155#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee0aea392010-06-02 12:41:34 +0200156
157DEFUN(cfg_sgsn, cfg_sgsn_cmd,
158 "sgsn",
159 SGSN_STR)
Harald Welte55fe0552010-05-01 16:48:27 +0200160{
161 vty->node = SGSN_NODE;
162 return CMD_SUCCESS;
163}
164
Harald Weltee0aea392010-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 Freytherf403c482011-11-05 15:21:16 +0100168 "Set the IP address for the local GTP bind\n"
169 "IPv4 Address\n")
Harald Weltee0aea392010-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 Weltec1f6bfe2010-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 Freytherf403c482011-11-05 15:21:16 +0100178 GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n")
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200179{
180 uint32_t id = atoi(argv[0]);
Harald Welteeb471c92010-05-18 14:32:29 +0200181 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte55fe0552010-05-01 16:48:27 +0200182
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200183 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte55fe0552010-05-01 16:48:27 +0200184
Harald Weltec1f6bfe2010-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 Welteeb471c92010-05-18 14:32:29 +0200194 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Weltec1f6bfe2010-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 Freytherf403c482011-11-05 15:21:16 +0100202 GGSN_STR "GGSN Number\n" "GTP Version\n"
203 "Version 0\n" "Version 1\n")
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200204{
205 uint32_t id = atoi(argv[0]);
Harald Welteeb471c92010-05-18 14:32:29 +0200206 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Weltec1f6bfe2010-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 Welte3ba2ce12010-06-09 15:50:45 +0200229 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Weltec1f6bfe2010-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 Erlbeckd781c7a2014-10-13 10:32:00 +0200237 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200238 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
Jacob Erlbeckd781c7a2014-10-13 10:32:00 +0200239 pfx, imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
Harald Welte493ba622010-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 Welte0fe506b2010-06-10 00:20:12 +0200246 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Weltec1f6bfe2010-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 Welte8a035af2010-05-18 10:57:45 +0200262 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
263
Harald Weltec1f6bfe2010-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 Weltec1f6bfe2010-05-17 22:58:03 +0200331DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
332 "show pdp-context all",
Holger Hans Peter Freytherf403c482011-11-05 15:21:16 +0100333 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Weltec1f6bfe2010-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 Welte55fe0552010-05-01 16:48:27 +0200342
Harald Weltea0879c12013-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 Erlbeck4760eae2014-10-24 15:11:03 +0200356 rc = sgsn_acl_add(imsi, g_cfg);
Harald Weltea0879c12013-03-19 11:00:13 +0100357 else
Jacob Erlbeck4760eae2014-10-24 15:11:03 +0200358 rc = sgsn_acl_del(imsi, g_cfg);
Harald Weltea0879c12013-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 Welte2b9693d2013-03-19 11:48:54 +0100368DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckd04f7cc2014-11-12 10:18:09 +0100369 "auth-policy (accept-all|closed|acl-only|remote)",
Harald Welte2b9693d2013-03-19 11:48:54 +0100370 "Autorization Policy of SGSN\n"
Jacob Erlbeckd7b77732014-11-04 10:08:37 +0100371 "Accept all IMSIs (DANGEROUS)\n"
372 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckd04f7cc2014-11-12 10:18:09 +0100373 "Accept only subscribers in the ACL\n"
374 "Use remote subscription data only (HLR)\n")
Harald Welte2b9693d2013-03-19 11:48:54 +0100375{
Jacob Erlbeckd7b77732014-11-04 10:08:37 +0100376 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckd04f7cc2014-11-12 10:18:09 +0100377 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeckd7b77732014-11-04 10:08:37 +0100378 g_cfg->auth_policy = val;
Jacob Erlbeck16b17ed2014-12-17 13:20:08 +0100379 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck6ff7f642014-12-19 18:08:48 +0100380 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte2b9693d2013-03-19 11:48:54 +0100381
382 return CMD_SUCCESS;
383}
384
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100385/* Subscriber */
386#include <openbsc/gsm_subscriber.h>
387
388static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending)
389{
390 char expire_time[200];
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100391 struct gsm_auth_tuple *at;
392 int at_idx;
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100393
394 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
395 subscr->authorized, VTY_NEWLINE);
396 if (strlen(subscr->name))
397 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
398 if (strlen(subscr->extension))
399 vty_out(vty, " Extension: %s%s", subscr->extension,
400 VTY_NEWLINE);
401 vty_out(vty, " LAC: %d/0x%x%s",
402 subscr->lac, subscr->lac, VTY_NEWLINE);
403 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
404 if (subscr->tmsi != GSM_RESERVED_TMSI)
405 vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
406 VTY_NEWLINE);
407
408 if (strlen(subscr->equipment.imei) > 0)
409 vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE);
410
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100411 for (at_idx = 0; at_idx < ARRAY_SIZE(subscr->sgsn_data->auth_triplets);
412 at_idx++) {
413 at = &subscr->sgsn_data->auth_triplets[at_idx];
414 if (at->key_seq == GSM_KEY_SEQ_INVAL)
415 continue;
416
417 vty_out(vty, " A3A8 tuple (used %d times): ",
418 at->use_count);
419 vty_out(vty, " seq # : %d, ",
420 at->key_seq);
421 vty_out(vty, " RAND : %s, ",
422 osmo_hexdump(at->rand, sizeof(at->rand)));
423 vty_out(vty, " SRES : %s, ",
424 osmo_hexdump(at->sres, sizeof(at->sres)));
425 vty_out(vty, " Kc : %s%s",
426 osmo_hexdump(at->kc, sizeof(at->kc)),
427 VTY_NEWLINE);
428 }
429
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100430 /* print the expiration time of a subscriber */
431 if (subscr->expire_lu) {
432 strftime(expire_time, sizeof(expire_time),
433 "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
434 expire_time[sizeof(expire_time) - 1] = '\0';
435 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
436 }
437
438 if (subscr->flags)
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100439 vty_out(vty, " Flags: %s%s%s%s%s",
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100440 subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ?
441 "FIRST_CONTACT " : "",
442 subscr->flags & GPRS_SUBSCRIBER_CANCELLED ?
443 "CANCELLED " : "",
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100444 subscr->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
445 "UPDATE_LOCATION_PENDING " : "",
446 subscr->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
447 "AUTH_INFO_PENDING " : "",
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100448 VTY_NEWLINE);
449
450 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
451}
452
453DEFUN(show_subscr_cache,
454 show_subscr_cache_cmd,
455 "show subscriber cache",
456 SHOW_STR "Show information about subscribers\n"
457 "Display contents of subscriber cache\n")
458{
459 struct gsm_subscriber *subscr;
460
461 llist_for_each_entry(subscr, &active_subscribers, entry) {
462 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
463 subscr_dump_full_vty(vty, subscr, 0);
464 }
465
466 return CMD_SUCCESS;
467}
468
469#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
470#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
471 "Use the IMSI to select the subscriber\n" \
472 "The IMSI\n"
473
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100474#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
475
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100476DEFUN(update_subscr_insert, update_subscr_insert_cmd,
Jacob Erlbeck16b17ed2014-12-17 13:20:08 +0100477 UPDATE_SUBSCR_STR "insert authorized <0-1>)",
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100478 UPDATE_SUBSCR_HELP
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100479 UPDATE_SUBSCR_INSERT_HELP
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100480 "Authorize the subscriber to attach\n"
481 "New option value\n")
482{
483 const char *imsi = argv[0];
Jacob Erlbeck16b17ed2014-12-17 13:20:08 +0100484 const char *value = argv[1];
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100485
486 struct gsm_subscriber *subscr;
487
488 subscr = gprs_subscr_get_or_create(imsi);
489 if (!subscr) {
490 vty_out(vty, "%% unable get subscriber record for %s\n", imsi);
491 return CMD_WARNING;
492 }
493
Jacob Erlbeck16b17ed2014-12-17 13:20:08 +0100494 subscr->authorized = atoi(value);
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100495
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100496 subscr_put(subscr);
497
498 return CMD_SUCCESS;
499}
500
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100501DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
502 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
503 UPDATE_SUBSCR_HELP
504 UPDATE_SUBSCR_INSERT_HELP
505 "Update authentication triplet\n"
506 "Triplet index\n"
507 "Set SRES value\nSRES value (4 byte) in hex\n"
508 "Set RAND value\nRAND value (16 byte) in hex\n"
509 "Set Kc value\nKc value (8 byte) in hex\n")
510{
511 const char *imsi = argv[0];
512 const int cksn = atoi(argv[1]) - 1;
513 const char *sres_str = argv[2];
514 const char *rand_str = argv[3];
515 const char *kc_str = argv[4];
516 struct gsm_auth_tuple at = {0,};
517
518 struct gsm_subscriber *subscr;
519
520 subscr = gprs_subscr_get_or_create(imsi);
521 if (!subscr) {
522 vty_out(vty, "%% unable get subscriber record for %s\n", imsi);
523 return CMD_WARNING;
524 }
525
526 OSMO_ASSERT(subscr->sgsn_data);
527
Jacob Erlbeckf7f55bd2015-01-05 09:43:51 +0100528 if (osmo_hexparse(sres_str, &at.sres[0], sizeof(at.sres)) < 0) {
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100529 vty_out(vty, "%% invalid SRES value '%s'\n", sres_str);
530 goto failed;
531 }
Jacob Erlbeckf7f55bd2015-01-05 09:43:51 +0100532 if (osmo_hexparse(rand_str, &at.rand[0], sizeof(at.rand)) < 0) {
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100533 vty_out(vty, "%% invalid RAND value '%s'\n", rand_str);
534 goto failed;
535 }
Jacob Erlbeckf7f55bd2015-01-05 09:43:51 +0100536 if (osmo_hexparse(kc_str, &at.kc[0], sizeof(at.kc)) < 0) {
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100537 vty_out(vty, "%% invalid Kc value '%s'\n", kc_str);
538 goto failed;
539 }
540 at.key_seq = cksn;
541
542 subscr->sgsn_data->auth_triplets[cksn] = at;
543 subscr->sgsn_data->auth_triplets_updated = 1;
544
545 subscr_put(subscr);
546
547 return CMD_SUCCESS;
548
549failed:
550 subscr_put(subscr);
551 return CMD_SUCCESS;
552}
553
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100554DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
555 UPDATE_SUBSCR_STR "cancel",
556 UPDATE_SUBSCR_HELP
557 "Cancel (remove) subscriber record\n")
558{
559 const char *imsi = argv[0];
560
561 struct gsm_subscriber *subscr;
562
563 subscr = gprs_subscr_get_by_imsi(imsi);
564 if (!subscr) {
565 vty_out(vty, "%% no subscriber record for %s\n", imsi);
566 return CMD_WARNING;
567 }
568
569 gprs_subscr_put_and_cancel(subscr);
570
571 return CMD_SUCCESS;
572}
573
574DEFUN(update_subscr_commit, update_subscr_commit_cmd,
575 UPDATE_SUBSCR_STR "commit",
576 UPDATE_SUBSCR_HELP
577 "Apply the changes made by the insert commands\n")
578{
579 const char *imsi = argv[0];
580
581 struct gsm_subscriber *subscr;
582
583 subscr = gprs_subscr_get_by_imsi(imsi);
584 if (!subscr) {
585 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
586 return CMD_WARNING;
587 }
588
589 gprs_subscr_update(subscr);
590
591 subscr_put(subscr);
592
593 return CMD_SUCCESS;
594}
595
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100596#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
597 "unknown-subscriber|roaming-not-allowed"
598
599#define UL_ERR_HELP \
600 "Force error code SystemFailure\n" \
601 "Force error code DataMissing\n" \
602 "Force error code UnexpectedDataValue\n" \
603 "Force error code UnknownSubscriber\n" \
604 "Force error code RoamingNotAllowed\n"
605
606DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
607 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
608 UPDATE_SUBSCR_HELP
609 "Complete the update location procedure\n"
610 "The update location request succeeded\n"
611 UL_ERR_HELP)
612{
613 const char *imsi = argv[0];
614 const char *ret_code_str = argv[1];
615
616 struct gsm_subscriber *subscr;
617
618 subscr = gprs_subscr_get_by_imsi(imsi);
619 if (!subscr) {
620 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
621 return CMD_WARNING;
622 }
623 if (strcmp(ret_code_str, "ok") == 0)
624 subscr->authorized = 1;
625 else
626 subscr->authorized = 0;
627
628 gprs_subscr_update(subscr);
629
630 subscr_put(subscr);
631
632 return CMD_SUCCESS;
633}
634
635DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
636 UPDATE_SUBSCR_STR "update-auth-info",
637 UPDATE_SUBSCR_HELP
638 "Complete the send authentication info procedure\n")
639{
640 const char *imsi = argv[0];
641
642 struct gsm_subscriber *subscr;
643
644 subscr = gprs_subscr_get_by_imsi(imsi);
645 if (!subscr) {
646 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
647 return CMD_WARNING;
648 }
649
650 gprs_subscr_update_auth_info(subscr);
651
652 subscr_put(subscr);
653
654 return CMD_SUCCESS;
655}
656
Jacob Erlbeck233715c2014-12-18 12:46:47 +0100657DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
658 "gsup remote-ip A.B.C.D",
659 "GSUP Parameters\n"
660 "Set the IP address of the remote GSUP server\n"
661 "IPv4 Address\n")
662{
663 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
664
665 return CMD_SUCCESS;
666}
667
668DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
669 "gsup remote-port <0-65535>",
670 "GSUP Parameters\n"
671 "Set the TCP port of the remote GSUP server\n"
672 "Remote TCP port\n")
673{
674 g_cfg->gsup_server_port = atoi(argv[0]);
675
676 return CMD_SUCCESS;
677}
678
679
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100680
Harald Welte55fe0552010-05-01 16:48:27 +0200681int sgsn_vty_init(void)
682{
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200683 install_element_ve(&show_sgsn_cmd);
684 //install_element_ve(&show_mmctx_tlli_cmd);
685 install_element_ve(&show_mmctx_imsi_cmd);
686 install_element_ve(&show_mmctx_all_cmd);
687 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100688 install_element_ve(&show_subscr_cache_cmd);
689
690 install_element(ENABLE_NODE, &update_subscr_insert_cmd);
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100691 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckc16c3502014-11-11 14:01:48 +0100692 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
693 install_element(ENABLE_NODE, &update_subscr_commit_cmd);
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100694 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
695 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Harald Welte55fe0552010-05-01 16:48:27 +0200696
697 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
698 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeckf414e852013-10-29 09:30:30 +0100699 vty_install_default(SGSN_NODE);
Harald Weltee0aea392010-06-02 12:41:34 +0200700 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200701 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
702 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
703 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Harald Weltea0879c12013-03-19 11:00:13 +0100704 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte2b9693d2013-03-19 11:48:54 +0100705 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Jacob Erlbeck233715c2014-12-18 12:46:47 +0100706 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
707 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Harald Welte55fe0552010-05-01 16:48:27 +0200708
709 return 0;
710}
711
712int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
713{
714 int rc;
715
716 g_cfg = cfg;
Harald Weltea0879c12013-03-19 11:00:13 +0100717
Harald Welte40152872010-05-16 20:52:23 +0200718 rc = vty_read_config_file(config_file, NULL);
Harald Welte55fe0552010-05-01 16:48:27 +0200719 if (rc < 0) {
720 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
721 return rc;
722 }
723
724 return 0;
725}