blob: d2f5a2e04586f4218bc776d99814bc29fc7c32b6 [file] [log] [blame]
Neels Hofmeyr7685a782017-01-30 23:30:26 +01001/* OsmoHLR VTY implementation */
2
3/* (C) 2016 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
Neels Hofmeyr7685a782017-01-30 23:30:26 +01004 * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
Harald Weltefa7ee332018-06-24 13:20:32 +02005 * (C) 2018 Harald Welte <laforge@gnumonks.org>
6 *
7 * All Rights Reserved
Neels Hofmeyr7685a782017-01-30 23:30:26 +01008 *
Harald Welte4956ae12018-06-15 22:04:28 +02009 * (C) 2018 Harald Welte <laforge@gnumonks.org>
10 *
11 * All Rights Reserved
12 *
Neels Hofmeyr7685a782017-01-30 23:30:26 +010013 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Affero General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Affero General Public License for more details.
22 *
23 * You should have received a copy of the GNU Affero General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 *
26 */
27
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +020028#include <osmocom/core/talloc.h>
Neels Hofmeyr7685a782017-01-30 23:30:26 +010029#include <osmocom/vty/vty.h>
Max20ddfdb2019-02-18 13:12:27 +010030#include <osmocom/vty/stats.h>
Neels Hofmeyr7685a782017-01-30 23:30:26 +010031#include <osmocom/vty/command.h>
32#include <osmocom/vty/logging.h>
Harald Welte7ee6e552018-02-14 00:52:05 +010033#include <osmocom/vty/misc.h>
Harald Weltefa7ee332018-06-24 13:20:32 +020034#include <osmocom/abis/ipa.h>
Neels Hofmeyr7685a782017-01-30 23:30:26 +010035
Oliver Smithc7f17872019-03-04 15:10:44 +010036#include "db.h"
Harald Weltedab544e2018-07-29 16:14:48 +020037#include "hlr.h"
Neels Hofmeyr7685a782017-01-30 23:30:26 +010038#include "hlr_vty.h"
Neels Hofmeyr183e7002017-10-06 02:59:54 +020039#include "hlr_vty_subscr.h"
Vadim Yanitskiyd157a562018-12-01 00:03:39 +070040#include "hlr_ussd.h"
Harald Weltefa7ee332018-06-24 13:20:32 +020041#include "gsup_server.h"
Neels Hofmeyr7685a782017-01-30 23:30:26 +010042
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +020043struct cmd_node hlr_node = {
44 HLR_NODE,
45 "%s(config-hlr)# ",
46 1,
47};
48
49DEFUN(cfg_hlr,
50 cfg_hlr_cmd,
51 "hlr",
52 "Configure the HLR")
53{
54 vty->node = HLR_NODE;
55 return CMD_SUCCESS;
56}
57
58struct cmd_node gsup_node = {
59 GSUP_NODE,
60 "%s(config-hlr-gsup)# ",
61 1,
62};
63
64DEFUN(cfg_gsup,
65 cfg_gsup_cmd,
66 "gsup",
67 "Configure GSUP options")
68{
69 vty->node = GSUP_NODE;
70 return CMD_SUCCESS;
71}
72
73static int config_write_hlr(struct vty *vty)
74{
75 vty_out(vty, "hlr%s", VTY_NEWLINE);
Oliver Smith851814a2019-01-11 15:30:21 +010076 if (g_hlr->store_imei)
77 vty_out(vty, " store-imei%s", VTY_NEWLINE);
Neels Hofmeyr5857c592019-04-02 04:24:49 +020078 if (g_hlr->db_file_path && strcmp(g_hlr->db_file_path, HLR_DEFAULT_DB_FILE_PATH))
79 vty_out(vty, " database %s%s", g_hlr->db_file_path, VTY_NEWLINE);
Oliver Smithc7f17872019-03-04 15:10:44 +010080 if (g_hlr->subscr_create_on_demand) {
81 const char *flags_str = "none";
82 uint8_t flags = g_hlr->subscr_create_on_demand_flags;
83 unsigned int rand_msisdn_len = g_hlr->subscr_create_on_demand_rand_msisdn_len;
84
85 if ((flags & DB_SUBSCR_FLAG_NAM_CS) && (flags & DB_SUBSCR_FLAG_NAM_PS))
86 flags_str = "cs+ps";
87 else if (flags & DB_SUBSCR_FLAG_NAM_CS)
88 flags_str = "cs";
89 else if (flags & DB_SUBSCR_FLAG_NAM_PS)
90 flags_str = "ps";
91
92 if (rand_msisdn_len)
93 vty_out(vty, " subscriber-create-on-demand %i %s%s", rand_msisdn_len, flags_str, VTY_NEWLINE);
94 else
95 vty_out(vty, " subscriber-create-on-demand no-msisdn %s%s", flags_str, VTY_NEWLINE);
96 }
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +020097 return CMD_SUCCESS;
98}
99
100static int config_write_hlr_gsup(struct vty *vty)
101{
102 vty_out(vty, " gsup%s", VTY_NEWLINE);
103 if (g_hlr->gsup_bind_addr)
104 vty_out(vty, " bind ip %s%s", g_hlr->gsup_bind_addr, VTY_NEWLINE);
105 return CMD_SUCCESS;
106}
107
Harald Weltefa7ee332018-06-24 13:20:32 +0200108static void show_one_conn(struct vty *vty, const struct osmo_gsup_conn *conn)
109{
110 const struct ipa_server_conn *isc = conn->conn;
111 char *name;
112 int rc;
113
114 rc = osmo_gsup_conn_ccm_get(conn, (uint8_t **) &name, IPAC_IDTAG_SERNR);
115 OSMO_ASSERT(rc);
116
117 vty_out(vty, " '%s' from %s:%5u, CS=%u, PS=%u, 3G_IND=%u%s",
118 name, isc->addr, isc->port, conn->supports_cs, conn->supports_ps, conn->auc_3g_ind,
119 VTY_NEWLINE);
120}
121
122DEFUN(show_gsup_conn, show_gsup_conn_cmd,
123 "show gsup-connections",
124 SHOW_STR "GSUP Connections from VLRs, SGSNs, EUSEs\n")
125{
126 struct osmo_gsup_server *gs = g_hlr->gs;
127 struct osmo_gsup_conn *conn;
128
129 llist_for_each_entry(conn, &gs->clients, list)
130 show_one_conn(vty, conn);
131
132 return CMD_SUCCESS;
133}
134
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200135DEFUN(cfg_hlr_gsup_bind_ip,
136 cfg_hlr_gsup_bind_ip_cmd,
137 "bind ip A.B.C.D",
138 "Listen/Bind related socket option\n"
139 IP_STR
140 "IPv4 Address to bind the GSUP interface to\n")
141{
142 if(g_hlr->gsup_bind_addr)
143 talloc_free(g_hlr->gsup_bind_addr);
144 g_hlr->gsup_bind_addr = talloc_strdup(g_hlr, argv[0]);
145
146 return CMD_SUCCESS;
147}
148
Harald Welte4956ae12018-06-15 22:04:28 +0200149/***********************************************************************
Harald Weltedab544e2018-07-29 16:14:48 +0200150 * USSD Entity
Harald Welte4956ae12018-06-15 22:04:28 +0200151 ***********************************************************************/
152
153#include "hlr_ussd.h"
154
Harald Weltedab544e2018-07-29 16:14:48 +0200155#define USSD_STR "USSD Configuration\n"
156#define UROUTE_STR "Routing Configuration\n"
157#define PREFIX_STR "Prefix-Matching Route\n" "USSD Prefix\n"
Harald Welte4956ae12018-06-15 22:04:28 +0200158
Vadim Yanitskiy277b2d62018-12-27 05:39:54 +0700159#define INT_CHOICE "(own-msisdn|own-imsi|get-ran)"
Harald Weltedab544e2018-07-29 16:14:48 +0200160#define INT_STR "Internal USSD Handler\n" \
161 "Respond with subscribers' own MSISDN\n" \
Vadim Yanitskiy277b2d62018-12-27 05:39:54 +0700162 "Respond with subscribers' own IMSI\n" \
163 "Respond with available RAN types\n"
Harald Weltedab544e2018-07-29 16:14:48 +0200164
165#define EXT_STR "External USSD Handler\n" \
166 "Name of External USSD Handler (IPA CCM ID)\n"
167
168DEFUN(cfg_ussd_route_pfx_int, cfg_ussd_route_pfx_int_cmd,
169 "ussd route prefix PREFIX internal " INT_CHOICE,
170 USSD_STR UROUTE_STR PREFIX_STR INT_STR)
171{
172 const struct hlr_iuse *iuse = iuse_find(argv[1]);
173 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
Harald Welte4956ae12018-06-15 22:04:28 +0200174 if (rt) {
175 vty_out(vty, "%% Cannot add [another?] route for prefix %s%s", argv[0], VTY_NEWLINE);
176 return CMD_WARNING;
177 }
Harald Weltedab544e2018-07-29 16:14:48 +0200178 ussd_route_prefix_alloc_int(g_hlr, argv[0], iuse);
Harald Welte4956ae12018-06-15 22:04:28 +0200179
180 return CMD_SUCCESS;
181}
182
Harald Weltedab544e2018-07-29 16:14:48 +0200183DEFUN(cfg_ussd_route_pfx_ext, cfg_ussd_route_pfx_ext_cmd,
184 "ussd route prefix PREFIX external EUSE",
185 USSD_STR UROUTE_STR PREFIX_STR EXT_STR)
Harald Welte4956ae12018-06-15 22:04:28 +0200186{
Harald Weltedab544e2018-07-29 16:14:48 +0200187 struct hlr_euse *euse = euse_find(g_hlr, argv[1]);
188 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
189 if (rt) {
190 vty_out(vty, "%% Cannot add [another?] route for prefix %s%s", argv[0], VTY_NEWLINE);
191 return CMD_WARNING;
192 }
193 if (!euse) {
194 vty_out(vty, "%% Cannot find euse '%s'%s", argv[1], VTY_NEWLINE);
195 return CMD_WARNING;
196 }
197 ussd_route_prefix_alloc_ext(g_hlr, argv[0], euse);
198
199 return CMD_SUCCESS;
200}
201
202DEFUN(cfg_ussd_no_route_pfx, cfg_ussd_no_route_pfx_cmd,
203 "no ussd route prefix PREFIX",
204 NO_STR USSD_STR UROUTE_STR PREFIX_STR)
205{
206 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
Harald Welte4956ae12018-06-15 22:04:28 +0200207 if (!rt) {
208 vty_out(vty, "%% Cannot find route for prefix %s%s", argv[0], VTY_NEWLINE);
209 return CMD_WARNING;
210 }
Harald Weltedab544e2018-07-29 16:14:48 +0200211 ussd_route_del(rt);
Harald Welte4956ae12018-06-15 22:04:28 +0200212
213 return CMD_SUCCESS;
214}
215
Harald Weltedab544e2018-07-29 16:14:48 +0200216DEFUN(cfg_ussd_defaultroute, cfg_ussd_defaultroute_cmd,
217 "ussd default-route external EUSE",
218 USSD_STR "Configure default-route for all USSD to unknown destinations\n"
219 EXT_STR)
Harald Welte4956ae12018-06-15 22:04:28 +0200220{
Vadim Yanitskiyb93c44f2018-08-02 23:37:51 +0700221 struct hlr_euse *euse;
222
223 euse = euse_find(g_hlr, argv[0]);
224 if (!euse) {
225 vty_out(vty, "%% Cannot find EUSE %s%s", argv[0], VTY_NEWLINE);
226 return CMD_WARNING;
227 }
Harald Welte4956ae12018-06-15 22:04:28 +0200228
229 if (g_hlr->euse_default != euse) {
230 vty_out(vty, "Switching default route from %s to %s%s",
Harald Welte55d32a12018-07-30 17:26:35 +0200231 g_hlr->euse_default ? g_hlr->euse_default->name : "<none>",
232 euse->name, VTY_NEWLINE);
Harald Welte4956ae12018-06-15 22:04:28 +0200233 g_hlr->euse_default = euse;
234 }
235
236 return CMD_SUCCESS;
237}
238
Harald Weltedab544e2018-07-29 16:14:48 +0200239DEFUN(cfg_ussd_no_defaultroute, cfg_ussd_no_defaultroute_cmd,
240 "no ussd default-route",
241 NO_STR USSD_STR "Remove the default-route for all USSD to unknown destinations\n")
Harald Welte4956ae12018-06-15 22:04:28 +0200242{
Harald Welte4956ae12018-06-15 22:04:28 +0200243 g_hlr->euse_default = NULL;
244
245 return CMD_SUCCESS;
246}
247
Neels Hofmeyr5857c592019-04-02 04:24:49 +0200248DEFUN(cfg_database, cfg_database_cmd,
249 "database PATH",
250 "Set the path to the HLR database file\n"
251 "Relative or absolute file system path to the database file (default is '" HLR_DEFAULT_DB_FILE_PATH "')\n")
252{
253 osmo_talloc_replace_string(g_hlr, &g_hlr->db_file_path, argv[0]);
254 return CMD_SUCCESS;
255}
256
Harald Welte4956ae12018-06-15 22:04:28 +0200257struct cmd_node euse_node = {
258 EUSE_NODE,
259 "%s(config-hlr-euse)# ",
260 1,
261};
262
263DEFUN(cfg_euse, cfg_euse_cmd,
264 "euse NAME",
265 "Configure a particular External USSD Entity\n"
266 "Alphanumeric name of the External USSD Entity\n")
267{
268 struct hlr_euse *euse;
269 const char *id = argv[0];
270
271 euse = euse_find(g_hlr, id);
272 if (!euse) {
273 euse = euse_alloc(g_hlr, id);
274 if (!euse)
275 return CMD_WARNING;
276 }
277 vty->index = euse;
278 vty->index_sub = &euse->description;
279 vty->node = EUSE_NODE;
280
281 return CMD_SUCCESS;
282}
283
284DEFUN(cfg_no_euse, cfg_no_euse_cmd,
285 "no euse NAME",
286 NO_STR "Remove a particular External USSD Entity\n"
287 "Alphanumeric name of the External USSD Entity\n")
288{
289 struct hlr_euse *euse = euse_find(g_hlr, argv[0]);
290 if (!euse) {
291 vty_out(vty, "%% Cannot remove non-existant EUSE %s%s", argv[0], VTY_NEWLINE);
292 return CMD_WARNING;
293 }
294 if (g_hlr->euse_default == euse) {
295 vty_out(vty, "%% Cannot remove EUSE %s, it is the default route%s", argv[0], VTY_NEWLINE);
296 return CMD_WARNING;
297 }
298 euse_del(euse);
299 return CMD_SUCCESS;
300}
301
302static void dump_one_euse(struct vty *vty, struct hlr_euse *euse)
303{
Harald Welte4956ae12018-06-15 22:04:28 +0200304 vty_out(vty, " euse %s%s", euse->name, VTY_NEWLINE);
Harald Welte4956ae12018-06-15 22:04:28 +0200305}
306
307static int config_write_euse(struct vty *vty)
308{
309 struct hlr_euse *euse;
Harald Weltedab544e2018-07-29 16:14:48 +0200310 struct hlr_ussd_route *rt;
Harald Welte4956ae12018-06-15 22:04:28 +0200311
312 llist_for_each_entry(euse, &g_hlr->euse_list, list)
313 dump_one_euse(vty, euse);
314
Harald Weltedab544e2018-07-29 16:14:48 +0200315 llist_for_each_entry(rt, &g_hlr->ussd_routes, list) {
316 vty_out(vty, " ussd route prefix %s %s %s%s", rt->prefix,
317 rt->is_external ? "external" : "internal",
318 rt->is_external ? rt->u.euse->name : rt->u.iuse->name,
319 VTY_NEWLINE);
320 }
321
322 if (g_hlr->euse_default)
323 vty_out(vty, " ussd default-route external %s%s", g_hlr->euse_default->name, VTY_NEWLINE);
324
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700325 if (g_hlr->ncss_guard_timeout != NCSS_GUARD_TIMEOUT_DEFAULT)
326 vty_out(vty, " ncss-guard-timeout %i%s",
327 g_hlr->ncss_guard_timeout, VTY_NEWLINE);
328
Harald Welte4956ae12018-06-15 22:04:28 +0200329 return 0;
330}
331
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700332DEFUN(cfg_ncss_guard_timeout, cfg_ncss_guard_timeout_cmd,
333 "ncss-guard-timeout <0-255>",
334 "Set guard timer for NCSS (call independent SS) session activity\n"
335 "Guard timer value (sec.), or 0 to disable")
336{
337 g_hlr->ncss_guard_timeout = atoi(argv[0]);
338 return CMD_SUCCESS;
339}
340
Oliver Smith851814a2019-01-11 15:30:21 +0100341DEFUN(cfg_store_imei, cfg_store_imei_cmd,
342 "store-imei",
343 "Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send"
344 " Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1').")
345{
346 g_hlr->store_imei = true;
347 return CMD_SUCCESS;
348}
349
350DEFUN(cfg_no_store_imei, cfg_no_store_imei_cmd,
351 "no store-imei",
352 "Do not save the IMEI in the database, when receiving Check IMEI requests.")
353{
354 g_hlr->store_imei = false;
355 return CMD_SUCCESS;
356}
357
Oliver Smithc7f17872019-03-04 15:10:44 +0100358DEFUN(cfg_subscr_create_on_demand, cfg_subscr_create_on_demand_cmd,
359 "subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps)",
360 "Make a new record when a subscriber is first seen.\n"
361 "Do not automatically assign MSISDN.\n"
362 "Length of an automatically assigned MSISDN.\n"
363 "Do not allow any NAM (Network Access Mode) by default.\n"
364 "Allow access to circuit switched NAM by default.\n"
365 "Allow access to packet switched NAM by default.\n"
366 "Allow access to circuit and packet switched NAM by default.\n")
367{
368 unsigned int rand_msisdn_len = 0;
369 uint8_t flags = 0x00;
370
371 if (strcmp(argv[0], "no-msisdn") != 0)
372 rand_msisdn_len = atoi(argv[0]);
373
374 if (strstr(argv[1], "cs"))
375 flags |= DB_SUBSCR_FLAG_NAM_CS;
376 if (strstr(argv[1], "ps"))
377 flags |= DB_SUBSCR_FLAG_NAM_PS;
378
379 g_hlr->subscr_create_on_demand = true;
380 g_hlr->subscr_create_on_demand_rand_msisdn_len = rand_msisdn_len;
381 g_hlr->subscr_create_on_demand_flags = flags;
382
383 return CMD_SUCCESS;
384}
385
386DEFUN(cfg_no_subscr_create_on_demand, cfg_no_subscr_create_on_demand_cmd,
387 "no subscriber-create-on-demand",
388 "Do not make a new record when a subscriber is first seen.\n")
389{
390 g_hlr->subscr_create_on_demand = false;
391 return CMD_SUCCESS;
392}
393
Harald Welte4956ae12018-06-15 22:04:28 +0200394/***********************************************************************
395 * Common Code
396 ***********************************************************************/
397
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200398int hlr_vty_go_parent(struct vty *vty)
399{
400 switch (vty->node) {
401 case GSUP_NODE:
Harald Welte4956ae12018-06-15 22:04:28 +0200402 case EUSE_NODE:
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200403 vty->node = HLR_NODE;
404 vty->index = NULL;
Harald Welte4956ae12018-06-15 22:04:28 +0200405 vty->index_sub = NULL;
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200406 break;
407 default:
408 case HLR_NODE:
409 vty->node = CONFIG_NODE;
410 vty->index = NULL;
411 break;
412 case CONFIG_NODE:
413 vty->node = ENABLE_NODE;
414 vty->index = NULL;
415 break;
416 }
417
418 return vty->node;
419}
420
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100421int hlr_vty_is_config_node(struct vty *vty, int node)
422{
423 switch (node) {
424 /* add items that are not config */
425 case CONFIG_NODE:
426 return 0;
427
428 default:
429 return 1;
430 }
431}
432
Pau Espin Pedrole49391b2019-08-05 15:57:10 +0200433void hlr_vty_init(void)
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100434{
Pau Espin Pedrole49391b2019-08-05 15:57:10 +0200435 logging_vty_add_cmds();
Harald Welte7ee6e552018-02-14 00:52:05 +0100436 osmo_talloc_vty_add_cmds();
Max20ddfdb2019-02-18 13:12:27 +0100437 osmo_stats_vty_add_cmds();
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200438
Harald Weltefa7ee332018-06-24 13:20:32 +0200439 install_element_ve(&show_gsup_conn_cmd);
440
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200441 install_element(CONFIG_NODE, &cfg_hlr_cmd);
442 install_node(&hlr_node, config_write_hlr);
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200443
444 install_element(HLR_NODE, &cfg_gsup_cmd);
445 install_node(&gsup_node, config_write_hlr_gsup);
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200446
447 install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200448
Neels Hofmeyr5857c592019-04-02 04:24:49 +0200449 install_element(HLR_NODE, &cfg_database_cmd);
450
Harald Welte4956ae12018-06-15 22:04:28 +0200451 install_element(HLR_NODE, &cfg_euse_cmd);
452 install_element(HLR_NODE, &cfg_no_euse_cmd);
453 install_node(&euse_node, config_write_euse);
Harald Weltedab544e2018-07-29 16:14:48 +0200454 install_element(HLR_NODE, &cfg_ussd_route_pfx_int_cmd);
455 install_element(HLR_NODE, &cfg_ussd_route_pfx_ext_cmd);
456 install_element(HLR_NODE, &cfg_ussd_no_route_pfx_cmd);
457 install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
458 install_element(HLR_NODE, &cfg_ussd_no_defaultroute_cmd);
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700459 install_element(HLR_NODE, &cfg_ncss_guard_timeout_cmd);
Oliver Smith851814a2019-01-11 15:30:21 +0100460 install_element(HLR_NODE, &cfg_store_imei_cmd);
461 install_element(HLR_NODE, &cfg_no_store_imei_cmd);
Oliver Smithc7f17872019-03-04 15:10:44 +0100462 install_element(HLR_NODE, &cfg_subscr_create_on_demand_cmd);
463 install_element(HLR_NODE, &cfg_no_subscr_create_on_demand_cmd);
Harald Welte4956ae12018-06-15 22:04:28 +0200464
Harald Welted5807b82018-07-29 12:27:41 +0200465 hlr_vty_subscriber_init();
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100466}