blob: e9333f5622ed85b3309da10be34d4b75cb5d5e47 [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;
Harald Welte3dfb5492013-03-19 11:48:54 +0100379
380 return CMD_SUCCESS;
381}
382
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100383/* Subscriber */
384#include <openbsc/gsm_subscriber.h>
385
386static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending)
387{
388 char expire_time[200];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100389 struct gsm_auth_tuple *at;
390 int at_idx;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100391
392 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
393 subscr->authorized, VTY_NEWLINE);
394 if (strlen(subscr->name))
395 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
396 if (strlen(subscr->extension))
397 vty_out(vty, " Extension: %s%s", subscr->extension,
398 VTY_NEWLINE);
399 vty_out(vty, " LAC: %d/0x%x%s",
400 subscr->lac, subscr->lac, VTY_NEWLINE);
401 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
402 if (subscr->tmsi != GSM_RESERVED_TMSI)
403 vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
404 VTY_NEWLINE);
405
406 if (strlen(subscr->equipment.imei) > 0)
407 vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE);
408
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100409 for (at_idx = 0; at_idx < ARRAY_SIZE(subscr->sgsn_data->auth_triplets);
410 at_idx++) {
411 at = &subscr->sgsn_data->auth_triplets[at_idx];
412 if (at->key_seq == GSM_KEY_SEQ_INVAL)
413 continue;
414
415 vty_out(vty, " A3A8 tuple (used %d times): ",
416 at->use_count);
417 vty_out(vty, " seq # : %d, ",
418 at->key_seq);
419 vty_out(vty, " RAND : %s, ",
420 osmo_hexdump(at->rand, sizeof(at->rand)));
421 vty_out(vty, " SRES : %s, ",
422 osmo_hexdump(at->sres, sizeof(at->sres)));
423 vty_out(vty, " Kc : %s%s",
424 osmo_hexdump(at->kc, sizeof(at->kc)),
425 VTY_NEWLINE);
426 }
427
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100428 /* print the expiration time of a subscriber */
429 if (subscr->expire_lu) {
430 strftime(expire_time, sizeof(expire_time),
431 "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
432 expire_time[sizeof(expire_time) - 1] = '\0';
433 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
434 }
435
436 if (subscr->flags)
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100437 vty_out(vty, " Flags: %s%s%s%s%s",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100438 subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ?
439 "FIRST_CONTACT " : "",
440 subscr->flags & GPRS_SUBSCRIBER_CANCELLED ?
441 "CANCELLED " : "",
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100442 subscr->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
443 "UPDATE_LOCATION_PENDING " : "",
444 subscr->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
445 "AUTH_INFO_PENDING " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100446 VTY_NEWLINE);
447
448 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
449}
450
451DEFUN(show_subscr_cache,
452 show_subscr_cache_cmd,
453 "show subscriber cache",
454 SHOW_STR "Show information about subscribers\n"
455 "Display contents of subscriber cache\n")
456{
457 struct gsm_subscriber *subscr;
458
459 llist_for_each_entry(subscr, &active_subscribers, entry) {
460 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
461 subscr_dump_full_vty(vty, subscr, 0);
462 }
463
464 return CMD_SUCCESS;
465}
466
467#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
468#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
469 "Use the IMSI to select the subscriber\n" \
470 "The IMSI\n"
471
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100472#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
473
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100474DEFUN(update_subscr_insert, update_subscr_insert_cmd,
Jacob Erlbeck2e5e94c2014-12-08 15:26:47 +0100475 UPDATE_SUBSCR_STR "insert (authorized|authenticate) (0|1)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100476 UPDATE_SUBSCR_HELP
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100477 UPDATE_SUBSCR_INSERT_HELP
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100478 "Authorize the subscriber to attach\n"
479 "New option value\n")
480{
481 const char *imsi = argv[0];
Jacob Erlbeck2e5e94c2014-12-08 15:26:47 +0100482 const char *option = argv[1];
483 const char *value = argv[2];
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
493 if (!strcmp(option, "authorized"))
494 subscr->authorized = atoi(value);
Jacob Erlbeck2e5e94c2014-12-08 15:26:47 +0100495 else
496 subscr->sgsn_data->authenticate = atoi(value);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100497
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100498 subscr_put(subscr);
499
500 return CMD_SUCCESS;
501}
502
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100503DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
504 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
505 UPDATE_SUBSCR_HELP
506 UPDATE_SUBSCR_INSERT_HELP
507 "Update authentication triplet\n"
508 "Triplet index\n"
509 "Set SRES value\nSRES value (4 byte) in hex\n"
510 "Set RAND value\nRAND value (16 byte) in hex\n"
511 "Set Kc value\nKc value (8 byte) in hex\n")
512{
513 const char *imsi = argv[0];
514 const int cksn = atoi(argv[1]) - 1;
515 const char *sres_str = argv[2];
516 const char *rand_str = argv[3];
517 const char *kc_str = argv[4];
518 struct gsm_auth_tuple at = {0,};
519
520 struct gsm_subscriber *subscr;
521
522 subscr = gprs_subscr_get_or_create(imsi);
523 if (!subscr) {
524 vty_out(vty, "%% unable get subscriber record for %s\n", imsi);
525 return CMD_WARNING;
526 }
527
528 OSMO_ASSERT(subscr->sgsn_data);
529
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100530 if (osmo_hexparse(sres_str, &at.sres[0], sizeof(at.sres)) < 0) {
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100531 vty_out(vty, "%% invalid SRES value '%s'\n", sres_str);
532 goto failed;
533 }
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100534 if (osmo_hexparse(rand_str, &at.rand[0], sizeof(at.rand)) < 0) {
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100535 vty_out(vty, "%% invalid RAND value '%s'\n", rand_str);
536 goto failed;
537 }
Jacob Erlbeck17fb3d42015-01-05 09:43:51 +0100538 if (osmo_hexparse(kc_str, &at.kc[0], sizeof(at.kc)) < 0) {
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100539 vty_out(vty, "%% invalid Kc value '%s'\n", kc_str);
540 goto failed;
541 }
542 at.key_seq = cksn;
543
544 subscr->sgsn_data->auth_triplets[cksn] = at;
545 subscr->sgsn_data->auth_triplets_updated = 1;
546
547 subscr_put(subscr);
548
549 return CMD_SUCCESS;
550
551failed:
552 subscr_put(subscr);
553 return CMD_SUCCESS;
554}
555
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100556DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
557 UPDATE_SUBSCR_STR "cancel",
558 UPDATE_SUBSCR_HELP
559 "Cancel (remove) subscriber record\n")
560{
561 const char *imsi = argv[0];
562
563 struct gsm_subscriber *subscr;
564
565 subscr = gprs_subscr_get_by_imsi(imsi);
566 if (!subscr) {
567 vty_out(vty, "%% no subscriber record for %s\n", imsi);
568 return CMD_WARNING;
569 }
570
571 gprs_subscr_put_and_cancel(subscr);
572
573 return CMD_SUCCESS;
574}
575
576DEFUN(update_subscr_commit, update_subscr_commit_cmd,
577 UPDATE_SUBSCR_STR "commit",
578 UPDATE_SUBSCR_HELP
579 "Apply the changes made by the insert commands\n")
580{
581 const char *imsi = argv[0];
582
583 struct gsm_subscriber *subscr;
584
585 subscr = gprs_subscr_get_by_imsi(imsi);
586 if (!subscr) {
587 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
588 return CMD_WARNING;
589 }
590
591 gprs_subscr_update(subscr);
592
593 subscr_put(subscr);
594
595 return CMD_SUCCESS;
596}
597
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100598#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
599 "unknown-subscriber|roaming-not-allowed"
600
601#define UL_ERR_HELP \
602 "Force error code SystemFailure\n" \
603 "Force error code DataMissing\n" \
604 "Force error code UnexpectedDataValue\n" \
605 "Force error code UnknownSubscriber\n" \
606 "Force error code RoamingNotAllowed\n"
607
608DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
609 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
610 UPDATE_SUBSCR_HELP
611 "Complete the update location procedure\n"
612 "The update location request succeeded\n"
613 UL_ERR_HELP)
614{
615 const char *imsi = argv[0];
616 const char *ret_code_str = argv[1];
617
618 struct gsm_subscriber *subscr;
619
620 subscr = gprs_subscr_get_by_imsi(imsi);
621 if (!subscr) {
622 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
623 return CMD_WARNING;
624 }
625 if (strcmp(ret_code_str, "ok") == 0)
626 subscr->authorized = 1;
627 else
628 subscr->authorized = 0;
629
630 gprs_subscr_update(subscr);
631
632 subscr_put(subscr);
633
634 return CMD_SUCCESS;
635}
636
637DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
638 UPDATE_SUBSCR_STR "update-auth-info",
639 UPDATE_SUBSCR_HELP
640 "Complete the send authentication info procedure\n")
641{
642 const char *imsi = argv[0];
643
644 struct gsm_subscriber *subscr;
645
646 subscr = gprs_subscr_get_by_imsi(imsi);
647 if (!subscr) {
648 vty_out(vty, "%% unable to get subscriber record for %s\n", imsi);
649 return CMD_WARNING;
650 }
651
652 gprs_subscr_update_auth_info(subscr);
653
654 subscr_put(subscr);
655
656 return CMD_SUCCESS;
657}
658
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100659DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
660 "gsup remote-ip A.B.C.D",
661 "GSUP Parameters\n"
662 "Set the IP address of the remote GSUP server\n"
663 "IPv4 Address\n")
664{
665 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
666
667 return CMD_SUCCESS;
668}
669
670DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
671 "gsup remote-port <0-65535>",
672 "GSUP Parameters\n"
673 "Set the TCP port of the remote GSUP server\n"
674 "Remote TCP port\n")
675{
676 g_cfg->gsup_server_port = atoi(argv[0]);
677
678 return CMD_SUCCESS;
679}
680
681
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100682
Harald Welte288be162010-05-01 16:48:27 +0200683int sgsn_vty_init(void)
684{
Harald Welted193cb32010-05-17 22:58:03 +0200685 install_element_ve(&show_sgsn_cmd);
686 //install_element_ve(&show_mmctx_tlli_cmd);
687 install_element_ve(&show_mmctx_imsi_cmd);
688 install_element_ve(&show_mmctx_all_cmd);
689 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100690 install_element_ve(&show_subscr_cache_cmd);
691
692 install_element(ENABLE_NODE, &update_subscr_insert_cmd);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100693 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100694 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
695 install_element(ENABLE_NODE, &update_subscr_commit_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100696 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
697 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Harald Welte288be162010-05-01 16:48:27 +0200698
699 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
700 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeck36722e12013-10-29 09:30:30 +0100701 vty_install_default(SGSN_NODE);
Harald Weltee300d002010-06-02 12:41:34 +0200702 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +0200703 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
704 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
705 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +0100706 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +0100707 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100708 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
709 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Harald Welte288be162010-05-01 16:48:27 +0200710
711 return 0;
712}
713
714int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
715{
716 int rc;
717
718 g_cfg = cfg;
Harald Welte7f6da482013-03-19 11:00:13 +0100719
Harald Weltedcccb182010-05-16 20:52:23 +0200720 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +0200721 if (rc < 0) {
722 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
723 return rc;
724 }
725
726 return 0;
727}