blob: e6dc68d9511f4b494413a373dbd1318608073a5a [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
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02004 * (C) 2015 by Holger Hans Peter Freyther
Harald Welte288be162010-05-01 16:48:27 +02005 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01008 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
Harald Welte288be162010-05-01 16:48:27 +020010 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010015 * GNU Affero General Public License for more details.
Harald Welte288be162010-05-01 16:48:27 +020016 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte288be162010-05-01 16:48:27 +020019 *
20 */
21
Harald Welte288be162010-05-01 16:48:27 +020022#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
Jacob Erlbeck207f4a52014-11-11 14:01:48 +010025#include <time.h>
Harald Welte288be162010-05-01 16:48:27 +020026
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010027#include <osmocom/core/talloc.h>
28#include <osmocom/core/utils.h>
29#include <osmocom/core/rate_ctr.h>
Harald Welte53373bc2016-04-20 17:11:43 +020030#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
Harald Welte288be162010-05-01 16:48:27 +020031
32#include <openbsc/debug.h>
33#include <openbsc/sgsn.h>
Harald Welteea34a4e2012-06-16 14:59:56 +080034#include <osmocom/gprs/gprs_ns.h>
Harald Welted193cb32010-05-17 22:58:03 +020035#include <openbsc/gprs_sgsn.h>
Harald Welte62ab20c2010-05-14 18:59:17 +020036#include <openbsc/vty.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010037#include <openbsc/gprs_gsup_client.h>
Harald Welte288be162010-05-01 16:48:27 +020038
Harald Welte4b037e42010-05-19 19:45:32 +020039#include <osmocom/vty/command.h>
40#include <osmocom/vty/vty.h>
Pablo Neira Ayuso6110a3f2011-03-28 19:35:00 +020041#include <osmocom/vty/misc.h>
Max93408ae2016-06-28 14:10:16 +020042#include <osmocom/crypt/gprs_cipher.h>
Jacob Erlbeck80547992014-12-19 19:19:46 +010043#include <osmocom/abis/ipa.h>
44
Harald Welted193cb32010-05-17 22:58:03 +020045#include <pdp.h>
46
Harald Welte288be162010-05-01 16:48:27 +020047static struct sgsn_config *g_cfg = NULL;
48
Jacob Erlbeck106f5472014-11-04 10:08:37 +010049const struct value_string sgsn_auth_pol_strs[] = {
50 { SGSN_AUTH_POLICY_OPEN, "accept-all" },
51 { SGSN_AUTH_POLICY_CLOSED, "closed" },
52 { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" },
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +010053 { SGSN_AUTH_POLICY_REMOTE, "remote" },
Jacob Erlbeck106f5472014-11-04 10:08:37 +010054 { 0, NULL }
55};
56
Harald Welte94508822015-08-15 19:08:21 +020057/* Section 11.2.2 / Table 11.3a GPRS Mobility management timers – MS side */
58#define GSM0408_T3312_SECS (10*60) /* periodic RAU interval, default 54min */
59
60/* Section 11.2.2 / Table 11.4 MM timers netwokr side */
61#define GSM0408_T3322_SECS 6 /* DETACH_REQ -> DETACH_ACC */
62#define GSM0408_T3350_SECS 6 /* waiting for ATT/RAU/TMSI COMPL */
63#define GSM0408_T3360_SECS 6 /* waiting for AUTH/CIPH RESP */
64#define GSM0408_T3370_SECS 6 /* waiting for ID RESP */
65
66/* Section 11.2.2 / Table 11.4a MM timers netwokr side */
67#define GSM0408_T3313_SECS 30 /* waiting for paging response */
68#define GSM0408_T3314_SECS 44 /* force to STBY on expiry, Ready timer */
69#define GSM0408_T3316_SECS 44
70
71/* Section 11.3 / Table 11.2d Timers of Session Management - network side */
72#define GSM0408_T3385_SECS 8 /* wait for ACT PDP CTX REQ */
73#define GSM0408_T3386_SECS 8 /* wait for MODIFY PDP CTX ACK */
74#define GSM0408_T3395_SECS 8 /* wait for DEACT PDP CTX ACK */
75#define GSM0408_T3397_SECS 8 /* wait for DEACT AA PDP CTX ACK */
76
77#define DECLARE_TIMER(number, doc) \
78 DEFUN(cfg_sgsn_T##number, \
79 cfg_sgsn_T##number##_cmd, \
80 "timer t" #number " <0-65535>", \
81 "Configure GPRS Timers\n" \
Holger Hans Peter Freytherfe60cfb2015-11-02 12:55:07 +010082 doc "\nTimer Value in seconds\n") \
Harald Welte94508822015-08-15 19:08:21 +020083{ \
84 int value = atoi(argv[0]); \
85 \
86 if (value < 0 || value > 65535) { \
87 vty_out(vty, "Timer value %s out of range.%s", \
88 argv[0], VTY_NEWLINE); \
89 return CMD_WARNING; \
90 } \
91 \
92 g_cfg->timers.T##number = value; \
93 return CMD_SUCCESS; \
94}
95
96DECLARE_TIMER(3312, "Periodic RA Update timer (s)")
Neels Hofmeyr65482c92015-10-19 14:37:12 +020097DECLARE_TIMER(3322, "Detach request -> accept timer (s)")
Harald Welte94508822015-08-15 19:08:21 +020098DECLARE_TIMER(3350, "Waiting for ATT/RAU/TMSI_COMPL timer (s)")
99DECLARE_TIMER(3360, "Waiting for AUTH/CIPH response timer (s)")
100DECLARE_TIMER(3370, "Waiting for IDENTITY response timer (s)")
101
102DECLARE_TIMER(3313, "Waiting for paging response timer (s)")
103DECLARE_TIMER(3314, "Force to STANDBY on expiry timer (s)")
Holger Hans Peter Freytherfe60cfb2015-11-02 12:55:07 +0100104DECLARE_TIMER(3316, "AA-Ready timer (s)")
Harald Welte94508822015-08-15 19:08:21 +0200105
106DECLARE_TIMER(3385, "Wait for ACT PDP CTX REQ timer (s)")
107DECLARE_TIMER(3386, "Wait for MODIFY PDP CTX ACK timer (s)")
108DECLARE_TIMER(3395, "Wait for DEACT PDP CTX ACK timer (s)")
109DECLARE_TIMER(3397, "Wait for DEACT AA PDP CTX ACK timer (s)")
110
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100111
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200112#define GSM48_MAX_APN_LEN 102 /* 10.5.6.1 */
Neels Hofmeyr30f7bcb2015-11-08 20:34:47 +0100113/* TODO: consolidate with gprs_apn_to_str(). */
114/** Copy apn to a static buffer, replacing the length octets in apn_enc with '.'
115 * and terminating with a '\0'. Return the static buffer.
116 * len: the length of the encoded APN (which has no terminating zero).
117 */
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200118static char *gprs_apn2str(uint8_t *apn, unsigned int len)
119{
120 static char apnbuf[GSM48_MAX_APN_LEN+1];
Holger Hans Peter Freyther80e03652013-07-04 18:44:16 +0200121 unsigned int i = 0;
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200122
123 if (!apn)
124 return "";
125
126 if (len > sizeof(apnbuf)-1)
127 len = sizeof(apnbuf)-1;
128
129 memcpy(apnbuf, apn, len);
130 apnbuf[len] = '\0';
131
132 /* replace the domain name step sizes with dots */
133 while (i < len) {
134 unsigned int step = apnbuf[i];
135 apnbuf[i] = '.';
136 i += step+1;
137 }
138
139 return apnbuf+1;
140}
141
Holger Hans Peter Freythera2730302014-03-23 18:08:26 +0100142char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200143{
144 static char str[INET6_ADDRSTRLEN + 10];
145
146 if (!pdpa || len < 2)
147 return "none";
148
149 switch (pdpa[0] & 0x0f) {
150 case PDP_TYPE_ORG_IETF:
151 switch (pdpa[1]) {
152 case PDP_TYPE_N_IETF_IPv4:
153 if (len < 2 + 4)
154 break;
155 strcpy(str, "IPv4 ");
156 inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
157 return str;
158 case PDP_TYPE_N_IETF_IPv6:
159 if (len < 2 + 8)
160 break;
161 strcpy(str, "IPv6 ");
162 inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
163 return str;
164 default:
165 break;
166 }
167 break;
168 case PDP_TYPE_ORG_ETSI:
169 if (pdpa[1] == PDP_TYPE_N_ETSI_PPP)
170 return "PPP";
171 break;
172 default:
173 break;
174 }
175
176 return "invalid";
177}
178
Harald Welte288be162010-05-01 16:48:27 +0200179static struct cmd_node sgsn_node = {
180 SGSN_NODE,
Harald Welte570ce242012-08-17 13:16:10 +0200181 "%s(config-sgsn)# ",
Harald Welte288be162010-05-01 16:48:27 +0200182 1,
183};
184
185static int config_write_sgsn(struct vty *vty)
186{
Harald Welte77289c22010-05-18 14:32:29 +0200187 struct sgsn_ggsn_ctx *gctx;
Harald Welte7f6da482013-03-19 11:00:13 +0100188 struct imsi_acl_entry *acl;
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100189 struct apn_ctx *actx;
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800190 struct ares_addr_node *server;
Harald Welte288be162010-05-01 16:48:27 +0200191
192 vty_out(vty, "sgsn%s", VTY_NEWLINE);
193
Harald Weltee300d002010-06-02 12:41:34 +0200194 vty_out(vty, " gtp local-ip %s%s",
195 inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
196
Harald Welted193cb32010-05-17 22:58:03 +0200197 llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800198 if (gctx->id == UINT32_MAX)
199 continue;
200
Harald Welteff3bde82010-05-19 15:09:09 +0200201 vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200202 inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
Harald Welteff3bde82010-05-19 15:09:09 +0200203 vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
Harald Welted193cb32010-05-17 22:58:03 +0200204 gctx->gtp_version, VTY_NEWLINE);
Harald Welte288be162010-05-01 16:48:27 +0200205 }
206
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800207 if (sgsn->cfg.dynamic_lookup)
208 vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE);
209
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800210 for (server = sgsn->ares_servers; server; server = server->next)
211 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
212
Max93408ae2016-06-28 14:10:16 +0200213 if (g_cfg->cipher != GPRS_ALGO_GEA0)
214 vty_out(vty, " encryption %s%s",
215 get_value_string(gprs_cipher_names, g_cfg->cipher),
216 VTY_NEWLINE);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100217 if (g_cfg->gsup_server_addr.sin_addr.s_addr)
218 vty_out(vty, " gsup remote-ip %s%s",
219 inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
220 if (g_cfg->gsup_server_port)
221 vty_out(vty, " gsup remote-port %d%s",
222 g_cfg->gsup_server_port, VTY_NEWLINE);
Max176b62a2016-07-04 11:09:07 +0200223 vty_out(vty, " auth-policy %s%s",
224 get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
225 VTY_NEWLINE);
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200226
227 vty_out(vty, " gsup oap-id %d%s",
228 (int)g_cfg->oap.client_id, VTY_NEWLINE);
229 if (g_cfg->oap.secret_k_present != 0)
230 vty_out(vty, " gsup oap-k %s%s",
231 osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)),
232 VTY_NEWLINE);
233 if (g_cfg->oap.secret_opc_present != 0)
234 vty_out(vty, " gsup oap-opc %s%s",
235 osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)),
236 VTY_NEWLINE);
237
Harald Welte7f6da482013-03-19 11:00:13 +0100238 llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
239 vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
240
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100241 if (llist_empty(&sgsn_apn_ctxts))
242 vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
243 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
244 if (strlen(actx->imsi_prefix) > 0)
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200245 vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100246 actx->name, actx->imsi_prefix, actx->ggsn->id,
247 VTY_NEWLINE);
248 else
Holger Hans Peter Freytherb7ae0b32015-05-29 15:11:55 +0200249 vty_out(vty, " apn %s ggsn %u%s", actx->name,
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100250 actx->ggsn->id, VTY_NEWLINE);
251 }
252
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +0200253 if (g_cfg->cdr.filename)
254 vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE);
255 else
256 vty_out(vty, " no cdr filename%s", VTY_NEWLINE);
257 vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
258
Harald Welte94508822015-08-15 19:08:21 +0200259 vty_out(vty, " timer t3312 %d%s", g_cfg->timers.T3312, VTY_NEWLINE);
260 vty_out(vty, " timer t3322 %d%s", g_cfg->timers.T3322, VTY_NEWLINE);
261 vty_out(vty, " timer t3350 %d%s", g_cfg->timers.T3350, VTY_NEWLINE);
262 vty_out(vty, " timer t3360 %d%s", g_cfg->timers.T3360, VTY_NEWLINE);
263 vty_out(vty, " timer t3370 %d%s", g_cfg->timers.T3370, VTY_NEWLINE);
264 vty_out(vty, " timer t3313 %d%s", g_cfg->timers.T3313, VTY_NEWLINE);
265 vty_out(vty, " timer t3314 %d%s", g_cfg->timers.T3314, VTY_NEWLINE);
266 vty_out(vty, " timer t3316 %d%s", g_cfg->timers.T3316, VTY_NEWLINE);
267 vty_out(vty, " timer t3385 %d%s", g_cfg->timers.T3385, VTY_NEWLINE);
268 vty_out(vty, " timer t3386 %d%s", g_cfg->timers.T3386, VTY_NEWLINE);
269 vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE);
270 vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE);
271
Harald Welte288be162010-05-01 16:48:27 +0200272 return CMD_SUCCESS;
273}
274
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100275#define SGSN_STR "Configure the SGSN\n"
276#define GGSN_STR "Configure the GGSN information\n"
Harald Weltee300d002010-06-02 12:41:34 +0200277
278DEFUN(cfg_sgsn, cfg_sgsn_cmd,
279 "sgsn",
280 SGSN_STR)
Harald Welte288be162010-05-01 16:48:27 +0200281{
282 vty->node = SGSN_NODE;
283 return CMD_SUCCESS;
284}
285
Harald Weltee300d002010-06-02 12:41:34 +0200286DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
287 "gtp local-ip A.B.C.D",
288 "GTP Parameters\n"
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100289 "Set the IP address for the local GTP bind\n"
290 "IPv4 Address\n")
Harald Weltee300d002010-06-02 12:41:34 +0200291{
292 inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
293
294 return CMD_SUCCESS;
295}
296
Harald Welted193cb32010-05-17 22:58:03 +0200297DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
298 "ggsn <0-255> remote-ip A.B.C.D",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100299 GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n")
Harald Welted193cb32010-05-17 22:58:03 +0200300{
301 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200302 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welte288be162010-05-01 16:48:27 +0200303
Harald Welted193cb32010-05-17 22:58:03 +0200304 inet_aton(argv[1], &ggc->remote_addr);
Harald Welte288be162010-05-01 16:48:27 +0200305
Harald Welted193cb32010-05-17 22:58:03 +0200306 return CMD_SUCCESS;
307}
308
309#if 0
310DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
311 "ggsn <0-255> remote-port <0-65535>",
312 "")
313{
314 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200315 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200316 uint16_t port = atoi(argv[1]);
317
318}
319#endif
320
321DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
322 "ggsn <0-255> gtp-version (0|1)",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100323 GGSN_STR "GGSN Number\n" "GTP Version\n"
324 "Version 0\n" "Version 1\n")
Harald Welted193cb32010-05-17 22:58:03 +0200325{
326 uint32_t id = atoi(argv[0]);
Harald Welte77289c22010-05-18 14:32:29 +0200327 struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
Harald Welted193cb32010-05-17 22:58:03 +0200328
329 if (atoi(argv[1]))
330 ggc->gtp_version = 1;
331 else
332 ggc->gtp_version = 0;
333
334 return CMD_SUCCESS;
335}
336
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +0800337DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd,
338 "ggsn dynamic",
339 GGSN_STR "Enable dynamic GRX based look-up (requires restart)\n")
340{
341 sgsn->cfg.dynamic_lookup = 1;
342 return CMD_SUCCESS;
343}
344
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +0800345DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
346 "grx-dns-add A.B.C.D",
347 "Add DNS server\nIPv4 address\n")
348{
349 struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node);
350 node->family = AF_INET;
351 inet_aton(argv[0], &node->addr.addr4);
352
353 node->next = sgsn->ares_servers;
354 sgsn->ares_servers = node;
355 return CMD_SUCCESS;
356}
357
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100358#define APN_STR "Configure the information per APN\n"
359#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n"
360
361static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
362 const char *imsi_prefix, int ggsn_id)
363{
364 struct apn_ctx *actx;
365 struct sgsn_ggsn_ctx *ggsn;
366
367 ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
368 if (ggsn == NULL) {
369 vty_out(vty, "%% a GGSN with id %d has not been defined%s",
370 ggsn_id, VTY_NEWLINE);
371 return CMD_WARNING;
372 }
373
374 actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix);
375 if (!actx) {
376 vty_out(vty, "%% unable to create APN context for %s/%s%s",
377 apn_str, imsi_prefix, VTY_NEWLINE);
378 return CMD_WARNING;
379 }
380
381 actx->ggsn = ggsn;
382
383 return CMD_SUCCESS;
384}
385
Harald Welted193cb32010-05-17 22:58:03 +0200386DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
387 "apn APNAME ggsn <0-255>",
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100388 APN_STR APN_GW_STR
389 "Select the GGSN to use when the APN gateway prefix matches\n"
390 "The GGSN id")
Harald Welted193cb32010-05-17 22:58:03 +0200391{
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100392
393 return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1]));
Harald Welted193cb32010-05-17 22:58:03 +0200394}
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +0100395
396DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
397 "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>",
398 APN_STR APN_GW_STR
399 "Restrict rule to a certain IMSI prefix\n"
400 "An IMSI prefix\n"
401 "Select the GGSN to use when APN gateway and IMSI prefix match\n"
402 "The GGSN id")
403{
404
405 return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
406}
Harald Welted193cb32010-05-17 22:58:03 +0200407
408const struct value_string gprs_mm_st_strs[] = {
409 { GMM_DEREGISTERED, "DEREGISTERED" },
410 { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
411 { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
Harald Weltebffeff82010-06-09 15:50:45 +0200412 { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
Harald Welted193cb32010-05-17 22:58:03 +0200413 { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
414 { 0, NULL }
415};
416
417static void vty_dump_pdp(struct vty *vty, const char *pfx,
418 struct sgsn_pdp_ctx *pdp)
419{
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200420 const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)";
Harald Welted193cb32010-05-17 22:58:03 +0200421 vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
Jacob Erlbeck99985b52014-10-13 10:32:00 +0200422 pfx, imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
Harald Weltec5d4a0c2010-07-02 22:47:59 +0200423 vty_out(vty, "%s APN: %s%s", pfx,
424 gprs_apn2str(pdp->lib->apn_use.v, pdp->lib->apn_use.l),
425 VTY_NEWLINE);
426 vty_out(vty, "%s PDP Address: %s%s", pfx,
427 gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
428 VTY_NEWLINE);
Harald Welteefbdee92010-06-10 00:20:12 +0200429 vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
Harald Welted193cb32010-05-17 22:58:03 +0200430}
431
432static void vty_dump_mmctx(struct vty *vty, const char *pfx,
433 struct sgsn_mm_ctx *mm, int pdp)
434{
435 vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
436 pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
Holger Hans Peter Freyther8ee13e22015-05-18 10:00:03 +0200437 vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
Harald Weltef97ee042015-12-25 19:12:21 +0100438 pfx, mm->msisdn, mm->gb.tlli, mm->hlr, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200439 vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, "
440 "Cell ID: %u%s", pfx,
441 get_value_string(gprs_mm_st_strs, mm->mm_state),
442 mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac,
Harald Weltef97ee042015-12-25 19:12:21 +0100443 mm->gb.cell_id, VTY_NEWLINE);
Harald Welted193cb32010-05-17 22:58:03 +0200444
Harald Welte8acd88f2010-05-18 10:57:45 +0200445 vty_out_rate_ctr_group(vty, " ", mm->ctrg);
446
Harald Welted193cb32010-05-17 22:58:03 +0200447 if (pdp) {
448 struct sgsn_pdp_ctx *pdp;
449
450 llist_for_each_entry(pdp, &mm->pdp_list, list)
451 vty_dump_pdp(vty, " ", pdp);
452 }
453}
454
455DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
456 SHOW_STR "Display information about the SGSN")
457{
Jacob Erlbeck80547992014-12-19 19:19:46 +0100458 if (sgsn->gsup_client) {
459 struct ipa_client_conn *link = sgsn->gsup_client->link;
460 vty_out(vty,
461 " Remote authorization: %sconnected to %s:%d via GSUP%s",
462 sgsn->gsup_client->is_connected ? "" : "not ",
463 link->addr, link->port,
464 VTY_NEWLINE);
465 }
Harald Welted193cb32010-05-17 22:58:03 +0200466 /* FIXME: statistics */
467 return CMD_SUCCESS;
468}
469
470#define MMCTX_STR "MM Context\n"
471#define INCLUDE_PDP_STR "Include PDP Context Information\n"
472
473#if 0
474DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
475 "show mm-context tlli HEX [pdp]",
476 SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
477{
478 uint32_t tlli;
479 struct sgsn_mm_ctx *mm;
480
481 tlli = strtoul(argv[0], NULL, 16);
482 mm = sgsn_mm_ctx_by_tlli(tlli);
483 if (!mm) {
484 vty_out(vty, "No MM context for TLLI %08x%s",
485 tlli, VTY_NEWLINE);
486 return CMD_WARNING;
487 }
488 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
489 return CMD_SUCCESS;
490}
491#endif
492
493DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
494 "show mm-context imsi IMSI [pdp]",
495 SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
496 INCLUDE_PDP_STR)
497{
498 struct sgsn_mm_ctx *mm;
499
500 mm = sgsn_mm_ctx_by_imsi(argv[0]);
501 if (!mm) {
502 vty_out(vty, "No MM context for IMSI %s%s",
503 argv[0], VTY_NEWLINE);
504 return CMD_WARNING;
505 }
506 vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
507 return CMD_SUCCESS;
508}
509
510DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
511 "show mm-context all [pdp]",
512 SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
513{
514 struct sgsn_mm_ctx *mm;
515
516 llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
517 vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
518
519 return CMD_SUCCESS;
520}
521
Harald Welted193cb32010-05-17 22:58:03 +0200522DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
523 "show pdp-context all",
Holger Hans Peter Freyther1491f2e2011-11-05 15:21:16 +0100524 SHOW_STR "Display information on PDP Context\n" "Show everything\n")
Harald Welted193cb32010-05-17 22:58:03 +0200525{
526 struct sgsn_pdp_ctx *pdp;
527
528 llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
529 vty_dump_pdp(vty, "", pdp);
530
531 return CMD_SUCCESS;
532}
Harald Welte288be162010-05-01 16:48:27 +0200533
Harald Welte7f6da482013-03-19 11:00:13 +0100534
535DEFUN(imsi_acl, cfg_imsi_acl_cmd,
536 "imsi-acl (add|del) IMSI",
537 "Access Control List of foreign IMSIs\n"
538 "Add IMSI to ACL\n"
539 "Remove IMSI from ACL\n"
540 "IMSI of subscriber\n")
541{
542 const char *op = argv[0];
543 const char *imsi = argv[1];
544 int rc;
545
546 if (!strcmp(op, "add"))
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200547 rc = sgsn_acl_add(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100548 else
Jacob Erlbeck3b5d4072014-10-24 15:11:03 +0200549 rc = sgsn_acl_del(imsi, g_cfg);
Harald Welte7f6da482013-03-19 11:00:13 +0100550
551 if (rc < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100552 vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE);
553
Harald Welte7f6da482013-03-19 11:00:13 +0100554 return CMD_WARNING;
555 }
556
557 return CMD_SUCCESS;
558}
559
Max93408ae2016-06-28 14:10:16 +0200560DEFUN(cfg_encrypt, cfg_encrypt_cmd,
561 "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
562 "Set encryption algorithm for SGSN\n"
563 "Use GEA0 (no encryption)\n"
564 "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
565{
566 if (!g_cfg->require_authentication) {
567 vty_out(vty, "%% unable to use encryption without "
568 "authentication: adjust auth-policy%s", VTY_NEWLINE);
569 return CMD_WARNING;
570 }
571
572 enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
573 if (!gprs_cipher_supported(c)) {
574 vty_out(vty, "%% cipher %s is unsupported in current version%s",
575 argv[0], VTY_NEWLINE);
576 return CMD_WARNING;
577 }
578
579 g_cfg->cipher = c;
580
581 return CMD_SUCCESS;
582}
583
Harald Welte3dfb5492013-03-19 11:48:54 +0100584DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100585 "auth-policy (accept-all|closed|acl-only|remote)",
Harald Welte3dfb5492013-03-19 11:48:54 +0100586 "Autorization Policy of SGSN\n"
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100587 "Accept all IMSIs (DANGEROUS)\n"
588 "Accept only home network subscribers or those in the ACL\n"
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100589 "Accept only subscribers in the ACL\n"
590 "Use remote subscription data only (HLR)\n")
Harald Welte3dfb5492013-03-19 11:48:54 +0100591{
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100592 int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
Jacob Erlbeckbe2c8d92014-11-12 10:18:09 +0100593 OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
Max176b62a2016-07-04 11:09:07 +0200594 if (val == SGSN_AUTH_POLICY_REMOTE) {
595 const char *err = "%% auth-policy remote requires";
596 if (!g_cfg->gsup_server_addr.sin_addr.s_addr) {
597 vty_out(vty, "%s 'gsup remote-ip'%s", err, VTY_NEWLINE);
598 return CMD_WARNING;
599 }
600 if (!g_cfg->gsup_server_port) {
601 vty_out(vty, "%s 'gsup remote-port'%s", err, VTY_NEWLINE);
602 return CMD_WARNING;
603 }
604 }
Jacob Erlbeck106f5472014-11-04 10:08:37 +0100605 g_cfg->auth_policy = val;
Jacob Erlbeck9d4f46c2014-12-17 13:20:08 +0100606 g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
Jacob Erlbeck771573c2014-12-19 18:08:48 +0100607 g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
Harald Welte3dfb5492013-03-19 11:48:54 +0100608
609 return CMD_SUCCESS;
610}
611
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100612/* Subscriber */
613#include <openbsc/gsm_subscriber.h>
614
615static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending)
616{
617 char expire_time[200];
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100618 struct gsm_auth_tuple *at;
619 int at_idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100620 struct sgsn_subscriber_pdp_data *pdp;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100621
622 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
623 subscr->authorized, VTY_NEWLINE);
624 if (strlen(subscr->name))
625 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
626 if (strlen(subscr->extension))
627 vty_out(vty, " Extension: %s%s", subscr->extension,
628 VTY_NEWLINE);
629 vty_out(vty, " LAC: %d/0x%x%s",
630 subscr->lac, subscr->lac, VTY_NEWLINE);
631 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
632 if (subscr->tmsi != GSM_RESERVED_TMSI)
633 vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
634 VTY_NEWLINE);
Holger Hans Peter Freytherf7b38262015-04-23 16:58:33 -0400635 if (subscr->sgsn_data->msisdn_len > 0)
636 vty_out(vty, " MSISDN (BCD): %s%s",
637 osmo_hexdump(subscr->sgsn_data->msisdn,
638 subscr->sgsn_data->msisdn_len),
639 VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100640
641 if (strlen(subscr->equipment.imei) > 0)
642 vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE);
643
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100644 for (at_idx = 0; at_idx < ARRAY_SIZE(subscr->sgsn_data->auth_triplets);
645 at_idx++) {
646 at = &subscr->sgsn_data->auth_triplets[at_idx];
647 if (at->key_seq == GSM_KEY_SEQ_INVAL)
648 continue;
649
650 vty_out(vty, " A3A8 tuple (used %d times): ",
651 at->use_count);
652 vty_out(vty, " seq # : %d, ",
653 at->key_seq);
654 vty_out(vty, " RAND : %s, ",
Harald Welte121e9a42016-04-20 13:13:19 +0200655 osmo_hexdump(at->vec.rand, sizeof(at->vec.rand)));
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100656 vty_out(vty, " SRES : %s, ",
Harald Welte121e9a42016-04-20 13:13:19 +0200657 osmo_hexdump(at->vec.sres, sizeof(at->vec.sres)));
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100658 vty_out(vty, " Kc : %s%s",
Harald Welte121e9a42016-04-20 13:13:19 +0200659 osmo_hexdump(at->vec.kc, sizeof(at->vec.kc)),
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100660 VTY_NEWLINE);
661 }
662
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100663 llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400664 vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s' QoS: %s%s",
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100665 pdp->context_id, pdp->pdp_type, pdp->apn_str,
Holger Hans Peter Freytherd05e0692015-04-23 16:59:04 -0400666 osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len),
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100667 VTY_NEWLINE);
668 }
669
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100670 /* print the expiration time of a subscriber */
671 if (subscr->expire_lu) {
672 strftime(expire_time, sizeof(expire_time),
673 "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
674 expire_time[sizeof(expire_time) - 1] = '\0';
675 vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
676 }
677
678 if (subscr->flags)
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100679 vty_out(vty, " Flags: %s%s%s%s%s%s",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100680 subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ?
681 "FIRST_CONTACT " : "",
682 subscr->flags & GPRS_SUBSCRIBER_CANCELLED ?
683 "CANCELLED " : "",
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100684 subscr->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
685 "UPDATE_LOCATION_PENDING " : "",
686 subscr->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
687 "AUTH_INFO_PENDING " : "",
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100688 subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
689 "ENABLE_PURGE " : "",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100690 VTY_NEWLINE);
691
692 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
693}
694
695DEFUN(show_subscr_cache,
696 show_subscr_cache_cmd,
697 "show subscriber cache",
698 SHOW_STR "Show information about subscribers\n"
699 "Display contents of subscriber cache\n")
700{
701 struct gsm_subscriber *subscr;
702
703 llist_for_each_entry(subscr, &active_subscribers, entry) {
704 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
705 subscr_dump_full_vty(vty, subscr, 0);
706 }
707
708 return CMD_SUCCESS;
709}
710
711#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
712#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
713 "Use the IMSI to select the subscriber\n" \
714 "The IMSI\n"
715
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100716#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
717
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100718DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
719 UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC",
720 UPDATE_SUBSCR_HELP
721 UPDATE_SUBSCR_INSERT_HELP
722 "Update authentication triplet\n"
723 "Triplet index\n"
724 "Set SRES value\nSRES value (4 byte) in hex\n"
725 "Set RAND value\nRAND value (16 byte) in hex\n"
726 "Set Kc value\nKc value (8 byte) in hex\n")
727{
728 const char *imsi = argv[0];
729 const int cksn = atoi(argv[1]) - 1;
730 const char *sres_str = argv[2];
731 const char *rand_str = argv[3];
732 const char *kc_str = argv[4];
733 struct gsm_auth_tuple at = {0,};
734
735 struct gsm_subscriber *subscr;
736
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100737 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100738 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100739 vty_out(vty, "%% unable get subscriber record for %s%s",
740 imsi, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100741 return CMD_WARNING;
742 }
743
744 OSMO_ASSERT(subscr->sgsn_data);
745
Harald Welte121e9a42016-04-20 13:13:19 +0200746 if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100747 vty_out(vty, "%% invalid SRES value '%s'%s",
748 sres_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100749 goto failed;
750 }
Harald Welte121e9a42016-04-20 13:13:19 +0200751 if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100752 vty_out(vty, "%% invalid RAND value '%s'%s",
753 rand_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100754 goto failed;
755 }
Harald Welte121e9a42016-04-20 13:13:19 +0200756 if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100757 vty_out(vty, "%% invalid Kc value '%s'%s",
758 kc_str, VTY_NEWLINE);
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100759 goto failed;
760 }
761 at.key_seq = cksn;
762
763 subscr->sgsn_data->auth_triplets[cksn] = at;
764 subscr->sgsn_data->auth_triplets_updated = 1;
765
766 subscr_put(subscr);
767
768 return CMD_SUCCESS;
769
770failed:
771 subscr_put(subscr);
772 return CMD_SUCCESS;
773}
774
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100775DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100776 UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100777 UPDATE_SUBSCR_HELP
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100778 "Cancel (remove) subscriber record\n"
779 "The MS moved to another SGSN\n"
780 "The subscription is no longer valid\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100781{
782 const char *imsi = argv[0];
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100783 const char *cancel_type = argv[1];
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100784
785 struct gsm_subscriber *subscr;
786
787 subscr = gprs_subscr_get_by_imsi(imsi);
788 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100789 vty_out(vty, "%% no subscriber record for %s%s",
790 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100791 return CMD_WARNING;
792 }
793
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100794 if (strcmp(cancel_type, "update-procedure") == 0)
795 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
796 else
797 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
798
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100799 gprs_subscr_cancel(subscr);
800 subscr_put(subscr);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100801
802 return CMD_SUCCESS;
803}
804
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100805DEFUN(update_subscr_create, update_subscr_create_cmd,
806 UPDATE_SUBSCR_STR "create",
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100807 UPDATE_SUBSCR_HELP
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100808 "Create a subscriber entry\n")
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100809{
810 const char *imsi = argv[0];
811
812 struct gsm_subscriber *subscr;
813
814 subscr = gprs_subscr_get_by_imsi(imsi);
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100815 if (subscr) {
816 vty_out(vty, "%% subscriber record already exists for %s%s",
817 imsi, VTY_NEWLINE);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100818 return CMD_WARNING;
819 }
820
Jacob Erlbeckd9193432015-01-19 14:11:46 +0100821 subscr = gprs_subscr_get_or_create(imsi);
822 subscr->keep_in_ram = 1;
Jacob Erlbeck207f4a52014-11-11 14:01:48 +0100823 subscr_put(subscr);
824
825 return CMD_SUCCESS;
826}
827
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100828DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
829 UPDATE_SUBSCR_STR "destroy",
830 UPDATE_SUBSCR_HELP
831 "Destroy a subscriber entry\n")
832{
833 const char *imsi = argv[0];
834
835 struct gsm_subscriber *subscr;
836
837 subscr = gprs_subscr_get_by_imsi(imsi);
838 if (!subscr) {
839 vty_out(vty, "%% subscriber record does not exist for %s%s",
840 imsi, VTY_NEWLINE);
841 return CMD_WARNING;
842 }
843
844 subscr->keep_in_ram = 0;
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100845 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecke988ae42015-01-27 12:41:19 +0100846 gprs_subscr_cancel(subscr);
847 if (subscr->use_count > 1)
848 vty_out(vty, "%% subscriber is still in use%s",
849 VTY_NEWLINE);
850 subscr_put(subscr);
851
852 return CMD_SUCCESS;
853}
854
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100855#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \
856 "unknown-subscriber|roaming-not-allowed"
857
858#define UL_ERR_HELP \
859 "Force error code SystemFailure\n" \
860 "Force error code DataMissing\n" \
861 "Force error code UnexpectedDataValue\n" \
862 "Force error code UnknownSubscriber\n" \
863 "Force error code RoamingNotAllowed\n"
864
865DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
866 UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
867 UPDATE_SUBSCR_HELP
868 "Complete the update location procedure\n"
869 "The update location request succeeded\n"
870 UL_ERR_HELP)
871{
872 const char *imsi = argv[0];
873 const char *ret_code_str = argv[1];
874
875 struct gsm_subscriber *subscr;
876
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100877 const struct value_string cause_mapping[] = {
878 { GMM_CAUSE_NET_FAIL, "system-failure" },
879 { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
880 { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
881 { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
882 { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
883 { 0, NULL }
884 };
885
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100886 subscr = gprs_subscr_get_by_imsi(imsi);
887 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100888 vty_out(vty, "%% unable to get subscriber record for %s%s",
889 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100890 return CMD_WARNING;
891 }
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100892
893 if (strcmp(ret_code_str, "ok") == 0) {
894 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100895 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100896 } else {
897 subscr->sgsn_data->error_cause =
898 get_string_value(cause_mapping, ret_code_str);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100899 subscr->authorized = 0;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100900 }
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100901
902 gprs_subscr_update(subscr);
903
904 subscr_put(subscr);
905
906 return CMD_SUCCESS;
907}
908
909DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
910 UPDATE_SUBSCR_STR "update-auth-info",
911 UPDATE_SUBSCR_HELP
912 "Complete the send authentication info procedure\n")
913{
914 const char *imsi = argv[0];
915
916 struct gsm_subscriber *subscr;
917
918 subscr = gprs_subscr_get_by_imsi(imsi);
919 if (!subscr) {
Jacob Erlbeck15cc8c82015-01-19 14:29:43 +0100920 vty_out(vty, "%% unable to get subscriber record for %s%s",
921 imsi, VTY_NEWLINE);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100922 return CMD_WARNING;
923 }
924
925 gprs_subscr_update_auth_info(subscr);
926
927 subscr_put(subscr);
928
929 return CMD_SUCCESS;
930}
931
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100932DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
933 "gsup remote-ip A.B.C.D",
934 "GSUP Parameters\n"
935 "Set the IP address of the remote GSUP server\n"
936 "IPv4 Address\n")
937{
938 inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
939
940 return CMD_SUCCESS;
941}
942
943DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
944 "gsup remote-port <0-65535>",
945 "GSUP Parameters\n"
946 "Set the TCP port of the remote GSUP server\n"
947 "Remote TCP port\n")
948{
949 g_cfg->gsup_server_port = atoi(argv[0]);
950
951 return CMD_SUCCESS;
952}
953
Neels Hofmeyr568a7272015-10-12 11:57:38 +0200954DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd,
955 "gsup oap-id <0-65535>",
956 "GSUP Parameters\n"
957 "Set the SGSN's OAP client ID\nOAP client ID (0 == disabled)\n")
958{
959 /* VTY ensures range */
960 g_cfg->oap.client_id = (uint16_t)atoi(argv[0]);
961 return CMD_SUCCESS;
962}
963
964DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd,
965 "gsup oap-k K",
966 "GSUP Parameters\n"
967 "Set the OAP shared secret K\nK value (16 byte) hex\n")
968{
969 const char *k = argv[0];
970
971 g_cfg->oap.secret_k_present = 0;
972
973 if ((!k) || (strlen(k) == 0))
974 goto disable;
975
976 int k_len = osmo_hexparse(k,
977 g_cfg->oap.secret_k,
978 sizeof(g_cfg->oap.secret_k));
979 if (k_len != 16) {
980 vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s",
981 k_len, VTY_NEWLINE);
982 goto disable;
983 }
984
985 g_cfg->oap.secret_k_present = 1;
986 return CMD_SUCCESS;
987
988disable:
989 if (g_cfg->oap.client_id > 0) {
990 vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s",
991 VTY_NEWLINE);
992 return CMD_WARNING;
993 }
994 return CMD_SUCCESS;
995}
996
997DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd,
998 "gsup oap-opc OPC",
999 "GSUP Parameters\n"
1000 "Set the OAP shared secret OPC\nOPC value (16 byte) hex\n")
1001{
1002 const char *opc = argv[0];
1003
1004 g_cfg->oap.secret_opc_present = 0;
1005
1006 if ((!opc) || (strlen(opc) == 0))
1007 goto disable;
1008
1009 int opc_len = osmo_hexparse(opc,
1010 g_cfg->oap.secret_opc,
1011 sizeof(g_cfg->oap.secret_opc));
1012 if (opc_len != 16) {
1013 vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s",
1014 opc_len, VTY_NEWLINE);
1015 goto disable;
1016 }
1017
1018 g_cfg->oap.secret_opc_present = 1;
1019 return CMD_SUCCESS;
1020
1021disable:
1022 if (g_cfg->oap.client_id > 0) {
1023 vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s",
1024 VTY_NEWLINE);
1025 return CMD_WARNING;
1026 }
1027 return CMD_SUCCESS;
1028}
1029
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001030DEFUN(cfg_apn_name, cfg_apn_name_cmd,
1031 "access-point-name NAME",
1032 "Configure a global list of allowed APNs\n"
1033 "Add this NAME to the list\n")
1034{
1035 return add_apn_ggsn_mapping(vty, argv[0], "", 0);
1036}
1037
1038DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd,
1039 "no access-point-name NAME",
1040 NO_STR "Configure a global list of allowed APNs\n"
1041 "Remove entry with NAME\n")
1042{
1043 struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], "");
1044 if (!apn_ctx)
1045 return CMD_SUCCESS;
1046
1047 sgsn_apn_ctx_free(apn_ctx);
1048 return CMD_SUCCESS;
1049}
1050
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001051DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd,
1052 "cdr filename NAME",
1053 "CDR\nSet filename\nname\n")
1054{
1055 talloc_free(g_cfg->cdr.filename);
1056 g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]);
1057 return CMD_SUCCESS;
1058}
1059
1060DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd,
1061 "no cdr filename",
1062 NO_STR "CDR\nDisable CDR generation\n")
1063{
1064 talloc_free(g_cfg->cdr.filename);
1065 g_cfg->cdr.filename = NULL;
1066 return CMD_SUCCESS;
1067}
1068
1069DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd,
1070 "cdr interval <1-2147483647>",
1071 "CDR\nPDP periodic log interval\nSeconds\n")
1072{
1073 g_cfg->cdr.interval = atoi(argv[0]);
1074 return CMD_SUCCESS;
1075}
1076
Harald Welte288be162010-05-01 16:48:27 +02001077int sgsn_vty_init(void)
1078{
Harald Welted193cb32010-05-17 22:58:03 +02001079 install_element_ve(&show_sgsn_cmd);
1080 //install_element_ve(&show_mmctx_tlli_cmd);
1081 install_element_ve(&show_mmctx_imsi_cmd);
1082 install_element_ve(&show_mmctx_all_cmd);
1083 install_element_ve(&show_pdpctx_all_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001084 install_element_ve(&show_subscr_cache_cmd);
1085
Jacob Erlbeck7921ab12014-12-08 15:52:00 +01001086 install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
Jacob Erlbeckd9193432015-01-19 14:11:46 +01001087 install_element(ENABLE_NODE, &update_subscr_create_cmd);
Jacob Erlbecke988ae42015-01-27 12:41:19 +01001088 install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
Jacob Erlbeck207f4a52014-11-11 14:01:48 +01001089 install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +01001090 install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
1091 install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001092
1093 install_element(CONFIG_NODE, &cfg_sgsn_cmd);
1094 install_node(&sgsn_node, config_write_sgsn);
Jacob Erlbeck36722e12013-10-29 09:30:30 +01001095 vty_install_default(SGSN_NODE);
Harald Weltee300d002010-06-02 12:41:34 +02001096 install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
Harald Welted193cb32010-05-17 22:58:03 +02001097 install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
1098 //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
1099 install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
Harald Welte7f6da482013-03-19 11:00:13 +01001100 install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
Harald Welte3dfb5492013-03-19 11:48:54 +01001101 install_element(SGSN_NODE, &cfg_auth_policy_cmd);
Max93408ae2016-06-28 14:10:16 +02001102 install_element(SGSN_NODE, &cfg_encrypt_cmd);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +01001103 install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
1104 install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
Neels Hofmeyr568a7272015-10-12 11:57:38 +02001105 install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd);
1106 install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd);
1107 install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd);
Jacob Erlbeckcb1db8b2015-02-03 13:47:53 +01001108 install_element(SGSN_NODE, &cfg_apn_ggsn_cmd);
1109 install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd);
Holger Hans Peter Freyther9c20a5f2015-02-06 16:23:29 +01001110 install_element(SGSN_NODE, &cfg_apn_name_cmd);
1111 install_element(SGSN_NODE, &cfg_no_apn_name_cmd);
Holger Hans Peter Freytherc15c61c2015-05-06 17:46:08 +02001112 install_element(SGSN_NODE, &cfg_cdr_filename_cmd);
1113 install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd);
1114 install_element(SGSN_NODE, &cfg_cdr_interval_cmd);
Holger Hans Peter Freyther39c430e2015-05-25 12:26:49 +08001115 install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
Holger Hans Peter Freythera5a6da42015-05-25 15:20:27 +08001116 install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
Harald Welte288be162010-05-01 16:48:27 +02001117
Harald Welte94508822015-08-15 19:08:21 +02001118 install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd);
1119 install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd);
1120 install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd);
1121 install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd);
1122 install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd);
1123 install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd);
1124 install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd);
1125 install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd);
1126 install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd);
1127 install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd);
1128 install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd);
1129 install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd);
1130
Harald Welte288be162010-05-01 16:48:27 +02001131 return 0;
1132}
1133
1134int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
1135{
1136 int rc;
1137
1138 g_cfg = cfg;
Harald Welte7f6da482013-03-19 11:00:13 +01001139
Harald Welte94508822015-08-15 19:08:21 +02001140 g_cfg->timers.T3312 = GSM0408_T3312_SECS;
1141 g_cfg->timers.T3322 = GSM0408_T3322_SECS;
1142 g_cfg->timers.T3350 = GSM0408_T3350_SECS;
1143 g_cfg->timers.T3360 = GSM0408_T3360_SECS;
1144 g_cfg->timers.T3370 = GSM0408_T3370_SECS;
1145 g_cfg->timers.T3313 = GSM0408_T3313_SECS;
1146 g_cfg->timers.T3314 = GSM0408_T3314_SECS;
1147 g_cfg->timers.T3316 = GSM0408_T3316_SECS;
1148 g_cfg->timers.T3385 = GSM0408_T3385_SECS;
1149 g_cfg->timers.T3386 = GSM0408_T3386_SECS;
1150 g_cfg->timers.T3395 = GSM0408_T3395_SECS;
1151 g_cfg->timers.T3397 = GSM0408_T3397_SECS;
1152
Harald Weltedcccb182010-05-16 20:52:23 +02001153 rc = vty_read_config_file(config_file, NULL);
Harald Welte288be162010-05-01 16:48:27 +02001154 if (rc < 0) {
1155 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1156 return rc;
1157 }
1158
1159 return 0;
1160}