Compare commits

..

14 Commits

Author SHA1 Message Date
Harald Welte
e6f695e0e6 SS/USSD: implement basic USSE routing configuration for VTY
This change introduces basic Unstructured Supplementary Services
processing Entity (USSE) configuration for VTY by analogy with
ESME and SMPP.

The configuration is done by allocating USSE nodes, so each one
is bound to a particular GSUP-connection, and represents a single
processing entity. Then, one or more USSD-code matching patterns
(e.g. code, prefix, regexp) can be assigned to a particular USSE
node, so all matched USSD-requests will be handled by this node.

Among all other USSE nodes, which are basically External USSEs,
there is a special one called IUSSE - internal USSD handler.
It can be optionally configured to handle and answer simple
requests, like *#100#.

Also, it's possible to set the default USSE, which will handle
all USSD-requests unmatched by other USSEs. Otherwise,
unmatched requests are being rejected.

Change-Id: I3cfd7cd401ea32b7e92f1124d129099d9f7dc6e6
2018-07-29 23:17:59 +07:00
Harald Welte
35d2342850 Store identity of VLR/SGSN in UpdateLocation
The HLR must store the least-recently used VLR and SGSN identities in
its database to ensure subsequent mobile-terminated transactions can
be routed accordingly.

Change-Id: Ib2611421f3638eadc361787af801fffe9a34bd8a
Closes: OS#2796
2018-07-06 06:50:23 +07:00
Pau Espin Pedrol
6b274b95fc sql/Makefile: Create empty /var/lib/osmocom directory at install time
Otherwise osmo-hlr is unable to start correctly.

Change-Id: I1233fc9b3dc685561f79a34e1c32c459dc1aa685
2018-07-02 17:47:24 +02:00
Pau Espin Pedrol
edca4f88a6 sql/Makefile: Install sql files under doc/.../sql subdir
Change-Id: I1c9008d4692412a0cfe39d05216fc9c857cf1e8a
2018-07-02 17:44:35 +02:00
Pau Espin Pedrol
b9c1028cb0 sql/Makefile: Install hlr_data.sql as example together with hlr.sql
Change-Id: Id4a12252b309f03bb393fa26612c305744e14403
2018-07-02 17:27:44 +02:00
Pau Espin Pedrol
1442e3a3d3 debian: Avoid installing duplicate cfg file in /etc
Change-Id: Ieb25cc8195a2fe7f81b7a39955e0bca5d5c510eb
2018-07-02 17:15:13 +02:00
Martin Hauke
0b8f054b5f sql/Makefile.am: Make docsdir completely configurable
$(docdir) defaults to $(datadir)/doc/osmo-hlr

Change-Id: I77fa16d0edcf88a8e120921504cd088328077836
2018-06-24 17:14:04 +00:00
Harald Welte
fa7ee333f7 Add "show gsup-connections" VTY command
This can help with debugging and give operational insight.

Change-Id: I977b4b8cdb36dab42b3d736a28d8b5f17cff04cd
2018-06-24 14:06:56 +02:00
Harald Welte
8fbf82b83f gsup_router: Use "#pragma once" and add missing #includes
Change-Id: I2cc43ea5846e5b98281efc897252c8dcc3ef5728
2018-06-24 11:49:16 +02:00
Harald Welte
bd72f1331d move osmo_gsup_addr_send() declaration from luop.h to gsup_router.h
Change-Id: I33165b7b58bd8c863083ed50ce21e3c032c579f5
2018-06-24 11:49:13 +02:00
Harald Welte
32acace879 gsup_server: Add "priv" pointer and make it point to 'struct hlr'
Change-Id: Iada68996b7f4cbdcca92b254ddaf6b88b962e6f1
2018-06-16 20:21:45 +02:00
Harald Welte
b85f60477f disable blind subscriber insertion into every VLR/SGSN
During the attempt to fix OS#2785 in Change-Id
I6a92ca34cdaadca9eacc774bb1ca386c325ba865, we introduced logic that
would blindly insert a subscriber *concurrently* in all VLRs/SGSNs of
the network on any update of the subscriber.

Before that patch, we didn't update the current serving SGSN/VLR,
and after the change we created subscribers in all SGSNs/VLRs, of which
all-1 are not serving the subscriber at that time.

We'll have to go back to the original behavior until a proper fix can
be introduced.

Change-Id: Ibf6f1b21b08560d4d8f41bbe7782d40abf4585f8
Related: OS#3091
Related: OS#2785
2018-06-15 18:01:14 +02:00
Harald Welte
a1d3b048fb Return proper GSUP error in case of too short IMSI
This fixes HLR_Tests.TC_gsup_sai_err_invalid_imsi

Change-Id: I4f51abdf44dfc62d7e8792341aad6dafe58923da
Closes: OS#3028
2018-06-11 20:28:35 +02:00
Stefan Sperling
f83432c25c move creation of insert subscriber data messages to a common function
Move code to create an Insert Subscriber Data message into a common
function which can be shared by hlr.c and luop.c.

As a consequence, we always encode gsup.cn_domain in the corresponding
msgb and must adjust expected output of the 'gsup' test accordingly.

Change-Id: I6a92ca34cdaadca9eacc774bb1ca386c325ba865
Requested-by: neels
Related: OS#2785
2018-05-18 12:18:32 +02:00
18 changed files with 983 additions and 82 deletions

View File

@@ -1,5 +1,6 @@
/usr/bin/osmo-hlr
/usr/bin/osmo-hlr-db-tool
/usr/share/doc/osmo-hlr/hlr.sql
/usr/share/doc/osmo-hlr/sql/hlr.sql
/usr/share/doc/osmo-hlr/sql/hlr_data.sql
/usr/share/doc/osmo-hlr/examples/osmo-hlr.cfg
/usr/share/doc/osmo-hlr/examples/osmo-hlr.cfg /etc/osmocom/
/var/lib/osmocom

View File

