blob: f7c5bc8a6400072e94db05cc99644e662112e71e [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
Harald Weltedab544e2018-07-29 16:14:48 +0200159#define INT_CHOICE "(own-msisdn|own-imsi)"
160#define INT_STR "Internal USSD Handler\n" \
161 "Respond with subscribers' own MSISDN\n" \
162 "Respond with subscribers' own IMSI\n"
163
164#define EXT_STR "External USSD Handler\n" \
165 "Name of External USSD Handler (IPA CCM ID)\n"
166
167DEFUN(cfg_ussd_route_pfx_int, cfg_ussd_route_pfx_int_cmd,
168 "ussd route prefix PREFIX internal " INT_CHOICE,
169 USSD_STR UROUTE_STR PREFIX_STR INT_STR)
170{
171 const struct hlr_iuse *iuse = iuse_find(argv[1]);
172 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
Harald Welte4956ae12018-06-15 22:04:28 +0200173 if (rt) {
174 vty_out(vty, "%% Cannot add [another?] route for prefix %s%s", argv[0], VTY_NEWLINE);
175 return CMD_WARNING;
176 }
Harald Weltedab544e2018-07-29 16:14:48 +0200177 ussd_route_prefix_alloc_int(g_hlr, argv[0], iuse);
Harald Welte4956ae12018-06-15 22:04:28 +0200178
179 return CMD_SUCCESS;
180}
181
Harald Weltedab544e2018-07-29 16:14:48 +0200182DEFUN(cfg_ussd_route_pfx_ext, cfg_ussd_route_pfx_ext_cmd,
183 "ussd route prefix PREFIX external EUSE",
184 USSD_STR UROUTE_STR PREFIX_STR EXT_STR)
Harald Welte4956ae12018-06-15 22:04:28 +0200185{
Harald Weltedab544e2018-07-29 16:14:48 +0200186 struct hlr_euse *euse = euse_find(g_hlr, argv[1]);
187 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
188 if (rt) {
189 vty_out(vty, "%% Cannot add [another?] route for prefix %s%s", argv[0], VTY_NEWLINE);
190 return CMD_WARNING;
191 }
192 if (!euse) {
193 vty_out(vty, "%% Cannot find euse '%s'%s", argv[1], VTY_NEWLINE);
194 return CMD_WARNING;
195 }
196 ussd_route_prefix_alloc_ext(g_hlr, argv[0], euse);
197
198 return CMD_SUCCESS;
199}
200
201DEFUN(cfg_ussd_no_route_pfx, cfg_ussd_no_route_pfx_cmd,
202 "no ussd route prefix PREFIX",
203 NO_STR USSD_STR UROUTE_STR PREFIX_STR)
204{
205 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
Harald Welte4956ae12018-06-15 22:04:28 +0200206 if (!rt) {
207 vty_out(vty, "%% Cannot find route for prefix %s%s", argv[0], VTY_NEWLINE);
208 return CMD_WARNING;
209 }
Harald Weltedab544e2018-07-29 16:14:48 +0200210 ussd_route_del(rt);
Harald Welte4956ae12018-06-15 22:04:28 +0200211
212 return CMD_SUCCESS;
213}
214
Harald Weltedab544e2018-07-29 16:14:48 +0200215DEFUN(cfg_ussd_defaultroute, cfg_ussd_defaultroute_cmd,
216 "ussd default-route external EUSE",
217 USSD_STR "Configure default-route for all USSD to unknown destinations\n"
218 EXT_STR)
Harald Welte4956ae12018-06-15 22:04:28 +0200219{
Vadim Yanitskiyb93c44f2018-08-02 23:37:51 +0700220 struct hlr_euse *euse;
221
222 euse = euse_find(g_hlr, argv[0]);
223 if (!euse) {
224 vty_out(vty, "%% Cannot find EUSE %s%s", argv[0], VTY_NEWLINE);
225 return CMD_WARNING;
226 }
Harald Welte4956ae12018-06-15 22:04:28 +0200227
228 if (g_hlr->euse_default != euse) {
229 vty_out(vty, "Switching default route from %s to %s%s",
Harald Welte55d32a12018-07-30 17:26:35 +0200230 g_hlr->euse_default ? g_hlr->euse_default->name : "<none>",
231 euse->name, VTY_NEWLINE);
Harald Welte4956ae12018-06-15 22:04:28 +0200232 g_hlr->euse_default = euse;
233 }
234
235 return CMD_SUCCESS;
236}
237
Harald Weltedab544e2018-07-29 16:14:48 +0200238DEFUN(cfg_ussd_no_defaultroute, cfg_ussd_no_defaultroute_cmd,
239 "no ussd default-route",
240 NO_STR USSD_STR "Remove the default-route for all USSD to unknown destinations\n")
Harald Welte4956ae12018-06-15 22:04:28 +0200241{
Harald Welte4956ae12018-06-15 22:04:28 +0200242 g_hlr->euse_default = NULL;
243
244 return CMD_SUCCESS;
245}
246
Neels Hofmeyr5857c592019-04-02 04:24:49 +0200247DEFUN(cfg_database, cfg_database_cmd,
248 "database PATH",
249 "Set the path to the HLR database file\n"
250 "Relative or absolute file system path to the database file (default is '" HLR_DEFAULT_DB_FILE_PATH "')\n")
251{
252 osmo_talloc_replace_string(g_hlr, &g_hlr->db_file_path, argv[0]);
253 return CMD_SUCCESS;
254}
255
Harald Welte4956ae12018-06-15 22:04:28 +0200256struct cmd_node euse_node = {
257 EUSE_NODE,
258 "%s(config-hlr-euse)# ",
259 1,
260};
261
262DEFUN(cfg_euse, cfg_euse_cmd,
263 "euse NAME",
264 "Configure a particular External USSD Entity\n"
265 "Alphanumeric name of the External USSD Entity\n")
266{
267 struct hlr_euse *euse;
268 const char *id = argv[0];
269
270 euse = euse_find(g_hlr, id);
271 if (!euse) {
272 euse = euse_alloc(g_hlr, id);
273 if (!euse)
274 return CMD_WARNING;
275 }
276 vty->index = euse;
277 vty->index_sub = &euse->description;
278 vty->node = EUSE_NODE;
279
280 return CMD_SUCCESS;
281}
282
283DEFUN(cfg_no_euse, cfg_no_euse_cmd,
284 "no euse NAME",
285 NO_STR "Remove a particular External USSD Entity\n"
286 "Alphanumeric name of the External USSD Entity\n")
287{
288 struct hlr_euse *euse = euse_find(g_hlr, argv[0]);
289 if (!euse) {
290 vty_out(vty, "%% Cannot remove non-existant EUSE %s%s", argv[0], VTY_NEWLINE);
291 return CMD_WARNING;
292 }
293 if (g_hlr->euse_default == euse) {
294 vty_out(vty, "%% Cannot remove EUSE %s, it is the default route%s", argv[0], VTY_NEWLINE);
295 return CMD_WARNING;
296 }
297 euse_del(euse);
298 return CMD_SUCCESS;
299}
300
301static void dump_one_euse(struct vty *vty, struct hlr_euse *euse)
302{
Harald Welte4956ae12018-06-15 22:04:28 +0200303 vty_out(vty, " euse %s%s", euse->name, VTY_NEWLINE);
Harald Welte4956ae12018-06-15 22:04:28 +0200304}
305
306static int config_write_euse(struct vty *vty)
307{
308 struct hlr_euse *euse;
Harald Weltedab544e2018-07-29 16:14:48 +0200309 struct hlr_ussd_route *rt;
Harald Welte4956ae12018-06-15 22:04:28 +0200310
311 llist_for_each_entry(euse, &g_hlr->euse_list, list)
312 dump_one_euse(vty, euse);
313
Harald Weltedab544e2018-07-29 16:14:48 +0200314 llist_for_each_entry(rt, &g_hlr->ussd_routes, list) {
315 vty_out(vty, " ussd route prefix %s %s %s%s", rt->prefix,
316 rt->is_external ? "external" : "internal",
317 rt->is_external ? rt->u.euse->name : rt->u.iuse->name,
318 VTY_NEWLINE);
319 }
320
321 if (g_hlr->euse_default)
322 vty_out(vty, " ussd default-route external %s%s", g_hlr->euse_default->name, VTY_NEWLINE);
323
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700324 if (g_hlr->ncss_guard_timeout != NCSS_GUARD_TIMEOUT_DEFAULT)
325 vty_out(vty, " ncss-guard-timeout %i%s",
326 g_hlr->ncss_guard_timeout, VTY_NEWLINE);
327
Harald Welte4956ae12018-06-15 22:04:28 +0200328 return 0;
329}
330
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700331DEFUN(cfg_ncss_guard_timeout, cfg_ncss_guard_timeout_cmd,
332 "ncss-guard-timeout <0-255>",
333 "Set guard timer for NCSS (call independent SS) session activity\n"
334 "Guard timer value (sec.), or 0 to disable")
335{
336 g_hlr->ncss_guard_timeout = atoi(argv[0]);
337 return CMD_SUCCESS;
338}
339
Oliver Smith851814a2019-01-11 15:30:21 +0100340DEFUN(cfg_store_imei, cfg_store_imei_cmd,
341 "store-imei",
342 "Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send"
343 " Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1').")
344{
345 g_hlr->store_imei = true;
346 return CMD_SUCCESS;
347}
348
349DEFUN(cfg_no_store_imei, cfg_no_store_imei_cmd,
350 "no store-imei",
351 "Do not save the IMEI in the database, when receiving Check IMEI requests.")
352{
353 g_hlr->store_imei = false;
354 return CMD_SUCCESS;
355}
356
Oliver Smithc7f17872019-03-04 15:10:44 +0100357DEFUN(cfg_subscr_create_on_demand, cfg_subscr_create_on_demand_cmd,
358 "subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps)",
359 "Make a new record when a subscriber is first seen.\n"
360 "Do not automatically assign MSISDN.\n"
361 "Length of an automatically assigned MSISDN.\n"
362 "Do not allow any NAM (Network Access Mode) by default.\n"
363 "Allow access to circuit switched NAM by default.\n"
364 "Allow access to packet switched NAM by default.\n"
365 "Allow access to circuit and packet switched NAM by default.\n")
366{
367 unsigned int rand_msisdn_len = 0;
368 uint8_t flags = 0x00;
369
370 if (strcmp(argv[0], "no-msisdn") != 0)
371 rand_msisdn_len = atoi(argv[0]);
372
373 if (strstr(argv[1], "cs"))
374 flags |= DB_SUBSCR_FLAG_NAM_CS;
375 if (strstr(argv[1], "ps"))
376 flags |= DB_SUBSCR_FLAG_NAM_PS;
377
378 g_hlr->subscr_create_on_demand = true;
379 g_hlr->subscr_create_on_demand_rand_msisdn_len = rand_msisdn_len;
380 g_hlr->subscr_create_on_demand_flags = flags;
381
382 return CMD_SUCCESS;
383}
384
385DEFUN(cfg_no_subscr_create_on_demand, cfg_no_subscr_create_on_demand_cmd,
386 "no subscriber-create-on-demand",
387 "Do not make a new record when a subscriber is first seen.\n")
388{
389 g_hlr->subscr_create_on_demand = false;
390 return CMD_SUCCESS;
391}
392
Harald Welte4956ae12018-06-15 22:04:28 +0200393/***********************************************************************
394 * Common Code
395 ***********************************************************************/
396
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200397int hlr_vty_go_parent(struct vty *vty)
398{
399 switch (vty->node) {
400 case GSUP_NODE:
Harald Welte4956ae12018-06-15 22:04:28 +0200401 case EUSE_NODE:
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200402 vty->node = HLR_NODE;
403 vty->index = NULL;
Harald Welte4956ae12018-06-15 22:04:28 +0200404 vty->index_sub = NULL;
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200405 break;
406 default:
407 case HLR_NODE:
408 vty->node = CONFIG_NODE;
409 vty->index = NULL;
410 break;
411 case CONFIG_NODE:
412 vty->node = ENABLE_NODE;
413 vty->index = NULL;
414 break;
415 }
416
417 return vty->node;
418}
419
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100420int hlr_vty_is_config_node(struct vty *vty, int node)
421{
422 switch (node) {
423 /* add items that are not config */
424 case CONFIG_NODE:
425 return 0;
426
427 default:
428 return 1;
429 }
430}
431
Pau Espin Pedrole49391b2019-08-05 15:57:10 +0200432void hlr_vty_init(void)
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100433{
Pau Espin Pedrole49391b2019-08-05 15:57:10 +0200434 logging_vty_add_cmds();
Harald Welte7ee6e552018-02-14 00:52:05 +0100435 osmo_talloc_vty_add_cmds();
Max20ddfdb2019-02-18 13:12:27 +0100436 osmo_stats_vty_add_cmds();
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200437
Harald Weltefa7ee332018-06-24 13:20:32 +0200438 install_element_ve(&show_gsup_conn_cmd);
439
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200440 install_element(CONFIG_NODE, &cfg_hlr_cmd);
441 install_node(&hlr_node, config_write_hlr);
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200442
443 install_element(HLR_NODE, &cfg_gsup_cmd);
444 install_node(&gsup_node, config_write_hlr_gsup);
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200445
446 install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200447
Neels Hofmeyr5857c592019-04-02 04:24:49 +0200448 install_element(HLR_NODE, &cfg_database_cmd);
449
Harald Welte4956ae12018-06-15 22:04:28 +0200450 install_element(HLR_NODE, &cfg_euse_cmd);
451 install_element(HLR_NODE, &cfg_no_euse_cmd);
452 install_node(&euse_node, config_write_euse);
Harald Weltedab544e2018-07-29 16:14:48 +0200453 install_element(HLR_NODE, &cfg_ussd_route_pfx_int_cmd);
454 install_element(HLR_NODE, &cfg_ussd_route_pfx_ext_cmd);
455 install_element(HLR_NODE, &cfg_ussd_no_route_pfx_cmd);
456 install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
457 install_element(HLR_NODE, &cfg_ussd_no_defaultroute_cmd);
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700458 install_element(HLR_NODE, &cfg_ncss_guard_timeout_cmd);
Oliver Smith851814a2019-01-11 15:30:21 +0100459 install_element(HLR_NODE, &cfg_store_imei_cmd);
460 install_element(HLR_NODE, &cfg_no_store_imei_cmd);
Oliver Smithc7f17872019-03-04 15:10:44 +0100461 install_element(HLR_NODE, &cfg_subscr_create_on_demand_cmd);
462 install_element(HLR_NODE, &cfg_no_subscr_create_on_demand_cmd);
Harald Welte4956ae12018-06-15 22:04:28 +0200463
Harald Welted5807b82018-07-29 12:27:41 +0200464 hlr_vty_subscriber_init();
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100465}