blob: 5e7fa9a651c80f8cf2549c312874b734de036119 [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 Yanitskiye9dd9c62018-12-27 08:15:00 +0700159#define INT_CHOICE "(own-msisdn|own-imsi|get-ran|umts-on|umts-off)"
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" \
Vadim Yanitskiye9dd9c62018-12-27 08:15:00 +0700163 "Respond with available RAN types\n" \
164 "Enable UMTS service\n" \
165 "Disable UMTS service\n"
Harald Weltedab544e2018-07-29 16:14:48 +0200166
167#define EXT_STR "External USSD Handler\n" \
168 "Name of External USSD Handler (IPA CCM ID)\n"
169
170DEFUN(cfg_ussd_route_pfx_int, cfg_ussd_route_pfx_int_cmd,
171 "ussd route prefix PREFIX internal " INT_CHOICE,
172 USSD_STR UROUTE_STR PREFIX_STR INT_STR)
173{
174 const struct hlr_iuse *iuse = iuse_find(argv[1]);
175 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
Harald Welte4956ae12018-06-15 22:04:28 +0200176 if (rt) {
177 vty_out(vty, "%% Cannot add [another?] route for prefix %s%s", argv[0], VTY_NEWLINE);
178 return CMD_WARNING;
179 }
Harald Weltedab544e2018-07-29 16:14:48 +0200180 ussd_route_prefix_alloc_int(g_hlr, argv[0], iuse);
Harald Welte4956ae12018-06-15 22:04:28 +0200181
182 return CMD_SUCCESS;
183}
184
Harald Weltedab544e2018-07-29 16:14:48 +0200185DEFUN(cfg_ussd_route_pfx_ext, cfg_ussd_route_pfx_ext_cmd,
186 "ussd route prefix PREFIX external EUSE",
187 USSD_STR UROUTE_STR PREFIX_STR EXT_STR)
Harald Welte4956ae12018-06-15 22:04:28 +0200188{
Harald Weltedab544e2018-07-29 16:14:48 +0200189 struct hlr_euse *euse = euse_find(g_hlr, argv[1]);
190 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
191 if (rt) {
192 vty_out(vty, "%% Cannot add [another?] route for prefix %s%s", argv[0], VTY_NEWLINE);
193 return CMD_WARNING;
194 }
195 if (!euse) {
196 vty_out(vty, "%% Cannot find euse '%s'%s", argv[1], VTY_NEWLINE);
197 return CMD_WARNING;
198 }
199 ussd_route_prefix_alloc_ext(g_hlr, argv[0], euse);
200
201 return CMD_SUCCESS;
202}
203
204DEFUN(cfg_ussd_no_route_pfx, cfg_ussd_no_route_pfx_cmd,
205 "no ussd route prefix PREFIX",
206 NO_STR USSD_STR UROUTE_STR PREFIX_STR)
207{
208 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
Harald Welte4956ae12018-06-15 22:04:28 +0200209 if (!rt) {
210 vty_out(vty, "%% Cannot find route for prefix %s%s", argv[0], VTY_NEWLINE);
211 return CMD_WARNING;
212 }
Harald Weltedab544e2018-07-29 16:14:48 +0200213 ussd_route_del(rt);
Harald Welte4956ae12018-06-15 22:04:28 +0200214
215 return CMD_SUCCESS;
216}
217
Harald Weltedab544e2018-07-29 16:14:48 +0200218DEFUN(cfg_ussd_defaultroute, cfg_ussd_defaultroute_cmd,
219 "ussd default-route external EUSE",
220 USSD_STR "Configure default-route for all USSD to unknown destinations\n"
221 EXT_STR)
Harald Welte4956ae12018-06-15 22:04:28 +0200222{
Vadim Yanitskiyb93c44f2018-08-02 23:37:51 +0700223 struct hlr_euse *euse;
224
225 euse = euse_find(g_hlr, argv[0]);
226 if (!euse) {
227 vty_out(vty, "%% Cannot find EUSE %s%s", argv[0], VTY_NEWLINE);
228 return CMD_WARNING;
229 }
Harald Welte4956ae12018-06-15 22:04:28 +0200230
231 if (g_hlr->euse_default != euse) {
232 vty_out(vty, "Switching default route from %s to %s%s",
Harald Welte55d32a12018-07-30 17:26:35 +0200233 g_hlr->euse_default ? g_hlr->euse_default->name : "<none>",
234 euse->name, VTY_NEWLINE);
Harald Welte4956ae12018-06-15 22:04:28 +0200235 g_hlr->euse_default = euse;
236 }
237
238 return CMD_SUCCESS;
239}
240
Harald Weltedab544e2018-07-29 16:14:48 +0200241DEFUN(cfg_ussd_no_defaultroute, cfg_ussd_no_defaultroute_cmd,
242 "no ussd default-route",
243 NO_STR USSD_STR "Remove the default-route for all USSD to unknown destinations\n")
Harald Welte4956ae12018-06-15 22:04:28 +0200244{
Harald Welte4956ae12018-06-15 22:04:28 +0200245 g_hlr->euse_default = NULL;
246
247 return CMD_SUCCESS;
248}
249
Neels Hofmeyr5857c592019-04-02 04:24:49 +0200250DEFUN(cfg_database, cfg_database_cmd,
251 "database PATH",
252 "Set the path to the HLR database file\n"
253 "Relative or absolute file system path to the database file (default is '" HLR_DEFAULT_DB_FILE_PATH "')\n")
254{
255 osmo_talloc_replace_string(g_hlr, &g_hlr->db_file_path, argv[0]);
256 return CMD_SUCCESS;
257}
258
Harald Welte4956ae12018-06-15 22:04:28 +0200259struct cmd_node euse_node = {
260 EUSE_NODE,
261 "%s(config-hlr-euse)# ",
262 1,
263};
264
265DEFUN(cfg_euse, cfg_euse_cmd,
266 "euse NAME",
267 "Configure a particular External USSD Entity\n"
268 "Alphanumeric name of the External USSD Entity\n")
269{
270 struct hlr_euse *euse;
271 const char *id = argv[0];
272
273 euse = euse_find(g_hlr, id);
274 if (!euse) {
275 euse = euse_alloc(g_hlr, id);
276 if (!euse)
277 return CMD_WARNING;
278 }
279 vty->index = euse;
280 vty->index_sub = &euse->description;
281 vty->node = EUSE_NODE;
282
283 return CMD_SUCCESS;
284}
285
286DEFUN(cfg_no_euse, cfg_no_euse_cmd,
287 "no euse NAME",
288 NO_STR "Remove a particular External USSD Entity\n"
289 "Alphanumeric name of the External USSD Entity\n")
290{
291 struct hlr_euse *euse = euse_find(g_hlr, argv[0]);
292 if (!euse) {
293 vty_out(vty, "%% Cannot remove non-existant EUSE %s%s", argv[0], VTY_NEWLINE);
294 return CMD_WARNING;
295 }
296 if (g_hlr->euse_default == euse) {
297 vty_out(vty, "%% Cannot remove EUSE %s, it is the default route%s", argv[0], VTY_NEWLINE);
298 return CMD_WARNING;
299 }
300 euse_del(euse);
301 return CMD_SUCCESS;
302}
303
304static void dump_one_euse(struct vty *vty, struct hlr_euse *euse)
305{
Harald Welte4956ae12018-06-15 22:04:28 +0200306 vty_out(vty, " euse %s%s", euse->name, VTY_NEWLINE);
Harald Welte4956ae12018-06-15 22:04:28 +0200307}
308
309static int config_write_euse(struct vty *vty)
310{
311 struct hlr_euse *euse;
Harald Weltedab544e2018-07-29 16:14:48 +0200312 struct hlr_ussd_route *rt;
Harald Welte4956ae12018-06-15 22:04:28 +0200313
314 llist_for_each_entry(euse, &g_hlr->euse_list, list)
315 dump_one_euse(vty, euse);
316
Harald Weltedab544e2018-07-29 16:14:48 +0200317 llist_for_each_entry(rt, &g_hlr->ussd_routes, list) {
318 vty_out(vty, " ussd route prefix %s %s %s%s", rt->prefix,
319 rt->is_external ? "external" : "internal",
320 rt->is_external ? rt->u.euse->name : rt->u.iuse->name,
321 VTY_NEWLINE);
322 }
323
324 if (g_hlr->euse_default)
325 vty_out(vty, " ussd default-route external %s%s", g_hlr->euse_default->name, VTY_NEWLINE);
326
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700327 if (g_hlr->ncss_guard_timeout != NCSS_GUARD_TIMEOUT_DEFAULT)
328 vty_out(vty, " ncss-guard-timeout %i%s",
329 g_hlr->ncss_guard_timeout, VTY_NEWLINE);
330
Harald Welte4956ae12018-06-15 22:04:28 +0200331 return 0;
332}
333
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700334DEFUN(cfg_ncss_guard_timeout, cfg_ncss_guard_timeout_cmd,
335 "ncss-guard-timeout <0-255>",
336 "Set guard timer for NCSS (call independent SS) session activity\n"
337 "Guard timer value (sec.), or 0 to disable")
338{
339 g_hlr->ncss_guard_timeout = atoi(argv[0]);
340 return CMD_SUCCESS;
341}
342
Oliver Smith851814a2019-01-11 15:30:21 +0100343DEFUN(cfg_store_imei, cfg_store_imei_cmd,
344 "store-imei",
345 "Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send"
346 " Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1').")
347{
348 g_hlr->store_imei = true;
349 return CMD_SUCCESS;
350}
351
352DEFUN(cfg_no_store_imei, cfg_no_store_imei_cmd,
353 "no store-imei",
354 "Do not save the IMEI in the database, when receiving Check IMEI requests.")
355{
356 g_hlr->store_imei = false;
357 return CMD_SUCCESS;
358}
359
Oliver Smithc7f17872019-03-04 15:10:44 +0100360DEFUN(cfg_subscr_create_on_demand, cfg_subscr_create_on_demand_cmd,
361 "subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps)",
362 "Make a new record when a subscriber is first seen.\n"
363 "Do not automatically assign MSISDN.\n"
364 "Length of an automatically assigned MSISDN.\n"
365 "Do not allow any NAM (Network Access Mode) by default.\n"
366 "Allow access to circuit switched NAM by default.\n"
367 "Allow access to packet switched NAM by default.\n"
368 "Allow access to circuit and packet switched NAM by default.\n")
369{
370 unsigned int rand_msisdn_len = 0;
371 uint8_t flags = 0x00;
372
373 if (strcmp(argv[0], "no-msisdn") != 0)
374 rand_msisdn_len = atoi(argv[0]);
375
376 if (strstr(argv[1], "cs"))
377 flags |= DB_SUBSCR_FLAG_NAM_CS;
378 if (strstr(argv[1], "ps"))
379 flags |= DB_SUBSCR_FLAG_NAM_PS;
380
381 g_hlr->subscr_create_on_demand = true;
382 g_hlr->subscr_create_on_demand_rand_msisdn_len = rand_msisdn_len;
383 g_hlr->subscr_create_on_demand_flags = flags;
384
385 return CMD_SUCCESS;
386}
387
388DEFUN(cfg_no_subscr_create_on_demand, cfg_no_subscr_create_on_demand_cmd,
389 "no subscriber-create-on-demand",
390 "Do not make a new record when a subscriber is first seen.\n")
391{
392 g_hlr->subscr_create_on_demand = false;
393 return CMD_SUCCESS;
394}
395
Harald Welte4956ae12018-06-15 22:04:28 +0200396/***********************************************************************
397 * Common Code
398 ***********************************************************************/
399
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200400int hlr_vty_go_parent(struct vty *vty)
401{
402 switch (vty->node) {
403 case GSUP_NODE:
Harald Welte4956ae12018-06-15 22:04:28 +0200404 case EUSE_NODE:
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200405 vty->node = HLR_NODE;
406 vty->index = NULL;
Harald Welte4956ae12018-06-15 22:04:28 +0200407 vty->index_sub = NULL;
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200408 break;
409 default:
410 case HLR_NODE:
411 vty->node = CONFIG_NODE;
412 vty->index = NULL;
413 break;
414 case CONFIG_NODE:
415 vty->node = ENABLE_NODE;
416 vty->index = NULL;
417 break;
418 }
419
420 return vty->node;
421}
422
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100423int hlr_vty_is_config_node(struct vty *vty, int node)
424{
425 switch (node) {
426 /* add items that are not config */
427 case CONFIG_NODE:
428 return 0;
429
430 default:
431 return 1;
432 }
433}
434
Pau Espin Pedrole49391b2019-08-05 15:57:10 +0200435void hlr_vty_init(void)
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100436{
Pau Espin Pedrole49391b2019-08-05 15:57:10 +0200437 logging_vty_add_cmds();
Harald Welte7ee6e552018-02-14 00:52:05 +0100438 osmo_talloc_vty_add_cmds();
Max20ddfdb2019-02-18 13:12:27 +0100439 osmo_stats_vty_add_cmds();
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200440
Harald Weltefa7ee332018-06-24 13:20:32 +0200441 install_element_ve(&show_gsup_conn_cmd);
442
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200443 install_element(CONFIG_NODE, &cfg_hlr_cmd);
444 install_node(&hlr_node, config_write_hlr);
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200445
446 install_element(HLR_NODE, &cfg_gsup_cmd);
447 install_node(&gsup_node, config_write_hlr_gsup);
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200448
449 install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200450
Neels Hofmeyr5857c592019-04-02 04:24:49 +0200451 install_element(HLR_NODE, &cfg_database_cmd);
452
Harald Welte4956ae12018-06-15 22:04:28 +0200453 install_element(HLR_NODE, &cfg_euse_cmd);
454 install_element(HLR_NODE, &cfg_no_euse_cmd);
455 install_node(&euse_node, config_write_euse);
Harald Weltedab544e2018-07-29 16:14:48 +0200456 install_element(HLR_NODE, &cfg_ussd_route_pfx_int_cmd);
457 install_element(HLR_NODE, &cfg_ussd_route_pfx_ext_cmd);
458 install_element(HLR_NODE, &cfg_ussd_no_route_pfx_cmd);
459 install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
460 install_element(HLR_NODE, &cfg_ussd_no_defaultroute_cmd);
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700461 install_element(HLR_NODE, &cfg_ncss_guard_timeout_cmd);
Oliver Smith851814a2019-01-11 15:30:21 +0100462 install_element(HLR_NODE, &cfg_store_imei_cmd);
463 install_element(HLR_NODE, &cfg_no_store_imei_cmd);
Oliver Smithc7f17872019-03-04 15:10:44 +0100464 install_element(HLR_NODE, &cfg_subscr_create_on_demand_cmd);
465 install_element(HLR_NODE, &cfg_no_subscr_create_on_demand_cmd);
Harald Welte4956ae12018-06-15 22:04:28 +0200466
Harald Welted5807b82018-07-29 12:27:41 +0200467 hlr_vty_subscriber_init();
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100468}