@@ -3,5 +3,12 @@ EXTRA_DIST = \
hlr.sql \
$(NULL)
docsdir = $(datadir)/doc/osmo-hlr
docs_DATA = $(srcdir)/hlr.sql
sqldir = $(docdir)/sql
sql_DATA = $(srcdir)/hlr.sql $(srcdir)/hlr_data.sql
install-data-local:
$(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/osmocom
uninstall-hook:
rm -rf $(DESTDIR)$(localstatedir)/lib/osmocom

View File

@@ -30,6 +30,7 @@ noinst_HEADERS = \
ctrl.h \
hlr_vty.h \
hlr_vty_subscr.h \
hlr_ss_ussd.h \
db_bootstrap.h \
$(NULL)
@@ -53,6 +54,7 @@ osmo_hlr_SOURCES = \
hlr_vty.c \
hlr_vty_subscr.c \
gsup_send.c \
hlr_ss_ussd.c \
$(NULL)
osmo_hlr_LDADD = \

View File

@@ -1,3 +1,8 @@
#pragma once
#include <stdint.h>
#include "gsup_server.h"
struct osmo_gsup_conn *gsup_route_find(struct osmo_gsup_server *gs,
const uint8_t *addr, size_t addrlen);
@@ -6,3 +11,7 @@ int gsup_route_add(struct osmo_gsup_conn *conn, const uint8_t *addr, size_t addr
/* delete all routes for the given connection */
int gsup_route_del_conn(struct osmo_gsup_conn *conn);
int osmo_gsup_addr_send(struct osmo_gsup_server *gs,
const uint8_t *addr, size_t addrlen,
struct msgb *msg);

View File

@@ -24,6 +24,7 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/abis/ipa.h>
#include <osmocom/abis/ipaccess.h>
#include <osmocom/gsm/gsm48_ie.h>
#include <osmocom/gsm/apn.h>
#include "gsup_server.h"
@@ -291,7 +292,7 @@ failed:
struct osmo_gsup_server *
osmo_gsup_server_create(void *ctx, const char *ip_addr, uint16_t tcp_port,
osmo_gsup_read_cb_t read_cb,
struct llist_head *lu_op_lst)
struct llist_head *lu_op_lst, void *priv)
{
struct osmo_gsup_server *gsups;
int rc;
@@ -311,6 +312,7 @@ osmo_gsup_server_create(void *ctx, const char *ip_addr, uint16_t tcp_port,
goto failed;
gsups->read_cb = read_cb;
gsups->priv = priv;
rc = ipa_server_link_open(gsups->link);
if (rc < 0)
@@ -357,3 +359,56 @@ int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup,
return 0;
}
/**
* Populate a gsup message structure with an Insert Subscriber Data Message.
* All required memory buffers for data pointed to by pointers in struct omso_gsup_message
* must be allocated by the caller and should have the same lifetime as the gsup parameter.
*
* \param[out] gsup The gsup message to populate.
* \param[in] imsi The subscriber's IMSI.
* \param[in] msisdn The subscriber's MSISDN.
* \param[out] msisdn_enc A buffer large enough to store the MSISDN in encoded form.
* \param[in] msisdn_enc_size Size of the buffer (must be >= OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN).
* \param[out] apn_buf A buffer large enough to store an APN (required if cn_domain is OSMO_GSUP_CN_DOMAIN_PS).
* \param[in] apn_buf_size Size of APN buffer (must be >= APN_MAXLEN).
* \param[in] cn_domain The CN Domain of the subscriber connection.
* \returns 0 on success, and negative on error.
*/
int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,
uint8_t *msisdn_enc, size_t msisdn_enc_size,
uint8_t *apn_buf, size_t apn_buf_size,
enum osmo_gsup_cn_domain cn_domain)
{
int len;
OSMO_ASSERT(gsup);
gsup->message_type = OSMO_GSUP_MSGT_INSERT_DATA_REQUEST;
osmo_strlcpy(gsup->imsi, imsi, sizeof(gsup->imsi));
if (msisdn_enc_size < OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN)
return -ENOSPC;
OSMO_ASSERT(msisdn_enc);
len = gsm48_encode_bcd_number(msisdn_enc, msisdn_enc_size, 0, msisdn);
if (len < 1) {
LOGP(DLGSUP, LOGL_ERROR, "%s: Error: cannot encode MSISDN '%s'\n", imsi, msisdn);
return -ENOSPC;
}
gsup->msisdn_enc = msisdn_enc;
gsup->msisdn_enc_len = len;
#pragma message "FIXME: deal with encoding the following data: gsup.hlr_enc"
gsup->cn_domain = cn_domain;
if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS) {
OSMO_ASSERT(apn_buf_size >= APN_MAXLEN);
OSMO_ASSERT(apn_buf);
/* FIXME: PDP infos - use more fine-grained access control
instead of wildcard APN */
osmo_gsup_configure_wildcard_apn(gsup, apn_buf, apn_buf_size);
}
return 0;
}

View File

@@ -6,12 +6,19 @@
#include <osmocom/abis/ipaccess.h>
#include <osmocom/gsm/gsup.h>
#ifndef OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN
#define OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN 43 /* TS 24.008 10.5.4.7 */
#endif
struct osmo_gsup_conn;
/* Expects message in msg->l2h */
typedef int (*osmo_gsup_read_cb_t)(struct osmo_gsup_conn *conn, struct msgb *msg);
struct osmo_gsup_server {
/* private data of the application/user */
void *priv;
/* list of osmo_gsup_conn */
struct llist_head clients;
@@ -49,9 +56,14 @@ struct osmo_gsup_server *osmo_gsup_server_create(void *ctx,
const char *ip_addr,
uint16_t tcp_port,
osmo_gsup_read_cb_t read_cb,
struct llist_head *lu_op_lst);
struct llist_head *lu_op_lst,
void *priv);
void osmo_gsup_server_destroy(struct osmo_gsup_server *gsups);
int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup,
uint8_t *apn_buf, size_t apn_buf_size);
int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,
uint8_t *msisdn_enc, size_t msisdn_enc_size,
uint8_t *apn_buf, size_t apn_buf_size,
enum osmo_gsup_cn_domain cn_domain);

121
src/hlr.c
View File

