blob: f8cf852e093ebfaebd0ffaf565d22db75faa316e [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
Alexander Couzens268a33e2020-01-12 00:48:07 +010028#include <errno.h>
Alexander Couzens37f0b3a2023-04-11 19:28:36 +020029#include <string.h>
Alexander Couzens268a33e2020-01-12 00:48:07 +010030
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +020031#include <osmocom/core/talloc.h>
Alexander Couzens268a33e2020-01-12 00:48:07 +010032#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
Alexander Couzens37f0b3a2023-04-11 19:28:36 +020033#include <osmocom/gsm/apn.h>
34
Neels Hofmeyr7685a782017-01-30 23:30:26 +010035#include <osmocom/vty/vty.h>
Max20ddfdb2019-02-18 13:12:27 +010036#include <osmocom/vty/stats.h>
Neels Hofmeyr7685a782017-01-30 23:30:26 +010037#include <osmocom/vty/command.h>
38#include <osmocom/vty/logging.h>
Harald Welte7ee6e552018-02-14 00:52:05 +010039#include <osmocom/vty/misc.h>
Harald Weltefa7ee332018-06-24 13:20:32 +020040#include <osmocom/abis/ipa.h>
Neels Hofmeyr7685a782017-01-30 23:30:26 +010041
Neels Hofmeyr2f758032019-11-20 00:37:07 +010042#include <osmocom/hlr/db.h>
43#include <osmocom/hlr/hlr.h>
44#include <osmocom/hlr/hlr_vty.h>
45#include <osmocom/hlr/hlr_vty_subscr.h>
46#include <osmocom/hlr/hlr_ussd.h>
47#include <osmocom/hlr/gsup_server.h>
Neels Hofmeyr7685a782017-01-30 23:30:26 +010048
Alexander Couzens268a33e2020-01-12 00:48:07 +010049static const struct value_string gsm48_gmm_cause_vty_names[] = {
50 { GMM_CAUSE_IMSI_UNKNOWN, "imsi-unknown" },
51 { GMM_CAUSE_ILLEGAL_MS, "illegal-ms" },
52 { GMM_CAUSE_PLMN_NOTALLOWED, "plmn-not-allowed" },
53 { GMM_CAUSE_LA_NOTALLOWED, "la-not-allowed" },
54 { GMM_CAUSE_ROAMING_NOTALLOWED, "roaming-not-allowed" },
55 { GMM_CAUSE_NO_SUIT_CELL_IN_LA, "no-suitable-cell-in-la" },
56 { GMM_CAUSE_NET_FAIL, "net-fail" },
57 { GMM_CAUSE_CONGESTION, "congestion" },
58 { GMM_CAUSE_GSM_AUTH_UNACCEPT, "auth-unacceptable" },
59 { GMM_CAUSE_PROTO_ERR_UNSPEC, "proto-error-unspec" },
60 { 0, NULL },
61};
62
63/* TS 24.008 4.4.4.7 */
64static const struct value_string gsm48_gmm_cause_vty_descs[] = {
65 { GMM_CAUSE_IMSI_UNKNOWN, " #02: (IMSI unknown in HLR)" },
66 { GMM_CAUSE_ILLEGAL_MS, " #03 (Illegal MS)" },
67 { GMM_CAUSE_PLMN_NOTALLOWED, " #11: (PLMN not allowed)" },
68 { GMM_CAUSE_LA_NOTALLOWED, " #12: (Location Area not allowed)" },
69 { GMM_CAUSE_ROAMING_NOTALLOWED, " #13: (Roaming not allowed in this location area)" },
70 { GMM_CAUSE_NO_SUIT_CELL_IN_LA, " #15: (No Suitable Cells In Location Area [continue search in PLMN])." },
71 { GMM_CAUSE_NET_FAIL, " #17: (Network Failure)" },
72 { GMM_CAUSE_CONGESTION, " #22: (Congestion)" },
73 { GMM_CAUSE_GSM_AUTH_UNACCEPT, " #23: (GSM authentication unacceptable [UMTS])" },
74 { GMM_CAUSE_PROTO_ERR_UNSPEC, "#111: (Protocol error, unspecified)" },
75 { 0, NULL },
76};
77
78
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +020079struct cmd_node hlr_node = {
80 HLR_NODE,
81 "%s(config-hlr)# ",
82 1,
83};
84
85DEFUN(cfg_hlr,
86 cfg_hlr_cmd,
87 "hlr",
88 "Configure the HLR")
89{
90 vty->node = HLR_NODE;
91 return CMD_SUCCESS;
92}
93
94struct cmd_node gsup_node = {
95 GSUP_NODE,
96 "%s(config-hlr-gsup)# ",
97 1,
98};
99
100DEFUN(cfg_gsup,
101 cfg_gsup_cmd,
102 "gsup",
103 "Configure GSUP options")
104{
105 vty->node = GSUP_NODE;
106 return CMD_SUCCESS;
107}
108
Alexander Couzens37f0b3a2023-04-11 19:28:36 +0200109struct cmd_node ps_node = {
110 PS_NODE,
111 "%s(config-hlr-ps)# ",
112 1,
113};
114
115DEFUN(cfg_ps,
116 cfg_ps_cmd,
117 "ps",
118 "Configure the PS options")
119{
120 vty->node = PS_NODE;
121 return CMD_SUCCESS;
122}
123
124struct cmd_node ps_pdp_profiles_node = {
125 PS_PDP_PROFILES_NODE,
126 "%s(config-hlr-ps-pdp-profiles)# ",
127 1,
128};
129
130DEFUN(cfg_ps_pdp_profiles,
131 cfg_ps_pdp_profiles_cmd,
132 "pdp-profiles default",
133 "Define a PDP profile set.\n"
134 "Define the global default profile.\n")
135{
136 g_hlr->ps.pdp_profile.enabled = true;
137
138 vty->node = PS_PDP_PROFILES_NODE;
139 return CMD_SUCCESS;
140}
141
142DEFUN(cfg_no_ps_pdp_profiles,
143 cfg_no_ps_pdp_profiles_cmd,
144 "no pdp-profiles default",
145 NO_STR
146 "Delete PDP profile.\n"
147 "Unique identifier for this PDP profile set.\n")
148{
149 g_hlr->ps.pdp_profile.enabled = false;
150 return CMD_SUCCESS;
151}
152
153
154
155struct cmd_node ps_pdp_profiles_profile_node = {
156 PS_PDP_PROFILES_PROFILE_NODE,
157 "%s(config-hlr-ps-pdp-profile)# ",
158 1,
159};
160
161
162/* context_id == 0 means the slot is free */
163struct osmo_gsup_pdp_info *get_pdp_profile(uint8_t context_id)
164{
165 for (int i = 0; i < OSMO_GSUP_MAX_NUM_PDP_INFO; i++) {
166 struct osmo_gsup_pdp_info *info = &g_hlr->ps.pdp_profile.pdp_infos[i];
167 if (info->context_id == context_id)
168 return info;
169 }
170
171 return NULL;
172}
173
174struct osmo_gsup_pdp_info *create_pdp_profile(uint8_t context_id)
175{
176 struct osmo_gsup_pdp_info *info = get_pdp_profile(0);
177 if (!info)
178 return NULL;
179
180 memset(info, 0, sizeof(*info));
181 info->context_id = context_id;
182 info->have_info = 1;
183
184 g_hlr->ps.pdp_profile.num_pdp_infos++;
185 return info;
186}
187
188void destroy_pdp_profile(struct osmo_gsup_pdp_info *info)
189{
190 info->context_id = 0;
191 if (info->apn_enc)
192 talloc_free((void *) info->apn_enc);
193
194 g_hlr->ps.pdp_profile.num_pdp_infos--;
195 memset(info, 0, sizeof(*info));
196}
197
198DEFUN(cfg_ps_pdp_profiles_profile,
199 cfg_ps_pdp_profiles_profile_cmd,
200 "profile <1-10>",
201 "Configure a PDP profile\n"
202 "Unique PDP context identifier. The lowest profile will be used as default context.\n")
203{
204 struct osmo_gsup_pdp_info *info;
205 uint8_t context_id = atoi(argv[0]);
206
207 info = get_pdp_profile(context_id);
208 if (!info) {
209 info = create_pdp_profile(context_id);
210 if (!info) {
211 vty_out(vty, "Failed to create profile %d!%s", context_id, VTY_NEWLINE);
212 return CMD_ERR_INCOMPLETE;
213 }
214 }
215
216 vty->node = PS_PDP_PROFILES_PROFILE_NODE;
217 vty->index = info;
218 return CMD_SUCCESS;
219}
220
221DEFUN(cfg_no_ps_pdp_profiles_profile,
222 cfg_no_ps_pdp_profiles_profile_cmd,
223 "no profile <1-10>",
224 NO_STR
225 "Delete a PDP profile\n"
226 "Unique PDP context identifier. The lowest profile will be used as default context.\n")
227{
228 struct osmo_gsup_pdp_info *info;
229 uint8_t context_id = atoi(argv[0]);
230
231 info = get_pdp_profile(context_id);
232 if (info)
233 destroy_pdp_profile(info);
234
235 return CMD_SUCCESS;
236}
237
238DEFUN(cfg_ps_pdp_profile_apn, cfg_ps_pdp_profile_apn_cmd,
239 "apn ID",
240 "Configure the APN.\n"
241 "APN name or * for wildcard apn.\n")
242{
243 struct osmo_gsup_pdp_info *info = vty->index;
244 const char *apn_name = argv[0];
245
246 /* apn encoded takes one more byte than strlen() */
247 size_t apn_enc_len = strlen(apn_name) + 1;
248 uint8_t *apn_enc;
249 int ret;
250
251 if (apn_enc_len > APN_MAXLEN) {
252 vty_out(vty, "APN name is too long '%s'. Max is %d!%s", apn_name, APN_MAXLEN, VTY_NEWLINE);
253 return CMD_ERR_INCOMPLETE;
254 }
255
256 info->apn_enc = apn_enc = (uint8_t *) talloc_zero_size(g_hlr, apn_enc_len);
257 ret = info->apn_enc_len = osmo_apn_from_str(apn_enc, apn_enc_len, apn_name);
258 if (ret < 0) {
259 talloc_free(apn_enc);
260 info->apn_enc = NULL;
261 info->apn_enc_len = 0;
262 vty_out(vty, "Invalid APN name %s!", apn_name);
263 return CMD_WARNING;
264 }
265
266 return CMD_SUCCESS;
267}
268
269DEFUN(cfg_no_ps_pdp_profile_apn, cfg_no_ps_pdp_profile_apn_cmd,
270 "no apn",
271 NO_STR
272 "Delete the APN.\n")
273{
274 struct osmo_gsup_pdp_info *info = vty->index;
275 if (info->apn_enc) {
276 talloc_free((void *) info->apn_enc);
277 info->apn_enc = NULL;
278 info->apn_enc_len = 0;
279 }
280
281 return CMD_SUCCESS;
282}
283
284
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200285static int config_write_hlr(struct vty *vty)
286{
287 vty_out(vty, "hlr%s", VTY_NEWLINE);
Alexander Couzens268a33e2020-01-12 00:48:07 +0100288
289 if (g_hlr->reject_cause != GMM_CAUSE_IMSI_UNKNOWN)
290 vty_out(vty, " reject-cause not-found %s%s",
291 get_value_string_or_null(gsm48_gmm_cause_vty_names,
292 (uint32_t) g_hlr->reject_cause), VTY_NEWLINE);
293 if (g_hlr->no_proxy_reject_cause != GMM_CAUSE_IMSI_UNKNOWN)
294 vty_out(vty, " reject-cause no-proxy %s%s",
295 get_value_string_or_null(gsm48_gmm_cause_vty_names,
296 (uint32_t) g_hlr->no_proxy_reject_cause), VTY_NEWLINE);
Oliver Smith851814a2019-01-11 15:30:21 +0100297 if (g_hlr->store_imei)
298 vty_out(vty, " store-imei%s", VTY_NEWLINE);
Neels Hofmeyr5857c592019-04-02 04:24:49 +0200299 if (g_hlr->db_file_path && strcmp(g_hlr->db_file_path, HLR_DEFAULT_DB_FILE_PATH))
300 vty_out(vty, " database %s%s", g_hlr->db_file_path, VTY_NEWLINE);
Oliver Smithc7f17872019-03-04 15:10:44 +0100301 if (g_hlr->subscr_create_on_demand) {
302 const char *flags_str = "none";
303 uint8_t flags = g_hlr->subscr_create_on_demand_flags;
304 unsigned int rand_msisdn_len = g_hlr->subscr_create_on_demand_rand_msisdn_len;
305
306 if ((flags & DB_SUBSCR_FLAG_NAM_CS) && (flags & DB_SUBSCR_FLAG_NAM_PS))
307 flags_str = "cs+ps";
308 else if (flags & DB_SUBSCR_FLAG_NAM_CS)
309 flags_str = "cs";
310 else if (flags & DB_SUBSCR_FLAG_NAM_PS)
311 flags_str = "ps";
312
313 if (rand_msisdn_len)
314 vty_out(vty, " subscriber-create-on-demand %i %s%s", rand_msisdn_len, flags_str, VTY_NEWLINE);
315 else
316 vty_out(vty, " subscriber-create-on-demand no-msisdn %s%s", flags_str, VTY_NEWLINE);
317 }
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200318 return CMD_SUCCESS;
319}
320
321static int config_write_hlr_gsup(struct vty *vty)
322{
323 vty_out(vty, " gsup%s", VTY_NEWLINE);
324 if (g_hlr->gsup_bind_addr)
325 vty_out(vty, " bind ip %s%s", g_hlr->gsup_bind_addr, VTY_NEWLINE);
Keith649c3352021-02-26 01:05:31 +0100326 if (g_hlr->gsup_unit_name.serno)
327 vty_out(vty, " ipa-name %s%s", g_hlr->gsup_unit_name.serno, VTY_NEWLINE);
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200328 return CMD_SUCCESS;
329}
330
Alexander Couzens37f0b3a2023-04-11 19:28:36 +0200331static int config_write_hlr_ps(struct vty *vty)
332{
333 vty_out(vty, " ps%s", VTY_NEWLINE);
334 return CMD_SUCCESS;
335}
336
337static int config_write_hlr_ps_pdp_profiles(struct vty *vty)
338{
339 char apn[APN_MAXLEN + 1] = {};
340
341 if (!g_hlr->ps.pdp_profile.enabled)
342 return CMD_SUCCESS;
343
344 vty_out(vty, " pdp-profiles default%s", VTY_NEWLINE);
345 for (int i = 0; i < g_hlr->ps.pdp_profile.num_pdp_infos; i++) {
346 struct osmo_gsup_pdp_info *pdp_info = &g_hlr->ps.pdp_profile.pdp_infos[i];
347 if (!pdp_info->context_id)
348 continue;
349
350 vty_out(vty, " profile %d%s", pdp_info->context_id, VTY_NEWLINE);
351 if (!pdp_info->have_info)
352 continue;
353
354 if (pdp_info->apn_enc && pdp_info->apn_enc_len) {
355 osmo_apn_to_str(apn, pdp_info->apn_enc, pdp_info->apn_enc_len);
356 vty_out(vty, " apn %s%s", apn, VTY_NEWLINE);
357 }
358 }
359 return CMD_SUCCESS;
360}
361
Harald Weltefa7ee332018-06-24 13:20:32 +0200362static void show_one_conn(struct vty *vty, const struct osmo_gsup_conn *conn)
363{
364 const struct ipa_server_conn *isc = conn->conn;
365 char *name;
366 int rc;
367
368 rc = osmo_gsup_conn_ccm_get(conn, (uint8_t **) &name, IPAC_IDTAG_SERNR);
369 OSMO_ASSERT(rc);
370
Neels Hofmeyr3f9d1972019-12-12 04:04:53 +0100371 vty_out(vty, " '%s' from %s:%5u, CS=%u, PS=%u%s",
372 name, isc->addr, isc->port, conn->supports_cs, conn->supports_ps,
Harald Weltefa7ee332018-06-24 13:20:32 +0200373 VTY_NEWLINE);
374}
375
376DEFUN(show_gsup_conn, show_gsup_conn_cmd,
377 "show gsup-connections",
378 SHOW_STR "GSUP Connections from VLRs, SGSNs, EUSEs\n")
379{
380 struct osmo_gsup_server *gs = g_hlr->gs;
381 struct osmo_gsup_conn *conn;
382
383 llist_for_each_entry(conn, &gs->clients, list)
384 show_one_conn(vty, conn);
385
386 return CMD_SUCCESS;
387}
388
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200389DEFUN(cfg_hlr_gsup_bind_ip,
390 cfg_hlr_gsup_bind_ip_cmd,
391 "bind ip A.B.C.D",
392 "Listen/Bind related socket option\n"
393 IP_STR
394 "IPv4 Address to bind the GSUP interface to\n")
395{
396 if(g_hlr->gsup_bind_addr)
397 talloc_free(g_hlr->gsup_bind_addr);
398 g_hlr->gsup_bind_addr = talloc_strdup(g_hlr, argv[0]);
399
400 return CMD_SUCCESS;
401}
402
Neels Hofmeyr76328bd2019-11-20 03:35:37 +0100403DEFUN(cfg_hlr_gsup_ipa_name,
404 cfg_hlr_gsup_ipa_name_cmd,
405 "ipa-name NAME",
406 "Set the IPA name of this HLR, for proxying to remote HLRs\n"
407 "A globally unique name for this HLR. For example: PLMN + redundancy server number: HLR-901-70-0. "
408 "This name is used for GSUP routing and must be set if multiple HLRs interconnect (e.g. mslookup "
409 "for Distributed GSM).\n")
410{
411 if (vty->type != VTY_FILE) {
412 vty_out(vty, "gsup/ipa-name: The GSUP IPA name cannot be changed at run-time; "
Max53f60672022-09-18 20:51:23 +0700413 "It can only be set in the configuration file.%s", VTY_NEWLINE);
Neels Hofmeyr76328bd2019-11-20 03:35:37 +0100414 return CMD_WARNING;
415 }
416
417 g_hlr->gsup_unit_name.serno = talloc_strdup(g_hlr, argv[0]);
418 return CMD_SUCCESS;
419}
420
Harald Welte4956ae12018-06-15 22:04:28 +0200421/***********************************************************************
Harald Weltedab544e2018-07-29 16:14:48 +0200422 * USSD Entity
Harald Welte4956ae12018-06-15 22:04:28 +0200423 ***********************************************************************/
424
Harald Weltedab544e2018-07-29 16:14:48 +0200425#define USSD_STR "USSD Configuration\n"
426#define UROUTE_STR "Routing Configuration\n"
427#define PREFIX_STR "Prefix-Matching Route\n" "USSD Prefix\n"
Harald Welte4956ae12018-06-15 22:04:28 +0200428
Vadim Yanitskiydac855e2020-11-17 04:17:46 +0700429#define INT_CHOICE "(own-msisdn|own-imsi|test-idle)"
Harald Weltedab544e2018-07-29 16:14:48 +0200430#define INT_STR "Internal USSD Handler\n" \
431 "Respond with subscribers' own MSISDN\n" \
Vadim Yanitskiydac855e2020-11-17 04:17:46 +0700432 "Respond with subscribers' own IMSI\n" \
433 "Keep the session idle (useful for testing)\n"
Harald Weltedab544e2018-07-29 16:14:48 +0200434
435#define EXT_STR "External USSD Handler\n" \
436 "Name of External USSD Handler (IPA CCM ID)\n"
437
438DEFUN(cfg_ussd_route_pfx_int, cfg_ussd_route_pfx_int_cmd,
439 "ussd route prefix PREFIX internal " INT_CHOICE,
440 USSD_STR UROUTE_STR PREFIX_STR INT_STR)
441{
442 const struct hlr_iuse *iuse = iuse_find(argv[1]);
443 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
Harald Welte4956ae12018-06-15 22:04:28 +0200444 if (rt) {
445 vty_out(vty, "%% Cannot add [another?] route for prefix %s%s", argv[0], VTY_NEWLINE);
446 return CMD_WARNING;
447 }
Harald Weltedab544e2018-07-29 16:14:48 +0200448 ussd_route_prefix_alloc_int(g_hlr, argv[0], iuse);
Harald Welte4956ae12018-06-15 22:04:28 +0200449
450 return CMD_SUCCESS;
451}
452
Harald Weltedab544e2018-07-29 16:14:48 +0200453DEFUN(cfg_ussd_route_pfx_ext, cfg_ussd_route_pfx_ext_cmd,
454 "ussd route prefix PREFIX external EUSE",
455 USSD_STR UROUTE_STR PREFIX_STR EXT_STR)
Harald Welte4956ae12018-06-15 22:04:28 +0200456{
Harald Weltedab544e2018-07-29 16:14:48 +0200457 struct hlr_euse *euse = euse_find(g_hlr, argv[1]);
458 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
459 if (rt) {
460 vty_out(vty, "%% Cannot add [another?] route for prefix %s%s", argv[0], VTY_NEWLINE);
461 return CMD_WARNING;
462 }
463 if (!euse) {
464 vty_out(vty, "%% Cannot find euse '%s'%s", argv[1], VTY_NEWLINE);
465 return CMD_WARNING;
466 }
467 ussd_route_prefix_alloc_ext(g_hlr, argv[0], euse);
468
469 return CMD_SUCCESS;
470}
471
472DEFUN(cfg_ussd_no_route_pfx, cfg_ussd_no_route_pfx_cmd,
473 "no ussd route prefix PREFIX",
474 NO_STR USSD_STR UROUTE_STR PREFIX_STR)
475{
476 struct hlr_ussd_route *rt = ussd_route_find_prefix(g_hlr, argv[0]);
Harald Welte4956ae12018-06-15 22:04:28 +0200477 if (!rt) {
478 vty_out(vty, "%% Cannot find route for prefix %s%s", argv[0], VTY_NEWLINE);
479 return CMD_WARNING;
480 }
Harald Weltedab544e2018-07-29 16:14:48 +0200481 ussd_route_del(rt);
Harald Welte4956ae12018-06-15 22:04:28 +0200482
483 return CMD_SUCCESS;
484}
485
Harald Weltedab544e2018-07-29 16:14:48 +0200486DEFUN(cfg_ussd_defaultroute, cfg_ussd_defaultroute_cmd,
487 "ussd default-route external EUSE",
488 USSD_STR "Configure default-route for all USSD to unknown destinations\n"
489 EXT_STR)
Harald Welte4956ae12018-06-15 22:04:28 +0200490{
Vadim Yanitskiyb93c44f2018-08-02 23:37:51 +0700491 struct hlr_euse *euse;
492
493 euse = euse_find(g_hlr, argv[0]);
494 if (!euse) {
495 vty_out(vty, "%% Cannot find EUSE %s%s", argv[0], VTY_NEWLINE);
496 return CMD_WARNING;
497 }
Harald Welte4956ae12018-06-15 22:04:28 +0200498
499 if (g_hlr->euse_default != euse) {
500 vty_out(vty, "Switching default route from %s to %s%s",
Harald Welte55d32a12018-07-30 17:26:35 +0200501 g_hlr->euse_default ? g_hlr->euse_default->name : "<none>",
502 euse->name, VTY_NEWLINE);
Harald Welte4956ae12018-06-15 22:04:28 +0200503 g_hlr->euse_default = euse;
504 }
505
506 return CMD_SUCCESS;
507}
508
Harald Weltedab544e2018-07-29 16:14:48 +0200509DEFUN(cfg_ussd_no_defaultroute, cfg_ussd_no_defaultroute_cmd,
510 "no ussd default-route",
511 NO_STR USSD_STR "Remove the default-route for all USSD to unknown destinations\n")
Harald Welte4956ae12018-06-15 22:04:28 +0200512{
Harald Welte4956ae12018-06-15 22:04:28 +0200513 g_hlr->euse_default = NULL;
514
515 return CMD_SUCCESS;
516}
517
Neels Hofmeyr5857c592019-04-02 04:24:49 +0200518DEFUN(cfg_database, cfg_database_cmd,
519 "database PATH",
520 "Set the path to the HLR database file\n"
521 "Relative or absolute file system path to the database file (default is '" HLR_DEFAULT_DB_FILE_PATH "')\n")
522{
523 osmo_talloc_replace_string(g_hlr, &g_hlr->db_file_path, argv[0]);
524 return CMD_SUCCESS;
525}
526
Harald Welte4956ae12018-06-15 22:04:28 +0200527struct cmd_node euse_node = {
528 EUSE_NODE,
529 "%s(config-hlr-euse)# ",
530 1,
531};
532
533DEFUN(cfg_euse, cfg_euse_cmd,
534 "euse NAME",
535 "Configure a particular External USSD Entity\n"
536 "Alphanumeric name of the External USSD Entity\n")
537{
538 struct hlr_euse *euse;
539 const char *id = argv[0];
540
541 euse = euse_find(g_hlr, id);
542 if (!euse) {
543 euse = euse_alloc(g_hlr, id);
544 if (!euse)
545 return CMD_WARNING;
546 }
547 vty->index = euse;
548 vty->index_sub = &euse->description;
549 vty->node = EUSE_NODE;
550
551 return CMD_SUCCESS;
552}
553
554DEFUN(cfg_no_euse, cfg_no_euse_cmd,
555 "no euse NAME",
556 NO_STR "Remove a particular External USSD Entity\n"
557 "Alphanumeric name of the External USSD Entity\n")
558{
559 struct hlr_euse *euse = euse_find(g_hlr, argv[0]);
560 if (!euse) {
Vadim Yanitskiyc47d5c02020-10-29 18:05:22 +0700561 vty_out(vty, "%% Cannot remove non-existent EUSE %s%s", argv[0], VTY_NEWLINE);
Harald Welte4956ae12018-06-15 22:04:28 +0200562 return CMD_WARNING;
563 }
564 if (g_hlr->euse_default == euse) {
565 vty_out(vty, "%% Cannot remove EUSE %s, it is the default route%s", argv[0], VTY_NEWLINE);
566 return CMD_WARNING;
567 }
568 euse_del(euse);
569 return CMD_SUCCESS;
570}
571
572static void dump_one_euse(struct vty *vty, struct hlr_euse *euse)
573{
Harald Welte4956ae12018-06-15 22:04:28 +0200574 vty_out(vty, " euse %s%s", euse->name, VTY_NEWLINE);
Harald Welte4956ae12018-06-15 22:04:28 +0200575}
576
577static int config_write_euse(struct vty *vty)
578{
579 struct hlr_euse *euse;
Harald Weltedab544e2018-07-29 16:14:48 +0200580 struct hlr_ussd_route *rt;
Harald Welte4956ae12018-06-15 22:04:28 +0200581
582 llist_for_each_entry(euse, &g_hlr->euse_list, list)
583 dump_one_euse(vty, euse);
584
Harald Weltedab544e2018-07-29 16:14:48 +0200585 llist_for_each_entry(rt, &g_hlr->ussd_routes, list) {
586 vty_out(vty, " ussd route prefix %s %s %s%s", rt->prefix,
587 rt->is_external ? "external" : "internal",
588 rt->is_external ? rt->u.euse->name : rt->u.iuse->name,
589 VTY_NEWLINE);
590 }
591
592 if (g_hlr->euse_default)
593 vty_out(vty, " ussd default-route external %s%s", g_hlr->euse_default->name, VTY_NEWLINE);
594
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700595 if (g_hlr->ncss_guard_timeout != NCSS_GUARD_TIMEOUT_DEFAULT)
596 vty_out(vty, " ncss-guard-timeout %i%s",
597 g_hlr->ncss_guard_timeout, VTY_NEWLINE);
598
Harald Welte4956ae12018-06-15 22:04:28 +0200599 return 0;
600}
601
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700602DEFUN(cfg_ncss_guard_timeout, cfg_ncss_guard_timeout_cmd,
603 "ncss-guard-timeout <0-255>",
604 "Set guard timer for NCSS (call independent SS) session activity\n"
605 "Guard timer value (sec.), or 0 to disable")
606{
607 g_hlr->ncss_guard_timeout = atoi(argv[0]);
608 return CMD_SUCCESS;
609}
610
Alexander Couzens268a33e2020-01-12 00:48:07 +0100611
612DEFUN(cfg_reject_cause, cfg_reject_cause_cmd,
613 "reject-cause TYPE CAUSE", "") /* Dynamically Generated */
614{
615 int cause_code = get_string_value(gsm48_gmm_cause_vty_names, argv[1]);
616 OSMO_ASSERT(cause_code >= 0);
617
618 if (strcmp(argv[0], "not-found") == 0)
619 g_hlr->reject_cause = (enum gsm48_gmm_cause) cause_code;
620 if (strcmp(argv[0], "no-proxy") == 0)
621 g_hlr->no_proxy_reject_cause = (enum gsm48_gmm_cause) cause_code;
622
623 return CMD_SUCCESS;
624}
625
Oliver Smith851814a2019-01-11 15:30:21 +0100626DEFUN(cfg_store_imei, cfg_store_imei_cmd,
627 "store-imei",
628 "Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send"
629 " Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1').")
630{
631 g_hlr->store_imei = true;
632 return CMD_SUCCESS;
633}
634
635DEFUN(cfg_no_store_imei, cfg_no_store_imei_cmd,
636 "no store-imei",
637 "Do not save the IMEI in the database, when receiving Check IMEI requests.")
638{
639 g_hlr->store_imei = false;
640 return CMD_SUCCESS;
641}
642
Oliver Smithc7f17872019-03-04 15:10:44 +0100643DEFUN(cfg_subscr_create_on_demand, cfg_subscr_create_on_demand_cmd,
644 "subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps)",
645 "Make a new record when a subscriber is first seen.\n"
646 "Do not automatically assign MSISDN.\n"
647 "Length of an automatically assigned MSISDN.\n"
648 "Do not allow any NAM (Network Access Mode) by default.\n"
649 "Allow access to circuit switched NAM by default.\n"
650 "Allow access to packet switched NAM by default.\n"
651 "Allow access to circuit and packet switched NAM by default.\n")
652{
653 unsigned int rand_msisdn_len = 0;
654 uint8_t flags = 0x00;
655
656 if (strcmp(argv[0], "no-msisdn") != 0)
657 rand_msisdn_len = atoi(argv[0]);
658
659 if (strstr(argv[1], "cs"))
660 flags |= DB_SUBSCR_FLAG_NAM_CS;
661 if (strstr(argv[1], "ps"))
662 flags |= DB_SUBSCR_FLAG_NAM_PS;
663
664 g_hlr->subscr_create_on_demand = true;
665 g_hlr->subscr_create_on_demand_rand_msisdn_len = rand_msisdn_len;
666 g_hlr->subscr_create_on_demand_flags = flags;
667
668 return CMD_SUCCESS;
669}
670
671DEFUN(cfg_no_subscr_create_on_demand, cfg_no_subscr_create_on_demand_cmd,
672 "no subscriber-create-on-demand",
673 "Do not make a new record when a subscriber is first seen.\n")
674{
675 g_hlr->subscr_create_on_demand = false;
676 return CMD_SUCCESS;
677}
678
Harald Welte4956ae12018-06-15 22:04:28 +0200679/***********************************************************************
680 * Common Code
681 ***********************************************************************/
682
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200683int hlr_vty_go_parent(struct vty *vty)
684{
685 switch (vty->node) {
686 case GSUP_NODE:
Harald Welte4956ae12018-06-15 22:04:28 +0200687 case EUSE_NODE:
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200688 vty->node = HLR_NODE;
689 vty->index = NULL;
Harald Welte4956ae12018-06-15 22:04:28 +0200690 vty->index_sub = NULL;
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200691 break;
692 default:
693 case HLR_NODE:
694 vty->node = CONFIG_NODE;
695 vty->index = NULL;
696 break;
697 case CONFIG_NODE:
698 vty->node = ENABLE_NODE;
699 vty->index = NULL;
700 break;
701 }
702
703 return vty->node;
704}
705
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100706int hlr_vty_is_config_node(struct vty *vty, int node)
707{
708 switch (node) {
709 /* add items that are not config */
710 case CONFIG_NODE:
711 return 0;
712
713 default:
714 return 1;
715 }
716}
717
Alexander Couzens268a33e2020-01-12 00:48:07 +0100718void hlr_vty_init(void *hlr_ctx)
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100719{
Alexander Couzens268a33e2020-01-12 00:48:07 +0100720 cfg_reject_cause_cmd.string =
721 vty_cmd_string_from_valstr(hlr_ctx,
722 gsm48_gmm_cause_vty_names,
723 "reject-cause (not-found|no-proxy) (", "|", ")",
724 VTY_DO_LOWER);
725
726 cfg_reject_cause_cmd.doc =
727 vty_cmd_string_from_valstr(hlr_ctx,
728 gsm48_gmm_cause_vty_descs,
729 "GSUP/GMM cause to be sent\n"
730 "in the case the IMSI could not be found in the database\n"
731 "in the case no remote HLR reponded to mslookup GSUP request\n",
732 "\n", "", 0);
733
Pau Espin Pedrole49391b2019-08-05 15:57:10 +0200734 logging_vty_add_cmds();
Harald Welte7ee6e552018-02-14 00:52:05 +0100735 osmo_talloc_vty_add_cmds();
Max20ddfdb2019-02-18 13:12:27 +0100736 osmo_stats_vty_add_cmds();
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200737
Harald Weltefa7ee332018-06-24 13:20:32 +0200738 install_element_ve(&show_gsup_conn_cmd);
739
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200740 install_element(CONFIG_NODE, &cfg_hlr_cmd);
741 install_node(&hlr_node, config_write_hlr);
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200742
743 install_element(HLR_NODE, &cfg_gsup_cmd);
744 install_node(&gsup_node, config_write_hlr_gsup);
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200745
746 install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
Neels Hofmeyr76328bd2019-11-20 03:35:37 +0100747 install_element(GSUP_NODE, &cfg_hlr_gsup_ipa_name_cmd);
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200748
Alexander Couzens37f0b3a2023-04-11 19:28:36 +0200749 /* PS */
750 install_node(&ps_node, config_write_hlr_ps);
751 install_element(HLR_NODE, &cfg_ps_cmd);
752
753 install_node(&ps_pdp_profiles_node, config_write_hlr_ps_pdp_profiles);
754 install_element(PS_NODE, &cfg_ps_pdp_profiles_cmd);
755 install_element(PS_NODE, &cfg_no_ps_pdp_profiles_cmd);
756
757 install_node(&ps_pdp_profiles_profile_node, NULL);
758 install_element(PS_PDP_PROFILES_NODE, &cfg_ps_pdp_profiles_profile_cmd);
759 install_element(PS_PDP_PROFILES_NODE, &cfg_no_ps_pdp_profiles_profile_cmd);
760 install_element(PS_PDP_PROFILES_PROFILE_NODE, &cfg_ps_pdp_profile_apn_cmd);
761 install_element(PS_PDP_PROFILES_PROFILE_NODE, &cfg_no_ps_pdp_profile_apn_cmd);
762
Neels Hofmeyr5857c592019-04-02 04:24:49 +0200763 install_element(HLR_NODE, &cfg_database_cmd);
764
Harald Welte4956ae12018-06-15 22:04:28 +0200765 install_element(HLR_NODE, &cfg_euse_cmd);
766 install_element(HLR_NODE, &cfg_no_euse_cmd);
767 install_node(&euse_node, config_write_euse);
Harald Weltedab544e2018-07-29 16:14:48 +0200768 install_element(HLR_NODE, &cfg_ussd_route_pfx_int_cmd);
769 install_element(HLR_NODE, &cfg_ussd_route_pfx_ext_cmd);
770 install_element(HLR_NODE, &cfg_ussd_no_route_pfx_cmd);
771 install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
772 install_element(HLR_NODE, &cfg_ussd_no_defaultroute_cmd);
Vadim Yanitskiyd157a562018-12-01 00:03:39 +0700773 install_element(HLR_NODE, &cfg_ncss_guard_timeout_cmd);
Alexander Couzens268a33e2020-01-12 00:48:07 +0100774 install_element(HLR_NODE, &cfg_reject_cause_cmd);
Oliver Smith851814a2019-01-11 15:30:21 +0100775 install_element(HLR_NODE, &cfg_store_imei_cmd);
776 install_element(HLR_NODE, &cfg_no_store_imei_cmd);
Oliver Smithc7f17872019-03-04 15:10:44 +0100777 install_element(HLR_NODE, &cfg_subscr_create_on_demand_cmd);
778 install_element(HLR_NODE, &cfg_no_subscr_create_on_demand_cmd);
Harald Welte4956ae12018-06-15 22:04:28 +0200779
Harald Welted5807b82018-07-29 12:27:41 +0200780 hlr_vty_subscriber_init();
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100781}