mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr.git
synced 2025-11-02 13:13:29 +00:00
Compare commits
14 Commits
0.2.1
...
fixeria/us
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6f695e0e6 | ||
|
|
35d2342850 | ||
|
|
6b274b95fc | ||
|
|
edca4f88a6 | ||
|
|
b9c1028cb0 | ||
|
|
1442e3a3d3 | ||
|
|
0b8f054b5f | ||
|
|
fa7ee333f7 | ||
|
|
8fbf82b83f | ||
|
|
bd72f1331d | ||
|
|
32acace879 | ||
|
|
b85f60477f | ||
|
|
a1d3b048fb | ||
|
|
f83432c25c |
5
debian/osmo-hlr.install
vendored
5
debian/osmo-hlr.install
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
121
src/hlr.c
@@ -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);
|
||||
|
||||
@@ -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
129
src/hlr_ss_ussd.c
Normal 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
51
src/hlr_ss_ussd.h
Normal 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);
|
||||
327
src/hlr_vty.c
327
src/hlr_vty.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
39
src/luop.c
39
src/luop.c
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -31,6 +31,7 @@ EXTRA_DIST = \
|
||||
test_subscriber.vty \
|
||||
test_subscriber.sql \
|
||||
test_subscriber.ctrl \
|
||||
test_sse.vty \
|
||||
$(NULL)
|
||||
|
||||
TESTSUITE = $(srcdir)/testsuite
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
246
tests/test_usse.vty
Normal 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
|
||||
Reference in New Issue
Block a user