@@ -26,7 +26,6 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/application.h>
#include <osmocom/gsm/gsup.h>
#include <osmocom/gsm/gsm48_ie.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/telnet_interface.h>
@@ -43,73 +42,56 @@
#include "rand.h"
#include "luop.h"
#include "hlr_vty.h"
#include "hlr_ss_ussd.h"
static struct hlr *g_hlr;
/* Trigger 'Insert Subscriber Data' messages to all connected GSUP clients.
*
* FIXME: In order to support large-scale networks this function should skip
* VLRs/SGSNs which do not currently serve the subscriber.
*
* \param[in] subscr A subscriber we have new data to send for.
*/
void
osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
{
/* FIXME: the below code can only be re-enabled after we make sure that an ISD
* is only sent tot the currently serving VLR and/or SGSN (if there are any).
* We cannot blindly flood the entire PLMN with this, as it would create subscriber
* state in every VLR/SGSN out there, even those that have never seen the subscriber.
* See https://osmocom.org/issues/3154 for details. */
#if 0
struct osmo_gsup_conn *co;
if (g_hlr->gs == NULL)
return;
llist_for_each_entry(co, &g_hlr->gs->clients, list) {
struct osmo_gsup_message gsup = {
.message_type = OSMO_GSUP_MSGT_INSERT_DATA_REQUEST
};
struct osmo_gsup_message gsup = { };
uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];
uint8_t apn[APN_MAXLEN];
struct msgb *msg_out;
uint8_t *peer;
int peer_len;
uint8_t msisdn_enc[43]; /* TODO use constant; TS 24.008 10.5.4.7 */
uint8_t apn[APN_MAXLEN];
int len;
struct msgb *msg_out;
enum osmo_gsup_cn_domain cn_domain;
peer_len = osmo_gsup_conn_ccm_get(co, &peer, IPAC_IDTAG_SERNR);
if (peer_len < 0) {
if (co->supports_ps)
cn_domain = OSMO_GSUP_CN_DOMAIN_PS;
else if (co->supports_cs)
cn_domain = OSMO_GSUP_CN_DOMAIN_CS;
else {
/* We have not yet received a location update from this subscriber .*/
continue;
}
if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi, subscr->msisdn, msisdn_enc,
sizeof(msisdn_enc), apn, sizeof(apn), cn_domain) != 0) {
LOGP(DMAIN, LOGL_ERROR,
"IMSI='%s': Cannot notify GSUP client, cannot get peer name "
"IMSI='%s': Cannot notify GSUP client; could not create gsup message "
"for %s:%u\n", subscr->imsi,
co && co->conn && co->conn->server? co->conn->server->addr : "unset",
co && co->conn && co->conn->server? co->conn->server->port : 0);
continue;
}
osmo_strlcpy(gsup.imsi, subscr->imsi, GSM23003_IMSI_MAX_DIGITS + 1);
len = gsm48_encode_bcd_number(msisdn_enc, sizeof(msisdn_enc), 0, subscr->msisdn);
if (len < 1) {
LOGP(DMAIN, LOGL_ERROR, "%s: Error: cannot encode MSISDN '%s'\n",
subscr->imsi, subscr->msisdn);
continue;
}
gsup.msisdn_enc = msisdn_enc;
gsup.msisdn_enc_len = len;
if (co->supports_ps) {
gsup.cn_domain = OSMO_GSUP_CN_DOMAIN_PS;
/* FIXME: PDP infos - use more fine-grained access control
instead of wildcard APN */
if (osmo_gsup_configure_wildcard_apn(&gsup, apn, sizeof(apn))) {
LOGP(DMAIN, LOGL_ERROR, "%s: Error: cannot encode wildcard APN\n",
subscr->imsi);
continue;
}
} else if (co->supports_cs) {
gsup.cn_domain = OSMO_GSUP_CN_DOMAIN_CS;
} else {
/* We have not yet received a location update from this subscriber .*/
continue;
}
/* Send ISD to MSC/SGSN */
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP ISD UPDATE");
if (msg_out == NULL) {
@@ -120,8 +102,17 @@ osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
co && co->conn && co->conn->server? co->conn->server->port : 0);
continue;
}
osmo_gsup_encode(msg_out, &gsup);
peer_len = osmo_gsup_conn_ccm_get(co, &peer, IPAC_IDTAG_SERNR);
if (peer_len < 0) {
LOGP(DMAIN, LOGL_ERROR,
"IMSI='%s': cannot get peer name for connection %s:%u\n", subscr->imsi,
co && co->conn && co->conn->server? co->conn->server->addr : "unset",
co && co->conn && co->conn->server? co->conn->server->port : 0);
continue;
}
if (osmo_gsup_addr_send(g_hlr->gs, peer, peer_len, msg_out) < 0) {
LOGP(DMAIN, LOGL_ERROR,
"IMSI='%s': Cannot notify GSUP client; send operation failed "
@@ -131,6 +122,7 @@ osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
continue;
}
}
#endif
}
/***********************************************************************
@@ -305,10 +297,19 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
} else
#endif
{
int rc;
uint8_t *addr;
rc = osmo_gsup_conn_ccm_get(conn, &addr, IPAC_IDTAG_SERNR);
if (rc <= 0) {
osmo_strlcpy(luop->subscr.imsi, gsup->imsi, sizeof(luop->subscr.imsi));
lu_op_tx_error(luop, GMM_CAUSE_NET_FAIL);
return 0;
}
/* TODO: Subscriber allowed to roam in PLMN? */
/* TODO: Update RoutingInfo */
/* TODO: Reset Flag MS Purged (cs/ps) */
/* TODO: Control_Tracing_HLR / Control_Tracing_HLR_with_SGSN */
db_subscr_lu(g_hlr->dbc, luop->subscr.id, (char *)addr, luop->is_ps);
lu_op_tx_insert_subscr_data(luop);
}
return 0;
@@ -351,6 +352,29 @@ static int rx_purge_ms_req(struct osmo_gsup_conn *conn,
return osmo_gsup_conn_send(conn, msg_out);
}
static int gsup_send_err_reply(struct osmo_gsup_conn *conn, const char *imsi,
enum osmo_gsup_message_type type_in, uint8_t err_cause)
{
int type_err = osmo_gsup_get_err_msg_type(type_in);
struct osmo_gsup_message gsup_reply = {0};
struct msgb *msg_out;
if (type_err < 0) {
LOGP(DMAIN, LOGL_ERROR, "unable to determine error response for %s\n",
osmo_gsup_message_type_name(type_in));
return type_err;
}
OSMO_STRLCPY_ARRAY(gsup_reply.imsi, imsi);
gsup_reply.message_type = type_err;
gsup_reply.cause = err_cause;
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP ERR response");
OSMO_ASSERT(msg_out);
osmo_gsup_encode(msg_out, &gsup_reply);
LOGP(DMAIN, LOGL_NOTICE, "Tx %s\n", osmo_gsup_message_type_name(type_err));
return osmo_gsup_conn_send(conn, msg_out);
}
static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
{
static struct osmo_gsup_message gsup;
@@ -362,6 +386,11 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
return rc;
}
/* 3GPP TS 23.003 Section 2.2 clearly states that an IMSI with less than 5
* digits is impossible. Even 5 digits is a highly theoretical case */
if (strlen(gsup.imsi) < 5)
return gsup_send_err_reply(conn, gsup.imsi, gsup.message_type, GMM_CAUSE_INV_MAND_INFO);
switch (gsup.message_type) {
/* requests sent to us */
case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:
@@ -505,6 +534,7 @@ static void signal_hdlr(int signal)
case SIGINT:
LOGP(DMAIN, LOGL_NOTICE, "Terminating due to SIGINT\n");
osmo_gsup_server_destroy(g_hlr->gs);
hlr_usse_clean_up(g_hlr);
db_close(g_hlr->dbc);
log_fini();
talloc_report_full(hlr_ctx, stderr);
@@ -541,6 +571,9 @@ int main(int argc, char **argv)
g_hlr = talloc_zero(hlr_ctx, struct hlr);
INIT_LLIST_HEAD(&g_hlr->usse_list);
g_hlr->usse_default = NULL;
rc = osmo_init_logging2(hlr_ctx, &hlr_log_info);
if (rc < 0) {
fprintf(stderr, "Error initializing logging\n");
@@ -581,7 +614,7 @@ int main(int argc, char **argv)
}
g_hlr->gs = osmo_gsup_server_create(hlr_ctx, g_hlr->gsup_bind_addr, OSMO_GSUP_PORT,
read_cb, &g_lu_ops);
read_cb, &g_lu_ops, g_hlr);
if (!g_hlr->gs) {
LOGP(DMAIN, LOGL_FATAL, "Error starting GSUP server\n");
exit(1);

View File

@@ -23,6 +23,9 @@
#pragma once
#include <stdbool.h>
#include <osmocom/core/linuxlist.h>
struct hlr_usse;
struct hlr {
/* GSUP server pointer */
@@ -37,6 +40,10 @@ struct hlr {
/* Local bind addr */
char *gsup_bind_addr;
/* SS/USSD processing entities */
struct llist_head usse_list;
struct hlr_usse *usse_default;
};
struct hlr_subscriber;

129
src/hlr_ss_ussd.c Normal file
View File

@@ -0,0 +1,129 @@
/* Supplementary Services signalling implementation */
/* (C) 2018 by Harald Welte <laforge@gnumonks.org>
* (C) 2018 by Vadim Yanitskiy <axilirator@gmail.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/linuxlist.h>
#include "hlr.h"
#include "hlr_ss_ussd.h"
struct hlr_usse *hlr_usse_find(struct hlr *hlr, const char *name)
{
struct hlr_usse *usse;
llist_for_each_entry(usse, &hlr->usse_list, list) {
if (!strcmp(usse->name, name))
return usse;
}
return NULL;
}
struct hlr_usse *hlr_usse_alloc(struct hlr *hlr, const char *name)
{
struct hlr_usse *usse;
usse = hlr_usse_find(hlr, name);
if (usse)
return NULL;
usse = talloc(hlr, struct hlr_usse);
usse->name = talloc_strdup(usse, name);
usse->description = NULL;
usse->hlr = hlr;
INIT_LLIST_HEAD(&usse->patterns);
llist_add_tail(&usse->list, &hlr->usse_list);
return usse;
}
void hlr_usse_del(struct hlr_usse *usse)
{
struct hlr_usse_pattern *pt, *_pt;
/* Release linked patterns */
llist_for_each_entry_safe(pt, _pt, &usse->patterns, list)
hlr_usse_pattern_del(pt);
/* Unlink from the HLR's USSE list */
llist_del(&usse->list);
/* Release memory */
talloc_free(usse);
}
struct hlr_usse_pattern *hlr_usse_pattern_find(struct hlr_usse *usse,
enum hlr_usse_pattern_type type, const char *pattern)
{
struct hlr_usse_pattern *pt;
llist_for_each_entry(pt, &usse->patterns, list) {
if (pt->type != type)
continue;
if (strcmp(pt->pattern, pattern))
continue;
return pt;
}
return NULL;
}
struct hlr_usse_pattern *hlr_usse_pattern_add(struct hlr_usse *usse,
enum hlr_usse_pattern_type type, const char *pattern)
{
struct hlr_usse_pattern *pt;
pt = hlr_usse_pattern_find(usse, type, pattern);
if (pt)
return NULL;
pt = talloc(usse, struct hlr_usse_pattern);
pt->pattern = talloc_strdup(pt, pattern);
pt->rsp_fmt = NULL;
pt->type = type;
pt->usse = usse;
llist_add_tail(&pt->list, &usse->patterns);
return pt;
}
void hlr_usse_pattern_del(struct hlr_usse_pattern *pt)
{
/* Unlink from the USSE's list */
llist_del(&pt->list);
/* Release memory */
talloc_free(pt);
}
void hlr_usse_clean_up(struct hlr *hlr)
{
struct hlr_usse *usse, *_usse;
llist_for_each_entry_safe(usse, _usse, &hlr->usse_list, list)
hlr_usse_del(usse);
}

51
src/hlr_ss_ussd.h Normal file
View File

@@ -0,0 +1,51 @@
#pragma once
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/gsm0480.h>
/* Represents a single USSE (either the internal, or an external) */
struct hlr_usse {
/* list in the per-HLR list of USSEs */
struct llist_head list;
/* back-pointer to the HLR instance */
struct hlr *hlr;
/* human-readable description */
const char *description;
/* name (must match the IPA ID tag) */
const char *name;
/* list of USSD-code matching patterns */
struct llist_head patterns;
};
/* Matching pattern types sorted by priority */
enum hlr_usse_pattern_type {
HLR_USSE_PATTERN_CODE = 0, /* higher priority */
HLR_USSE_PATTERN_REGEXP,
HLR_USSE_PATTERN_PREFIX,
};
/* Represents a USSD-code matching pattern */
struct hlr_usse_pattern {
/* link to the parent USSE */
struct llist_head list;
/* back-pointer to the parent USSE */
struct hlr_usse *usse;
/* Patter type, e.g. code, regexp or prefix */
enum hlr_usse_pattern_type type;
/* Mathing pattern, e.g. '*110*' for prefix */
const char *pattern;
/* Response format string, e.g. 'Your MSISDN is %m' */
char *rsp_fmt;
};
struct hlr_usse *hlr_usse_find(struct hlr *hlr, const char *name);
struct hlr_usse *hlr_usse_alloc(struct hlr *hlr, const char *name);
void hlr_usse_del(struct hlr_usse *usse);
struct hlr_usse_pattern *hlr_usse_pattern_find(struct hlr_usse *usse,
enum hlr_usse_pattern_type type, const char *pattern);
struct hlr_usse_pattern *hlr_usse_pattern_add(struct hlr_usse *usse,
enum hlr_usse_pattern_type type, const char *pattern);
void hlr_usse_pattern_del(struct hlr_usse_pattern *pt);
void hlr_usse_clean_up(struct hlr *hlr);

View File

@@ -1,9 +1,11 @@
/* OsmoHLR VTY implementation */
/* (C) 2016 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
* (C) 2018 Harald Welte <laforge@gnumonks.org>
* (C) 2018 by Vadim Yanitskiy <axilirator@gmail.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -25,9 +27,12 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/misc.h>
#include <osmocom/abis/ipa.h>
#include "hlr_vty.h"
#include "hlr_ss_ussd.h"
#include "hlr_vty_subscr.h"
#include "gsup_server.h"
static struct hlr *g_hlr = NULL;
@@ -75,6 +80,33 @@ static int config_write_hlr_gsup(struct vty *vty)
return CMD_SUCCESS;
}
static void show_one_conn(struct vty *vty, const struct osmo_gsup_conn *conn)
{
const struct ipa_server_conn *isc = conn->conn;
char *name;
int rc;
rc = osmo_gsup_conn_ccm_get(conn, (uint8_t **) &name, IPAC_IDTAG_SERNR);
OSMO_ASSERT(rc);
vty_out(vty, " '%s' from %s:%5u, CS=%u, PS=%u, 3G_IND=%u%s",
name, isc->addr, isc->port, conn->supports_cs, conn->supports_ps, conn->auc_3g_ind,
VTY_NEWLINE);
}
DEFUN(show_gsup_conn, show_gsup_conn_cmd,
"show gsup-connections",
SHOW_STR "GSUP Connections from VLRs, SGSNs, EUSSEs\n")
{
struct osmo_gsup_server *gs = g_hlr->gs;
struct osmo_gsup_conn *conn;
llist_for_each_entry(conn, &gs->clients, list)
show_one_conn(vty, conn);
return CMD_SUCCESS;
}
DEFUN(cfg_hlr_gsup_bind_ip,
cfg_hlr_gsup_bind_ip_cmd,
"bind ip A.B.C.D",
@@ -89,12 +121,290 @@ DEFUN(cfg_hlr_gsup_bind_ip,
return CMD_SUCCESS;
}
/***********************************************************************
* Unstructured Supplementary Services processing Entity configuration
***********************************************************************/
static struct cmd_node iusse_node = {
IUSSE_NODE,
"%s(config-hlr-iusse)# ",
1,
};
static struct cmd_node eusse_node = {
EUSSE_NODE,
"%s(config-hlr-eusse)# ",
1,
};
#define VTY_USSE_NAME_DESC \
"Internal USSD processing Entity\n" \
"Alphanumeric name of an External USSE\n"
DEFUN(cfg_usse, cfg_usse_cmd,
"usse (internal|NAME)",
"Configure a particular USSE (USSD processing Entity)\n"
VTY_USSE_NAME_DESC)
{
const char *name = argv[0];
struct hlr_usse *usse;
usse = hlr_usse_find(g_hlr, name);
if (!usse) {
usse = hlr_usse_alloc(g_hlr, name);
if (!usse)
return CMD_WARNING;
}
vty->index_sub = &usse->description;
vty->index = usse;
/* IUSSE or EUSSE? */
if (!strcmp(usse->name, "internal"))
vty->node = IUSSE_NODE;
else
vty->node = EUSSE_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_no_usse, cfg_no_usse_cmd,
"no usse (internal|NAME)",
NO_STR "Remove a particular USSE (USSD processing Entity)\n"
VTY_USSE_NAME_DESC)
{
const char *name = argv[0];
struct hlr_usse *usse;
usse = hlr_usse_find(g_hlr, name);
if (!usse) {
vty_out(vty, "%% Cannot remove non-existent "
"USSE '%s'%s", name, VTY_NEWLINE);
return CMD_WARNING;
}
if (g_hlr->usse_default == usse) {
vty_out(vty, "%% Cannot remove USSE '%s', "
"it is the default route%s", name, VTY_NEWLINE);
return CMD_WARNING;
}
hlr_usse_del(usse);
return CMD_SUCCESS;
}
DEFUN(cfg_usse_default, cfg_usse_default_cmd,
"usse-default (internal|NAME)",
"Default USSD processing Entity\n"
VTY_USSE_NAME_DESC)
{
const char *name = argv[0];
struct hlr_usse *usse;
usse = hlr_usse_find(g_hlr, name);
if (!usse) {
vty_out(vty, "%% Cannot find USSE '%s'%s", name, VTY_NEWLINE);
return CMD_WARNING;
}
if (g_hlr->usse_default == usse) {
vty_out(vty, "%% USSE '%s' is already "
"used by default%s", usse->name, VTY_NEWLINE);
return CMD_WARNING;
}
g_hlr->usse_default = usse;
return CMD_SUCCESS;
}
DEFUN(cfg_no_usse_default, cfg_no_usse_default_cmd,
"no usse-default",
NO_STR "No default USSD processing Entity "
"(drop all unmatched requests)\n")
{
g_hlr->usse_default = NULL;
return CMD_SUCCESS;
}
#define VTY_USSE_PATTERN_CMD \
"pattern (code|regexp|prefix) PATTERN"
#define VTY_USSE_PATTERN_DESC \
"Match USSD-request codes by exact value (e.g. '*#100#')\n" \
"Match USSD-request codes by regular expression (e.g. '^\\*[5-7]+'\\*)\n" \
"Match USSD-request codes by prefix (e.g. '*#' or '*110*')\n" \
"Matching pattern\n"
static int _cfg_usse_pattern(struct vty *vty, int argc, const char **argv)
{
struct hlr_usse *usse = vty->index;
enum hlr_usse_pattern_type type;
struct hlr_usse_pattern *pt;
bool is_iusse;
/* Determine which kind of matching pattern required */
switch (argv[0][0]) {
case 'c':
type = HLR_USSE_PATTERN_CODE;
break;
case 'r':
type = HLR_USSE_PATTERN_REGEXP;
break;
case 'p':
type = HLR_USSE_PATTERN_PREFIX;
break;
default:
/* Shouldn't happen, but let's make sure */
return CMD_WARNING;
}
/* IUSSE or EUSSE? */
is_iusse = !strcmp(usse->name, "internal");
/* Attempt to find pattern */
pt = hlr_usse_pattern_find(usse, type, argv[1]);
if (pt && !is_iusse) {
/* Response modification is only actual for IUSSE */
vty_out(vty, "%% Pattern already exists!%s", VTY_NEWLINE);
return CMD_WARNING;
}
/* Allocate if required */
if (!pt) {
pt = hlr_usse_pattern_add(usse, type, argv[1]);
if (!pt) {
vty_out(vty, "%% Cannot add pattern '%s' of type '%s'%s",
argv[1], argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
}
/* Response string for IUSSE */
if (is_iusse) {
if (pt->rsp_fmt)
talloc_free(pt->rsp_fmt);
pt->rsp_fmt = talloc_strdup(pt, argv_concat(argv, argc, 2));
}
return CMD_SUCCESS;
}
DEFUN(cfg_iusse_pattern, cfg_iusse_pattern_cmd,
VTY_USSE_PATTERN_CMD " response .RESPONSE",
"Add or modify a USSD-code matching pattern\n"
VTY_USSE_PATTERN_DESC
"Response format string (e.g. 'Your MSISDN is %m')\n")
{
return _cfg_usse_pattern(vty, argc, argv);
}
DEFUN(cfg_eusse_pattern, cfg_eusse_pattern_cmd,
VTY_USSE_PATTERN_CMD,
"Add a new USSD-code matching pattern\n"
VTY_USSE_PATTERN_DESC)
{
return _cfg_usse_pattern(vty, argc, argv);
}
DEFUN(cfg_usse_no_pattern, cfg_usse_no_pattern_cmd,
"no " VTY_USSE_PATTERN_CMD,
NO_STR "Remove an existing USSD-code matching pattern\n"
VTY_USSE_PATTERN_DESC)
{
struct hlr_usse *usse = vty->index;
enum hlr_usse_pattern_type type;
struct hlr_usse_pattern *pt;
/* Determine which kind of matching pattern required */
switch (argv[0][0]) {
case 'c':
type = HLR_USSE_PATTERN_CODE;
break;
case 'r':
type = HLR_USSE_PATTERN_REGEXP;
break;
case 'p':
type = HLR_USSE_PATTERN_PREFIX;
break;
default:
/* Shouldn't happen, but let's make sure */
return CMD_WARNING;
}
pt = hlr_usse_pattern_find(usse, type, argv[1]);
if (!pt) {
vty_out(vty, "%% Cannot remove non-existent pattern '%s' "
"of type '%s'%s", argv[1], argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
hlr_usse_pattern_del(pt);
return CMD_SUCCESS;
}
static void dump_one_usse(struct vty *vty, struct hlr_usse *usse)
{
struct hlr_usse_pattern *pt;
const char *pt_type;
vty_out(vty, " usse %s%s", usse->name, VTY_NEWLINE);
// FIXME: what about usse->description?
llist_for_each_entry(pt, &usse->patterns, list) {
/* Stringify pattern type */
switch (pt->type) {
case HLR_USSE_PATTERN_CODE:
pt_type = "code";
break;
case HLR_USSE_PATTERN_REGEXP:
pt_type = "regexp";
break;
case HLR_USSE_PATTERN_PREFIX:
pt_type = "prefix";
break;
default:
/* Should not happen */
OSMO_ASSERT(0);
}
if (pt->rsp_fmt != NULL)
vty_out(vty, " pattern %s %s response %s%s", pt_type,
pt->pattern, pt->rsp_fmt, VTY_NEWLINE);
else
vty_out(vty, " pattern %s %s%s", pt_type,
pt->pattern, VTY_NEWLINE);
}
}
static int config_write_usse(struct vty *vty)
{
struct hlr_usse *usse;
if (g_hlr->usse_default == NULL)
vty_out(vty, " no usse-default%s", VTY_NEWLINE);
else
vty_out(vty, " usse-default %s%s",
g_hlr->usse_default->name, VTY_NEWLINE);
llist_for_each_entry(usse, &g_hlr->usse_list, list)
dump_one_usse(vty, usse);
return CMD_SUCCESS;
}
/***********************************************************************
* Common Code
***********************************************************************/
int hlr_vty_go_parent(struct vty *vty)
{
switch (vty->node) {
case GSUP_NODE:
case IUSSE_NODE:
case EUSSE_NODE:
vty->node = HLR_NODE;
vty->index = NULL;
vty->index_sub = NULL;
break;
default:
case HLR_NODE:
@@ -129,6 +439,8 @@ void hlr_vty_init(struct hlr *hlr, const struct log_info *cat)
logging_vty_add_cmds(cat);
osmo_talloc_vty_add_cmds();
install_element_ve(&show_gsup_conn_cmd);
install_element(CONFIG_NODE, &cfg_hlr_cmd);
install_node(&hlr_node, config_write_hlr);
@@ -137,5 +449,16 @@ void hlr_vty_init(struct hlr *hlr, const struct log_info *cat)
install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
install_element(HLR_NODE, &cfg_usse_cmd);
install_element(HLR_NODE, &cfg_no_usse_cmd);
install_element(HLR_NODE, &cfg_usse_default_cmd);
install_element(HLR_NODE, &cfg_no_usse_default_cmd);
install_node(&eusse_node, config_write_usse);
install_element(EUSSE_NODE, &cfg_eusse_pattern_cmd);
install_element(EUSSE_NODE, &cfg_usse_no_pattern_cmd);
install_node(&iusse_node, NULL);
install_element(IUSSE_NODE, &cfg_iusse_pattern_cmd);
install_element(IUSSE_NODE, &cfg_usse_no_pattern_cmd);
hlr_vty_subscriber_init(hlr);
}

View File

@@ -30,6 +30,8 @@
enum hlr_vty_node {
HLR_NODE = _LAST_OSMOVTY_NODE + 1,
GSUP_NODE,
IUSSE_NODE,
EUSSE_NODE,
};
int hlr_vty_is_config_node(struct vty *vty, int node);

View File

@@ -25,7 +25,6 @@
#include <errno.h>
#include <osmocom/core/logging.h>
#include <osmocom/gsm/gsm48_ie.h>
#include <osmocom/gsm/gsup.h>
#include <osmocom/gsm/apn.h>
@@ -52,6 +51,7 @@ static void _luop_tx_gsup(struct lu_operation *luop,
struct msgb *msg_out;
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP LUOP");
OSMO_ASSERT(msg_out);
osmo_gsup_encode(msg_out, gsup);
osmo_gsup_addr_send(luop->gsup_server, luop->peer,
@@ -215,40 +215,27 @@ void lu_op_tx_cancel_old(struct lu_operation *luop)
/*! Transmit Insert Subscriber Data to new VLR/SGSN */
void lu_op_tx_insert_subscr_data(struct lu_operation *luop)
{
struct osmo_gsup_message gsup;
uint8_t msisdn_enc[43]; /* TODO use constant; TS 24.008 10.5.4.7 */
struct hlr_subscriber *subscr = &luop->subscr;
struct osmo_gsup_message gsup = { };
uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];
uint8_t apn[APN_MAXLEN];
int l;
enum osmo_gsup_cn_domain cn_domain;
OSMO_ASSERT(luop->state == LU_S_LU_RECEIVED ||
luop->state == LU_S_CANCEL_ACK_RECEIVED);
fill_gsup_msg(&gsup, luop, OSMO_GSUP_MSGT_INSERT_DATA_REQUEST);
if (luop->is_ps)
cn_domain = OSMO_GSUP_CN_DOMAIN_PS;
else
cn_domain = OSMO_GSUP_CN_DOMAIN_CS;
l = gsm48_encode_bcd_number(msisdn_enc, sizeof(msisdn_enc), 0,
luop->subscr.msisdn);
if (l < 1) {
if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi, subscr->msisdn, msisdn_enc,
sizeof(msisdn_enc), apn, sizeof(apn), cn_domain) != 0) {
LOGP(DMAIN, LOGL_ERROR,
"%s: Error: cannot encode MSISDN '%s'\n",
luop->subscr.imsi, luop->subscr.msisdn);
lu_op_tx_error(luop, GMM_CAUSE_PROTO_ERR_UNSPEC);
"IMSI='%s': Cannot notify GSUP client; could not create gsup message "
"for %s\n", subscr->imsi, luop->peer);
return;
}
gsup.msisdn_enc = msisdn_enc;
gsup.msisdn_enc_len = l;
#pragma message "FIXME: deal with encoding the following data: gsup.hlr_enc"
if (luop->is_ps) {
/* FIXME: PDP infos - use more fine-grained access control
instead of wildcard APN */
if (osmo_gsup_configure_wildcard_apn(&gsup, apn, sizeof(apn))) {
LOGP(DMAIN, LOGL_ERROR, "%s: Error: cannot encode wildcard APN\n",
luop->subscr.imsi);
lu_op_tx_error(luop, GMM_CAUSE_PROTO_ERR_UNSPEC);
return;
}
}
/* Send ISD to new VLR/SGSN */
_luop_tx_gsup(luop, &gsup);

View File

@@ -63,9 +63,6 @@ struct lu_operation {
uint8_t *peer;
};
int osmo_gsup_addr_send(struct osmo_gsup_server *gs,
const uint8_t *addr, size_t addrlen,
struct msgb *msg);
struct lu_operation *lu_op_alloc(struct osmo_gsup_server *srv);
struct lu_operation *lu_op_alloc_conn(struct osmo_gsup_conn *conn);

View File

@@ -31,6 +31,7 @@ EXTRA_DIST = \
test_subscriber.vty \
test_subscriber.sql \
test_subscriber.ctrl \
test_sse.vty \
$(NULL)
TESTSUITE = $(srcdir)/testsuite

View File

@@ -1,2 +1,2 @@
DMAIN 10 01 08 21 43 65 87 09 21 43 f5 08 09 08 89 67 45 23 01 89 67 f5 05 07 10 01 01 12 02 01 2a
DMAIN 10 01 08 21 43 65 87 09 21 43 f5 08 09 08 89 67 45 23 01 89 67 f5 05 07 10 01 01 12 02 01 2a 28 01 01
DMAIN LU OP state change: LU RECEIVED -> ISD SENT

View File

@@ -16,6 +16,7 @@ OsmoHLR> list
show talloc-context (application|all) (full|brief|DEPTH)
show talloc-context (application|all) (full|brief|DEPTH) tree ADDRESS
show talloc-context (application|all) (full|brief|DEPTH) filter REGEXP
show gsup-connections
subscriber (imsi|msisdn|id) IDENT show
OsmoHLR> enable
@@ -69,6 +70,10 @@ OsmoHLR(config-hlr)# list
exit
end
gsup
usse (internal|NAME)
no usse (internal|NAME)
usse-default (internal|NAME)
no usse-default
OsmoHLR(config-hlr)# gsup
OsmoHLR(config-hlr-gsup)# list
@@ -84,6 +89,39 @@ OsmoHLR(config-hlr-gsup)# list
bind ip A.B.C.D
OsmoHLR(config-hlr-gsup)# exit
OsmoHLR(config-hlr)# usse test
OsmoHLR(config-hlr-eusse)# list
help
list
write terminal
write file
write memory
write
show running-config
exit
end
pattern (code|regexp|prefix) PATTERN
no pattern (code|regexp|prefix) PATTERN
OsmoHLR(config-hlr-eusse)# exit
OsmoHLR(config-hlr)# usse internal
OsmoHLR(config-hlr-iusse)# list
help
list
write terminal
write file
write memory
write
show running-config
exit
end
pattern (code|regexp|prefix) PATTERN response .RESPONSE
no pattern (code|regexp|prefix) PATTERN
OsmoHLR(config-hlr-iusse)# exit
OsmoHLR(config-hlr)# no usse test
OsmoHLR(config-hlr)# no usse internal
OsmoHLR(config-hlr)# exit
OsmoHLR(config)# exit
OsmoHLR# configure terminal
@@ -118,4 +156,5 @@ ctrl
hlr
gsup
bind ip 127.0.0.1
no usse-default
end

246
tests/test_usse.vty Normal file
View File

@@ -0,0 +1,246 @@
OsmoHLR> enable
OsmoHLR# configure terminal
OsmoHLR(config)# show running-config
Current configuration:
!
!
log stderr
logging filter all 1
logging color 1
logging print category 1
logging print extended-timestamp 1
logging print file 1
logging level all debug
logging level main notice
logging level db notice
logging level auc notice
...
!
line vty
no login
!
ctrl
bind 127.0.0.1
hlr
gsup
bind ip 127.0.0.1
no usse-default
end
OsmoHLR(config)# hlr
OsmoHLR(config-hlr)# no usse test
% Cannot remove non-existent USSE 'test'
OsmoHLR(config-hlr)# usse gw1
OsmoHLR(config-hlr-eusse)# no pattern prefix *111*
% Cannot remove non-existent pattern '*111*' of type 'prefix'
OsmoHLR(config-hlr-eusse)# pattern prefix *110*
OsmoHLR(config-hlr-eusse)# pattern prefix *181*
OsmoHLR(config-hlr-eusse)# pattern prefix *110*
% Pattern already exists!
OsmoHLR(config-hlr-eusse)# pattern code *110*
OsmoHLR(config-hlr-eusse)# pattern code *888#
OsmoHLR(config-hlr-eusse)# pattern code *110*
% Pattern already exists!
OsmoHLR(config-hlr-eusse)# pattern regexp ^*[1-3]{3}*[0-9]+#$
OsmoHLR(config-hlr-eusse)# pattern regexp ^*[5-7]{3}*[0-9]+#$
OsmoHLR(config-hlr-eusse)# pattern regexp ^*[1-3]{3}*[0-9]+#$
% Pattern already exists!
OsmoHLR(config-hlr-eusse)# show running-config
Current configuration:
!
!
log stderr
logging filter all 1
logging color 1
logging print category 1
logging print extended-timestamp 1
logging print file 1
logging level all debug
logging level main notice
logging level db notice
logging level auc notice
...
!
line vty
no login
!
ctrl
bind 127.0.0.1
hlr
gsup
bind ip 127.0.0.1
no usse-default
usse gw1
pattern prefix *110*
pattern prefix *181*
pattern code *110*
pattern code *888#
pattern regexp ^*[1-3]{3}*[0-9]+#$
pattern regexp ^*[5-7]{3}*[0-9]+#$
end
OsmoHLR(config-hlr-eusse)# no pattern prefix *181*
OsmoHLR(config-hlr-eusse)# no pattern code *110*
OsmoHLR(config-hlr-eusse)# no pattern regexp ^*[1-3]{3}*[0-9]+#$
OsmoHLR(config-hlr-eusse)# show running-config
Current configuration:
!
!
log stderr
logging filter all 1
logging color 1
logging print category 1
logging print extended-timestamp 1
logging print file 1
logging level all debug
logging level main notice
logging level db notice
logging level auc notice
...
!
line vty
no login
!
ctrl
bind 127.0.0.1
hlr
gsup
bind ip 127.0.0.1
no usse-default
usse gw1
pattern prefix *110*
pattern code *888#
pattern regexp ^*[5-7]{3}*[0-9]+#$
end
OsmoHLR(config-hlr-eusse)# exit
OsmoHLR(config-hlr)# usse internal
OsmoHLR(config-hlr-iusse)# pattern code *#100#
% Command incomplete.
OsmoHLR(config-hlr-iusse)# pattern code *#100# response Your extension is %m
OsmoHLR(config-hlr-iusse)# pattern regexp ^*999*[0-3]+#$ response Mahlzeit!
OsmoHLR(config-hlr-iusse)# no pattern code *888#
% Cannot remove non-existent pattern '*888#' of type 'code'
OsmoHLR(config-hlr-iusse)# show running-config
Current configuration:
!
!
log stderr
logging filter all 1
logging color 1
logging print category 1
logging print extended-timestamp 1
logging print file 1
logging level all debug
logging level main notice
logging level db notice
logging level auc notice
...
!
line vty
no login
!
ctrl
bind 127.0.0.1
hlr
gsup
bind ip 127.0.0.1
no usse-default
usse gw1
pattern prefix *110*
pattern code *888#
pattern regexp ^*[5-7]{3}*[0-9]+#$
usse internal
pattern code *#100# response Your extension is %m
pattern regexp ^*999*[0-3]+#$ response Mahlzeit!
end
OsmoHLR(config-hlr-iusse)# exit
OsmoHLR(config-hlr)# usse-default test
% Cannot find USSE 'test'
OsmoHLR(config-hlr)# usse-default internal
OsmoHLR(config-hlr)# usse-default gw1
OsmoHLR(config-hlr)# show running-config
Current configuration:
!
!
log stderr
logging filter all 1
logging color 1
logging print category 1
logging print extended-timestamp 1
logging print file 1
logging level all debug
logging level main notice
logging level db notice
logging level auc notice
...
!
line vty
no login
!
ctrl
bind 127.0.0.1
hlr
gsup
bind ip 127.0.0.1
usse-default gw1
usse gw1
pattern prefix *110*
pattern code *888#
pattern regexp ^*[5-7]{3}*[0-9]+#$
usse internal
pattern code *#100# response Your extension is %m
pattern regexp ^*999*[0-3]+#$ response Mahlzeit!
end
OsmoHLR(config-hlr)# no usse gw1
% Cannot remove USSE 'gw1', it is the default route
OsmoHLR(config-hlr)# no usse-default
OsmoHLR(config-hlr)# no usse gw1
OsmoHLR(config-hlr)# show running-config
Current configuration:
!
!
log stderr
logging filter all 1
logging color 1
logging print category 1
logging print extended-timestamp 1
logging print file 1
logging level all debug
logging level main notice
logging level db notice
logging level auc notice
...
!
line vty
no login
!
ctrl
bind 127.0.0.1
hlr
gsup
bind ip 127.0.0.1
no usse-default
usse internal
pattern code *#100# response Your extension is %m
pattern regexp ^*999*[0-3]+#$ response Mahlzeit!
end