hlr mslookup and gsup proxy works for the first time

Change-Id: I546ca786308fed557703321bed2935e0adcbe0ee
This commit is contained in:
Neels Hofmeyr 2019-11-07 04:22:07 +01:00
parent 749e42902d
commit 2975bcbc2f
28 changed files with 760 additions and 128 deletions

View File

@ -188,4 +188,5 @@ AC_OUTPUT(
tests/gsup/Makefile
tests/db/Makefile
tests/db_upgrade/Makefile
tests/mslookup_manual_test/Makefile
)

View File

@ -39,6 +39,8 @@ struct osmo_gsup_client;
/* Expects message in msg->l2h */
typedef int (*osmo_gsup_client_read_cb_t)(struct osmo_gsup_client *gsupc, struct msgb *msg);
typedef bool (*osmo_gsup_client_up_down_cb_t)(struct osmo_gsup_client *gsupc, bool up);
struct osmo_gsup_client {
const char *unit_name; /* same as ipa_dev->unit_name, for backwards compat */
@ -54,8 +56,18 @@ struct osmo_gsup_client {
int got_ipa_pong;
struct ipaccess_unit *ipa_dev; /* identification information sent to IPA server */
osmo_gsup_client_up_down_cb_t up_down_cb;
};
struct osmo_gsup_client *osmo_gsup_client_create3(void *talloc_ctx,
struct ipaccess_unit *ipa_dev,
const char *ip_addr,
unsigned int tcp_port,
struct osmo_oap_client_config *oapc_config,
osmo_gsup_client_read_cb_t read_cb,
osmo_gsup_client_up_down_cb_t up_down_cb,
void *data);
struct osmo_gsup_client *osmo_gsup_client_create2(void *talloc_ctx,
struct ipaccess_unit *ipa_dev,
const char *ip_addr,

View File

@ -906,7 +906,7 @@ int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val,
/* FIXME: only send to single SGSN where latest update for IMSI came from */
llist_for_each_entry(co, &hlr->gs->clients, list) {
luop = lu_op_alloc_conn(co);
luop = lu_op_alloc_conn(co, NULL);
if (!luop) {
LOGHLR(subscr->imsi, LOGL_ERROR,
"Cannot notify GSUP client, cannot allocate lu_operation,"

View File

@ -13,9 +13,6 @@
#include "mslookup_server_mdns.h"
#include "global_title.h"
#define LOG_DGSM(imsi, level, fmt, args...) \
LOGP(DDGSM, level, "(IMSI-%s) " fmt, imsi, ##args)
void *dgsm_ctx = NULL;
const struct global_title dgsm_config_msc_wildcard = {};
@ -174,16 +171,102 @@ static void defer_gsup_message(const struct osmo_gsup_message *gsup)
/* Since osmo_gsup_message has a lot of dangling external pointers, the only way to defer the message is to
* store it encoded. */
m->gsup = osmo_gsup_msgb_alloc("GSUP proxy defer");
osmo_gsup_encode(m->gsup, gsup);
if (osmo_gsup_encode(m->gsup, gsup)) {
LOGP(DDGSM, LOGL_ERROR, "GSUP proxy defer: unable to encode GSUP message: %s %s\n",
osmo_gsup_message_type_name(gsup->message_type), osmo_quote_str(gsup->imsi, -1));
msgb_free(m->gsup);
talloc_free(m);
return;
}
llist_add_tail(&m->entry, &pending_gsup_messages);
}
void dgsm_send_to_remote_hlr(const struct proxy_subscr *ps, const struct osmo_gsup_message *gsup)
/* Unable to resolve remote HLR for this IMSI, Answer with error back to the sender. */
static void defer_gsup_message_err(struct pending_gsup_message *m)
{
struct osmo_gsup_message gsup;
struct osmo_gsup_conn *conn;
printf("whaha %p %p\n", m, m->gsup);
if (osmo_gsup_decode(m->gsup->data, m->gsup->len, &gsup)) {
LOGP(DDGSM, LOGL_ERROR, "Unable to decode deferred GSUP message for %s\n", m->imsi);
msgb_free(m->gsup);
m->gsup = NULL;
return;
}
conn = gsup_route_find(g_hlr->gs, gsup.source_name, gsup.source_name_len);
if (!conn) {
LOGP(DDGSM, LOGL_ERROR, "Unable to send error reply for %s %s, source_name is not known: %s\n",
osmo_gsup_message_type_name(gsup.message_type), gsup.imsi,
osmo_quote_str_c(OTC_SELECT, (char*)gsup.source_name, gsup.source_name_len));
return;
}
osmo_gsup_conn_send_err_reply(conn, &gsup, GMM_CAUSE_IMSI_UNKNOWN);
msgb_free(m->gsup);
m->gsup = NULL;
}
/* Forward spooled message for this IMSI to remote HLR. */
static void defer_gsup_message_send(struct pending_gsup_message *m, struct remote_hlr *remote_hlr)
{
/* To be able to log what we are forwarding, the spooled message needs to be decoded. Do that only if debug
* logging is enabled and decoding succeeds. If decoding fails, don't change anything about the code path, so
* that logging doesn't affect how osmo-hlr works. */
if (log_check_level(DDGSM, LOGL_DEBUG)) {
struct osmo_gsup_message gsup;
if (osmo_gsup_decode(m->gsup->data, m->gsup->len, &gsup))
LOGP(DDGSM, LOGL_ERROR, "Unable to decode deferred GSUP message for %s\n", m->imsi);
else
LOGP(DDGSM, LOGL_DEBUG,
"Forwarding deferred GSUP: %s %s from %s to " OSMO_SOCKADDR_STR_FMT "\n",
osmo_gsup_message_type_name(gsup.message_type), gsup.imsi,
osmo_quote_str_c(OTC_SELECT, (char*)gsup.source_name, gsup.source_name_len),
OSMO_SOCKADDR_STR_FMT_ARGS(&remote_hlr->addr));
}
/* If sending fails, still discard. */
if (!remote_hlr->gsupc || !remote_hlr->gsupc->is_connected) {
LOGP(DDGSM, LOGL_ERROR, "GSUP link to remote HLR is not connected: " OSMO_SOCKADDR_STR_FMT "\n",
OSMO_SOCKADDR_STR_FMT_ARGS(&remote_hlr->addr));
defer_gsup_message_err(m);
return;
}
remote_hlr_msgb_send(remote_hlr, m->gsup);
}
/* Result of looking for remote HLR. If it failed, pass remote_hlr as NULL. */
static void defer_gsup_message_pop(const char *imsi, struct remote_hlr *remote_hlr)
{
struct pending_gsup_message *m, *n;
if (remote_hlr)
LOG_DGSM(imsi, LOGL_DEBUG, "Sending spooled GSUP messages to remote HLR at " OSMO_SOCKADDR_STR_FMT "\n",
OSMO_SOCKADDR_STR_FMT_ARGS(&remote_hlr->addr));
else
LOG_DGSM(imsi, LOGL_ERROR, "No remote HLR found, dropping spooled GSUP messages\n");
llist_for_each_entry_safe(m, n, &pending_gsup_messages, entry) {
if (strcmp(m->imsi, imsi))
continue;
if (!remote_hlr)
defer_gsup_message_err(m);
else
defer_gsup_message_send(m, remote_hlr);
llist_del(&m->entry);
talloc_free(m);
}
}
void dgsm_send_to_remote_hlr(const struct proxy_subscr *proxy_subscr, const struct osmo_gsup_message *gsup)
{
struct remote_hlr *remote_hlr;
if (!osmo_sockaddr_str_is_nonzero(&ps->remote_hlr)) {
if (!osmo_sockaddr_str_is_nonzero(&proxy_subscr->remote_hlr_addr)) {
/* We don't know the remote target yet. Still waiting for an MS lookup response. */
LOG_DGSM(gsup->imsi, LOGL_DEBUG, "GSUP Proxy: deferring until remote proxy is known: %s\n",
osmo_gsup_message_type_name(gsup->message_type));
@ -192,67 +275,216 @@ void dgsm_send_to_remote_hlr(const struct proxy_subscr *ps, const struct osmo_gs
}
LOG_DGSM(gsup->imsi, LOGL_DEBUG, "GSUP Proxy: forwarding to " OSMO_SOCKADDR_STR_FMT ": %s\n",
OSMO_SOCKADDR_STR_FMT_ARGS(&ps->remote_hlr), osmo_gsup_message_type_name(gsup->message_type));
OSMO_SOCKADDR_STR_FMT_ARGS(&proxy_subscr->remote_hlr_addr),
osmo_gsup_message_type_name(gsup->message_type));
remote_hlr = remote_hlr_get(&ps->remote_hlr, true);
remote_hlr = remote_hlr_get(&proxy_subscr->remote_hlr_addr, true);
if (!remote_hlr) {
LOG_DGSM(gsup->imsi, LOGL_ERROR, "Failed to establish connection to remote HLR " OSMO_SOCKADDR_STR_FMT
", discarding GSUP: %s\n",
OSMO_SOCKADDR_STR_FMT_ARGS(&ps->remote_hlr), osmo_gsup_message_type_name(gsup->message_type));
OSMO_SOCKADDR_STR_FMT_ARGS(&proxy_subscr->remote_hlr_addr),
osmo_gsup_message_type_name(gsup->message_type));
return;
}
if (!remote_hlr->gsupc || !remote_hlr->gsupc->is_connected) {
/* GSUP link is still busy establishing... */
LOG_DGSM(gsup->imsi, LOGL_DEBUG, "GSUP Proxy: deferring until link to remote proxy is up: %s\n",
osmo_gsup_message_type_name(gsup->message_type));
defer_gsup_message(gsup);
return;
}
remote_hlr_gsup_send(remote_hlr, gsup);
}
static void resolve_hlr_result_cb(struct osmo_mslookup_client *client,
uint32_t request_handle,
const struct osmo_mslookup_query *query,
const struct osmo_mslookup_result *result)
{
struct proxy *proxy = g_hlr->gsup_proxy.cs;
const struct proxy_subscr *proxy_subscr;
struct proxy_subscr proxy_subscr_new;
struct remote_hlr *remote_hlr;
/* A remote HLR is answering back, indicating that it is the home HLR for a given IMSI.
* There should be a mostly empty proxy entry for that IMSI.
* Add the remote address data in the proxy. */
if (query->id.type != OSMO_MSLOOKUP_ID_IMSI) {
LOGP(DDGSM, LOGL_ERROR, "Expected IMSI ID type in mslookup query+result: %s\n",
osmo_mslookup_result_name_c(OTC_SELECT, query, result));
return;
}
proxy_subscr = proxy_subscr_get_by_imsi(proxy, query->id.imsi);
if (!proxy_subscr) {
LOG_DGSM(query->id.imsi, LOGL_ERROR, "No proxy entry for mslookup result: %s\n",
osmo_mslookup_result_name_c(OTC_SELECT, query, result));
defer_gsup_message_pop(query->id.imsi, NULL);
return;
}
if (result->rc != OSMO_MSLOOKUP_RC_OK) {
LOG_DGSM(query->id.imsi, LOGL_ERROR, "Failed to resolve remote HLR: %s\n",
osmo_mslookup_result_name_c(OTC_SELECT, query, result));
defer_gsup_message_pop(query->id.imsi, NULL);
proxy_subscr_del(proxy, proxy_subscr->imsi);
return;
}
/* Store the address. Make a copy to modify. */
proxy_subscr_new = *proxy_subscr;
proxy_subscr = &proxy_subscr_new;
if (osmo_sockaddr_str_is_nonzero(&result->host_v4))
proxy_subscr_new.remote_hlr_addr = result->host_v4;
else if (osmo_sockaddr_str_is_nonzero(&result->host_v6))
proxy_subscr_new.remote_hlr_addr = result->host_v6;
else {
LOG_DGSM(query->id.imsi, LOGL_ERROR, "Invalid address for remote HLR: %s\n",
osmo_mslookup_result_name_c(OTC_SELECT, query, result));
defer_gsup_message_pop(query->id.imsi, NULL);
proxy_subscr_del(proxy, proxy_subscr->imsi);
return;
}
if (proxy_subscr_update(proxy, proxy_subscr)) {
LOG_DGSM(query->id.imsi, LOGL_ERROR, "Failed to store proxy entry for remote HLR: %s\n",
osmo_mslookup_result_name_c(OTC_SELECT, query, result));
defer_gsup_message_pop(query->id.imsi, NULL);
proxy_subscr_del(proxy, proxy_subscr->imsi);
return;
}
LOG_DGSM(proxy_subscr->imsi, LOGL_DEBUG, "Stored remote hlr address for this IMSI: " OSMO_SOCKADDR_STR_FMT "\n",
OSMO_SOCKADDR_STR_FMT_ARGS(&proxy_subscr->remote_hlr_addr));
remote_hlr = remote_hlr_get(&proxy_subscr->remote_hlr_addr, true);
if (!remote_hlr) {
defer_gsup_message_pop(query->id.imsi, NULL);
proxy_subscr_del(proxy, proxy_subscr->imsi);
return;
}
if (!remote_hlr->gsupc || !remote_hlr->gsupc->is_connected) {
LOG_DGSM(query->id.imsi, LOGL_DEBUG, "Resolved remote HLR, waiting for link-up: %s\n",
osmo_mslookup_result_name_c(OTC_SELECT, query, result));
return;
}
LOG_DGSM(query->id.imsi, LOGL_DEBUG, "Resolved remote HLR, sending spooled GSUP messages: %s\n",
osmo_mslookup_result_name_c(OTC_SELECT, query, result));
defer_gsup_message_pop(query->id.imsi, remote_hlr);
}
static bool remote_hlr_up_yield(struct proxy *proxy, const struct proxy_subscr *proxy_subscr, void *data)
{
struct remote_hlr *remote_hlr = data;
defer_gsup_message_pop(proxy_subscr->imsi, remote_hlr);
return true;
}
void dgsm_remote_hlr_up(struct remote_hlr *remote_hlr)
{
LOGP(DDGSM, LOGL_NOTICE, "link to remote HLR is up, sending spooled GSUP messages: " OSMO_SOCKADDR_STR_FMT "\n",
OSMO_SOCKADDR_STR_FMT_ARGS(&remote_hlr->addr));
/* Send all spooled GSUP messaged for IMSIs that are waiting for this link to establish. */
proxy_subscrs_get_by_remote_hlr(g_hlr->gsup_proxy.cs, &remote_hlr->addr, remote_hlr_up_yield, remote_hlr);
}
/* Return true when the message has been handled by D-GSM. */
bool dgsm_check_forward_gsup_msg(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup)
{
const struct proxy_subscr *proxy_subscr;
struct proxy_subscr ps_new;
struct gsup_route *r;
struct proxy_subscr proxy_subscr_new;
struct gsup_route *route;
struct osmo_gsup_message gsup_copy;
struct proxy *proxy = g_hlr->gsup_proxy.cs;
if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS)
struct proxy *proxy;
struct osmo_mslookup_query query;
struct osmo_mslookup_query_handling handling;
uint32_t request_handle;
switch (gsup->cn_domain) {
case OSMO_GSUP_CN_DOMAIN_CS:
proxy = g_hlr->gsup_proxy.cs;
break;
case OSMO_GSUP_CN_DOMAIN_PS:
proxy = g_hlr->gsup_proxy.ps;
proxy_subscr = proxy_subscr_get_by_imsi(proxy, gsup->imsi);
if (proxy_subscr)
goto yes_we_are_proxying;
/* No proxy entry exists. If the IMSI is known in the local HLR, then we won't proxy. */
if (db_subscr_exists_by_imsi(g_hlr->dbc, gsup->imsi) == 0)
return false;
/* The IMSI is not known locally, so we want to proxy to a remote HLR, but no proxy entry exists yet. We need to
* look up the subscriber in remote HLRs via D-GSM mslookup, forward GSUP and reply once a result is back from
* there. Defer message and kick off MS lookup. */
/* Add a proxy entry without a remote address to indicate that we are busy querying for a remote HLR. */
ps_new = (struct proxy_subscr){};
OSMO_STRLCPY_ARRAY(ps_new.imsi, gsup->imsi);
proxy_subscr_update(proxy, &ps_new);
proxy_subscr = &ps_new;
yes_we_are_proxying:
OSMO_ASSERT(proxy_subscr);
break;
default:
LOG_DGSM(gsup->imsi, LOGL_ERROR, "Unknown cn_domain: %d\n", gsup->cn_domain);
osmo_gsup_conn_send_err_reply(conn, gsup, GMM_CAUSE_INV_MAND_INFO);
return -GMM_CAUSE_INV_MAND_INFO;
}
/* To forward to a remote HLR, we need to indicate the source MSC's name to make sure the reply can be routed
* back. Store the sender MSC in gsup->source_name -- the remote HLR is required to return this as
* gsup->destination_name so that the reply gets routed to the original MSC. */
r = gsup_route_find_by_conn(conn);
if (!r) {
route = gsup_route_find_by_conn(conn);
if (!route) {
/* The conn has not sent its IPA unit name yet, and hence we won't be able to proxy responses back from
* a remote HLR. Send GSUP error and indicate that this message has been handled. */
osmo_gsup_conn_send_err_reply(conn, gsup, GMM_CAUSE_NET_FAIL);
return true;
}
/* Be aware that osmo_gsup_message has a lot of external pointer references, so this is not a deep copy. */
gsup_copy = *gsup;
gsup_copy.source_name = r->addr;
gsup_copy.source_name_len = talloc_total_size(r->addr);
/* If the IMSI is known in the local HLR, then we won't proxy. */
if (db_subscr_exists_by_imsi(g_hlr->dbc, gsup->imsi) == 0)
return false;
/* Are we already forwarding this IMSI to a remote HLR? */
proxy_subscr = proxy_subscr_get_by_imsi(proxy, gsup->imsi);
if (proxy_subscr)
goto yes_we_are_proxying;
/* The IMSI is not known locally, so we want to proxy to a remote HLR, but no proxy entry exists yet. We need to
* look up the subscriber in remote HLRs via D-GSM mslookup, forward GSUP and reply once a result is back from
* there. Defer message and kick off MS lookup. */
/* Kick off an mslookup for the remote HLR. */
if (!g_hlr->mslookup.client.client) {
LOGP(DDGSM, LOGL_DEBUG, "mslookup client not running, cannot query remote home HLR for %s\n",
gsup->imsi);
return false;
}
query = (struct osmo_mslookup_query){
.id = {
.type = OSMO_MSLOOKUP_ID_IMSI,
}
};
OSMO_STRLCPY_ARRAY(query.id.imsi, gsup->imsi);
OSMO_STRLCPY_ARRAY(query.service, OSMO_MSLOOKUP_SERVICE_HLR_GSUP);
handling = (struct osmo_mslookup_query_handling){
.result_timeout_milliseconds = g_hlr->mslookup.client.result_timeout_milliseconds,
.result_cb = resolve_hlr_result_cb,
};
request_handle = osmo_mslookup_client_request(g_hlr->mslookup.client.client, &query, &handling);
if (!request_handle) {
LOG_DGSM(gsup->imsi, LOGL_ERROR, "Error dispatching mslookup query for home HLR: %s\n",
osmo_mslookup_result_name_c(OTC_SELECT, &query, NULL));
proxy_subscr_del(proxy, gsup->imsi);
return false;
}
/* Add a proxy entry without a remote address to indicate that we are busy querying for a remote HLR. */
proxy_subscr_new = (struct proxy_subscr){};
OSMO_STRLCPY_ARRAY(proxy_subscr_new.imsi, gsup->imsi);
global_title_set(&proxy_subscr_new.vlr_name, route->addr, talloc_total_size(route->addr));
proxy_subscr = &proxy_subscr_new;
proxy_subscr_update(proxy, proxy_subscr);
yes_we_are_proxying:
OSMO_ASSERT(proxy_subscr);
/* Be aware that osmo_gsup_message has a lot of external pointer references, so this is not a deep copy.
* dgsm_send_to_remote_hlr() may need to defer the GSUP message until the remote HLR has answered, in which case
* it will take care to deep copy (encode into a msgb), i.e. it is fine to pass a shallow copy. */
gsup_copy = *gsup;
gsup_copy.source_name = route->addr;
gsup_copy.source_name_len = talloc_total_size(route->addr);
/* If the remote HLR is already known, directly forward the GSUP message; otherwise, spool the GSUP message
* until the remote HLR will respond / until timeout aborts. */
dgsm_send_to_remote_hlr(proxy_subscr, &gsup_copy);
return true;
}
@ -263,7 +495,15 @@ void dgsm_init(void *ctx)
dgsm_ctx = talloc_named_const(ctx, 0, "dgsm");
dgsm_pending_messages_ctx = talloc_named_const(dgsm_ctx, 0, "dgsm_pending_messages");
INIT_LLIST_HEAD(&g_hlr->mslookup.vty.server.msc_configs);
g_hlr->mslookup.server.max_age = 60 * 60;
g_hlr->mslookup.client.result_timeout_milliseconds = 2000;
g_hlr->gsup_proxy.gsup_client_name.unit_name = "HLR";
g_hlr->gsup_proxy.gsup_client_name.serno = "unnamed-HLR";
g_hlr->gsup_proxy.gsup_client_name.swversion = PACKAGE_NAME "-" PACKAGE_VERSION;
osmo_sockaddr_str_from_str(&g_hlr->mslookup.vty.server.mdns.bind_addr,
OSMO_MSLOOKUP_MDNS_IP4, OSMO_MSLOOKUP_MDNS_PORT);
osmo_sockaddr_str_from_str(&g_hlr->mslookup.vty.client.mdns.query_addr,

View File

@ -4,7 +4,11 @@
#include "gsup_server.h"
#include "global_title.h"
#define LOG_DGSM(imsi, level, fmt, args...) \
LOGP(DDGSM, level, "(IMSI-%s) " fmt, imsi, ##args)
struct vty;
struct remote_hlr;
extern void *dgsm_ctx;
@ -67,4 +71,5 @@ void dgsm_start(void *ctx);
bool dgsm_check_forward_gsup_msg(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup);
void dgsm_vty_init();
void dgsm_vty_go_parent_action(struct vty *vty);
void dgsm_remote_hlr_up(struct remote_hlr *remote_hlr);

View File

@ -353,7 +353,3 @@ void dgsm_vty_init()
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_mdns_cmd);
}
void dgsm_vty_go_parent_action(struct vty *vty)
{
}

View File

@ -47,6 +47,11 @@ struct osmo_gsup_conn *gsup_route_find(struct osmo_gsup_server *gs,
return NULL;
}
struct osmo_gsup_conn *gsup_route_find_gt(struct osmo_gsup_server *gs, const struct global_title *gt)
{
return gsup_route_find(gs, gt->val, gt->len);
}
/*! Find a GSUP connection's route (to read the IPA address from the route).
* \param[in] conn GSUP connection
* \return GSUP route

View File

@ -13,6 +13,7 @@ struct gsup_route {
struct osmo_gsup_conn *gsup_route_find(struct osmo_gsup_server *gs,
const uint8_t *addr, size_t addrlen);
struct osmo_gsup_conn *gsup_route_find_gt(struct osmo_gsup_server *gs, const struct global_title *gt);
struct gsup_route *gsup_route_find_by_conn(const struct osmo_gsup_conn *conn);

View File

@ -82,14 +82,10 @@ void osmo_gsup_conn_send_err_reply(struct osmo_gsup_conn *conn, const struct osm
/* RP-Message-Reference is mandatory for SM Service */
.sm_rp_mr = gsup_orig->sm_rp_mr,
};
osmo_gsup_set_reply(gsup_orig, &gsup_reply);
OSMO_STRLCPY_ARRAY(gsup_reply.imsi, gsup_orig->imsi);
/* For SS/USSD, it's important to keep both session state and ID IEs */
if (gsup_orig->session_state != OSMO_GSUP_SESSION_STATE_NONE) {
if (gsup_orig->session_state != OSMO_GSUP_SESSION_STATE_NONE)
gsup_reply.session_state = OSMO_GSUP_SESSION_STATE_END;
gsup_reply.session_id = gsup_orig->session_id;
}
msg_out = osmo_gsup_msgb_alloc("GSUP ERR response");
rc = osmo_gsup_encode(msg_out, &gsup_reply);
@ -100,6 +96,9 @@ void osmo_gsup_conn_send_err_reply(struct osmo_gsup_conn *conn, const struct osm
return;
}
LOGP(DLGSUP, LOGL_DEBUG, "%s: GSUP tx %s\n",
osmo_quote_str(gsup_orig->imsi, -1), osmo_gsup_message_type_name(gsup_reply.message_type));
rc = osmo_gsup_conn_send(conn, msg_out);
if (rc)
LOGP(DLGSUP, LOGL_ERROR, "%s: Unable to send error response %s (rc=%d)\n",

View File

@ -97,7 +97,14 @@ static void connect_timer_cb(void *gsupc_)
if (gsupc->is_connected)
return;
if (gsupc->up_down_cb) {
/* When the up_down_cb() returns false, the user asks us not to retry connecting. */
if (!gsupc->up_down_cb(gsupc, false))
return;
}
gsup_client_connect(gsupc);
}
static void client_send(struct osmo_gsup_client *gsupc, int proto_ext,
@ -139,9 +146,18 @@ static void gsup_client_updown_cb(struct ipa_client_conn *link, int up)
gsup_client_oap_register(gsupc);
osmo_timer_del(&gsupc->connect_timer);
if (gsupc->up_down_cb)
gsupc->up_down_cb(gsupc, true);
} else {
osmo_timer_del(&gsupc->ping_timer);
if (gsupc->up_down_cb) {
/* When the up_down_cb() returns false, the user asks us not to retry connecting. */
if (!gsupc->up_down_cb(gsupc, false))
return;
}
osmo_timer_schedule(&gsupc->connect_timer,
OSMO_GSUP_CLIENT_RECONNECT_INTERVAL, 0);
}
@ -258,6 +274,57 @@ static void start_test_procedure(struct osmo_gsup_client *gsupc)
gsup_client_send_ping(gsupc);
}
struct osmo_gsup_client *osmo_gsup_client_create3(void *talloc_ctx,
struct ipaccess_unit *ipa_dev,
const char *ip_addr,
unsigned int tcp_port,
struct osmo_oap_client_config *oapc_config,
osmo_gsup_client_read_cb_t read_cb,
osmo_gsup_client_up_down_cb_t up_down_cb,
void *data)
{
struct osmo_gsup_client *gsupc;
int rc;
OSMO_ASSERT(ipa_dev->unit_name);
gsupc = talloc_zero(talloc_ctx, struct osmo_gsup_client);
OSMO_ASSERT(gsupc);
*gsupc = (struct osmo_gsup_client){
.unit_name = (const char *)ipa_dev->unit_name, /* API backwards compat */
.ipa_dev = ipa_dev,
.read_cb = read_cb,
.up_down_cb = up_down_cb,
.data = data,
};
/* a NULL oapc_config will mark oap_state disabled. */
rc = osmo_oap_client_init(oapc_config, &gsupc->oap_state);
if (rc != 0)
goto failed;
gsupc->link = ipa_client_conn_create(gsupc,
/* no e1inp */ NULL,
0,
ip_addr, tcp_port,
gsup_client_updown_cb,
gsup_client_read_cb,
/* default write_cb */ NULL,
gsupc);
if (!gsupc->link)
goto failed;
osmo_timer_setup(&gsupc->connect_timer, connect_timer_cb, gsupc);
rc = gsup_client_connect(gsupc);
if (rc < 0)
goto failed;
return gsupc;
failed:
osmo_gsup_client_destroy(gsupc);
return NULL;
}
/*!
* Create a gsup client connecting to the specified IP address and TCP port.
* Use the provided ipaccess unit as the client-side identifier; ipa_dev should
@ -278,44 +345,8 @@ struct osmo_gsup_client *osmo_gsup_client_create2(void *talloc_ctx,
osmo_gsup_client_read_cb_t read_cb,
struct osmo_oap_client_config *oapc_config)
{
struct osmo_gsup_client *gsupc;
int rc;
gsupc = talloc_zero(talloc_ctx, struct osmo_gsup_client);
OSMO_ASSERT(gsupc);
gsupc->unit_name = (const char *)ipa_dev->unit_name; /* API backwards compat */
gsupc->ipa_dev = ipa_dev;
/* a NULL oapc_config will mark oap_state disabled. */
rc = osmo_oap_client_init(oapc_config, &gsupc->oap_state);
if (rc != 0)
goto failed;
gsupc->link = ipa_client_conn_create(gsupc,
/* no e1inp */ NULL,
0,
ip_addr, tcp_port,
gsup_client_updown_cb,
gsup_client_read_cb,
/* default write_cb */ NULL,
gsupc);
if (!gsupc->link)
goto failed;
osmo_timer_setup(&gsupc->connect_timer, connect_timer_cb, gsupc);
rc = gsup_client_connect(gsupc);
if (rc < 0)
goto failed;
gsupc->read_cb = read_cb;
return gsupc;
failed:
osmo_gsup_client_destroy(gsupc);
return NULL;
return osmo_gsup_client_create3(talloc_ctx, ipa_dev, ip_addr, tcp_port, oapc_config,
read_cb, NULL, NULL);
}
/**

View File

@ -234,15 +234,14 @@ static int rx_send_auth_info(struct osmo_gsup_conn *conn,
const struct osmo_gsup_message *gsup,
struct db_context *dbc)
{
struct osmo_gsup_message gsup_out;
struct osmo_gsup_message gsup_out = {};
struct msgb *msg_out;
int rc;
subscr_create_on_demand(gsup->imsi);
/* initialize return message structure */
memset(&gsup_out, 0, sizeof(gsup_out));
memcpy(&gsup_out.imsi, &gsup->imsi, sizeof(gsup_out.imsi));
osmo_gsup_set_reply(gsup, &gsup_out);
rc = db_get_auc(dbc, gsup->imsi, conn->auc_3g_ind,
gsup_out.auth_vectors,
@ -344,7 +343,7 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
const struct osmo_gsup_message *gsup)
{
struct hlr_subscriber *subscr;
struct lu_operation *luop = lu_op_alloc_conn(conn);
struct lu_operation *luop = lu_op_alloc_conn(conn, gsup);
if (!luop) {
LOGP(DMAIN, LOGL_ERROR, "LU REQ from conn without addr?\n");
return -EINVAL;
@ -406,9 +405,15 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
#endif
/* Store the VLR / SGSN number with the subscriber, so we know where it was last seen. */
LOGP(DAUC, LOGL_DEBUG, "IMSI='%s': storing %s = %s\n",
subscr->imsi, luop->is_ps ? "SGSN number" : "VLR number",
global_title_name(&luop->peer));
if (global_title_cmp(&luop->vlr_number, &luop->peer))
LOGP(DAUC, LOGL_DEBUG, "IMSI='%s': storing %s = %s, via proxy %s\n",
subscr->imsi, luop->is_ps ? "SGSN number" : "VLR number",
global_title_name(&luop->vlr_number), global_title_name(&luop->peer));
else
LOGP(DAUC, LOGL_DEBUG, "IMSI='%s': storing %s = %s\n",
subscr->imsi, luop->is_ps ? "SGSN number" : "VLR number",
global_title_name(&luop->vlr_number));
if (db_subscr_lu(g_hlr->dbc, subscr->id, &luop->peer, &luop->vlr_number, luop->is_ps))
LOGP(DAUC, LOGL_ERROR, "IMSI='%s': Cannot update %s in the database\n",
subscr->imsi, luop->is_ps ? "SGSN number" : "VLR number");
@ -425,12 +430,12 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
static int rx_purge_ms_req(struct osmo_gsup_conn *conn,
const struct osmo_gsup_message *gsup)
{
struct osmo_gsup_message gsup_reply = {0};
struct osmo_gsup_message gsup_reply = {};
struct msgb *msg_out;
bool is_ps = false;
int rc;
memcpy(gsup_reply.imsi, gsup->imsi, sizeof(gsup_reply.imsi));
osmo_gsup_set_reply(gsup, &gsup_reply);
if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS)
is_ps = true;

View File

@ -76,6 +76,7 @@ struct hlr {
} server;
struct {
unsigned int result_timeout_milliseconds;
struct osmo_mslookup_client *client;
struct osmo_mslookup_client_method *mdns;
} client;

View File

@ -262,16 +262,18 @@ static int ss_tx_to_ms(struct ss_session *ss, enum osmo_gsup_message_type gsup_m
bool final, struct msgb *ss_msg)
{
struct osmo_gsup_message resp = {0};
struct osmo_gsup_message resp = {
.message_type = gsup_msg_type,
.cn_domain = OSMO_GSUP_CN_DOMAIN_CS,
.session_id = ss->session_id,
};
struct msgb *resp_msg;
resp.message_type = gsup_msg_type;
OSMO_STRLCPY_ARRAY(resp.imsi, ss->imsi);
if (final)
resp.session_state = OSMO_GSUP_SESSION_STATE_END;
else
resp.session_state = OSMO_GSUP_SESSION_STATE_CONTINUE;
resp.session_id = ss->session_id;
if (ss_msg) {
resp.ss_info = msgb_data(ss_msg);
resp.ss_info_len = msgb_length(ss_msg);

View File

@ -147,6 +147,24 @@ DEFUN(cfg_hlr_gsup_bind_ip,
return CMD_SUCCESS;
}
DEFUN(cfg_hlr_gsup_ipa_name,
cfg_hlr_gsup_ipa_name_cmd,
"ipa-name NAME",
"Set the IPA name of this HLR, for proxying to remote HLRs\n"
"A globally unique name for this HLR. For example: PLMN + redundancy server number: HLR-901-70-0. "
"This name is used for GSUP routing and must be set if multiple HLRs interconnect (e.g. mslookup "
"for Distributed GSM).\n")
{
if (vty->type != VTY_FILE) {
vty_out(vty, "gsup/ipa-name: The GSUP IPA name cannot be changed at run-time; "
"It can only be set in the configuraton file.%s", VTY_NEWLINE);
return CMD_WARNING;
}
g_hlr->gsup_proxy.gsup_client_name.serno = talloc_strdup(g_hlr, argv[0]);
return CMD_SUCCESS;
}
/***********************************************************************
* USSD Entity
***********************************************************************/
@ -397,7 +415,6 @@ DEFUN(cfg_no_subscr_create_on_demand, cfg_no_subscr_create_on_demand_cmd,
int hlr_vty_go_parent(struct vty *vty)
{
dgsm_vty_go_parent_action(vty);
switch (vty->node) {
case GSUP_NODE:
case EUSE_NODE:
@ -457,6 +474,7 @@ void hlr_vty_init(void)
install_node(&gsup_node, config_write_hlr_gsup);
install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
install_element(GSUP_NODE, &cfg_hlr_gsup_ipa_name_cmd);
install_element(HLR_NODE, &cfg_database_cmd);

View File

@ -66,6 +66,7 @@ static inline void fill_gsup_msg(struct osmo_gsup_message *out,
osmo_strlcpy(out->imsi, lu->subscr.imsi,
GSM23003_IMSI_MAX_DIGITS + 1);
out->message_type = mt;
out->cn_domain = lu->is_ps ? OSMO_GSUP_CN_DOMAIN_PS : OSMO_GSUP_CN_DOMAIN_CS;
}
/* timer call-back in case LU operation doesn't receive an response */
@ -123,7 +124,7 @@ void lu_op_free(struct lu_operation *luop)
talloc_free(luop);
}
struct lu_operation *lu_op_alloc_conn(struct osmo_gsup_conn *conn)
struct lu_operation *lu_op_alloc_conn(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup)
{
uint8_t *peer_addr;
struct lu_operation *luop = lu_op_alloc(conn->server);
@ -140,10 +141,14 @@ struct lu_operation *lu_op_alloc_conn(struct osmo_gsup_conn *conn)
return NULL;
}
if (gsup && gsup->source_name_len)
global_title_set(&luop->vlr_number, gsup->source_name, gsup->source_name_len);
else
luop->vlr_number = luop->peer;
return luop;
}
/* FIXME: this doesn't seem to work at all */
struct lu_operation *lu_op_by_imsi(const char *imsi,
const struct llist_head *lst)
{
@ -255,8 +260,6 @@ void lu_op_tx_del_subscr_data(struct lu_operation *luop)
fill_gsup_msg(&gsup, luop, OSMO_GSUP_MSGT_DELETE_DATA_REQUEST);
gsup.cn_domain = OSMO_GSUP_CN_DOMAIN_PS;
/* Send ISD to new VLR/SGSN */
_luop_tx_gsup(luop, &gsup);
}

View File

@ -67,7 +67,7 @@ struct lu_operation {
struct lu_operation *lu_op_alloc(struct osmo_gsup_server *srv);
struct lu_operation *lu_op_alloc_conn(struct osmo_gsup_conn *conn);
struct lu_operation *lu_op_alloc_conn(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup);
void lu_op_statechg(struct lu_operation *luop, enum lu_state new_state);
bool lu_op_fill_subscr(struct lu_operation *luop, struct db_context *dbc,
const char *imsi);

View File

@ -196,7 +196,7 @@ static bool subscriber_has_done_lu_here_proxy(const struct osmo_mslookup_query *
OSMO_SOCKADDR_STR_FMT "\n",
osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
age, global_title_name(local_msc_name),
OSMO_SOCKADDR_STR_FMT_ARGS(&subscr->remote_hlr));
OSMO_SOCKADDR_STR_FMT_ARGS(&subscr->remote_hlr_addr));
return true;
}

View File

@ -36,7 +36,7 @@ static void osmo_mslookup_server_mdns_tx(struct osmo_mslookup_server_mdns *serve
llist_add_tail(&rec_age->list, &ans.records);
if (osmo_sockaddr_str_is_nonzero(&result->host_v4)) {
if (osmo_sockaddr_str_to_32(&result->host_v4, &ip_v4)) {
if (osmo_sockaddr_str_to_32n(&result->host_v4, &ip_v4)) {
errmsg = "Error encoding IPv4 address";
goto clean_and_exit;
}

View File

@ -83,6 +83,19 @@ const struct proxy_subscr *proxy_subscr_get_by_msisdn(struct proxy *proxy, const
return &e->data;
}
void proxy_subscrs_get_by_remote_hlr(struct proxy *proxy, const struct osmo_sockaddr_str *remote_hlr_addr,
bool (*yield)(struct proxy *proxy, const struct proxy_subscr *subscr, void *data),
void *data)
{
struct proxy_subscr_listentry *e;
llist_for_each_entry(e, &proxy->subscr_list, entry) {
if (!osmo_sockaddr_str_ip_cmp(remote_hlr_addr, &e->data.remote_hlr_addr)) {
if (!yield(proxy, &e->data, data))
return;
}
}
}
int proxy_subscr_update(struct proxy *proxy, const struct proxy_subscr *proxy_subscr)
{
struct proxy_subscr_listentry *e = _proxy_get_by_imsi(proxy, proxy_subscr->imsi);

View File

@ -13,6 +13,7 @@ struct proxy {
/* How long to keep proxy entries without a refresh, in seconds. */
uint32_t fresh_time;
/* How often to garbage collect the proxy cache, period in seconds.
* To change this and take effect immediately, rather use proxy_set_gc_period(). */
uint32_t gc_period;
@ -28,14 +29,21 @@ struct proxy_subscr {
struct global_title vlr_via_proxy;
#endif
struct global_title vlr_name;
struct osmo_sockaddr_str remote_hlr;
struct osmo_sockaddr_str remote_hlr_addr;
struct timeval last_lu;
};
struct proxy *proxy_init(void *ctx);
void proxy_del(struct proxy *proxy);
void proxy_set_gc_period(struct proxy *proxy, uint32_t gc_period);
/* The API to access / modify proxy entries keeps the implementation opaque, to make sure that we can easily move proxy
* storage to SQLite db. */
const struct proxy_subscr *proxy_subscr_get_by_imsi(struct proxy *proxy, const char *imsi);
const struct proxy_subscr *proxy_subscr_get_by_msisdn(struct proxy *proxy, const char *msisdn);
void proxy_subscrs_get_by_remote_hlr(struct proxy *proxy, const struct osmo_sockaddr_str *remote_hlr_addr,
bool (*yield)(struct proxy *proxy, const struct proxy_subscr *subscr, void *data),
void *data);
const struct proxy_subscr *proxy_subscr_get_by_imsi(struct proxy *proxy, const char *imsi);
int proxy_subscr_update(struct proxy *proxy, const struct proxy_subscr *proxy_subscr);
int proxy_subscr_del(struct proxy *proxy, const char *imsi);

View File

@ -8,6 +8,7 @@
#include "gsup_router.h"
#include "dgsm.h"
#include "remote_hlr.h"
#include "proxy.h"
static LLIST_HEAD(remote_hlrs);
@ -49,10 +50,15 @@ void remote_hlr_err_reply(struct osmo_gsup_client *gsupc, const struct osmo_gsup
osmo_quote_str(gsup_orig->imsi, -1));
}
/* We are receiving back a GSUP message from a remote HLR to go back to a local MSC.
* The local MSC shall be indicated by gsup.destination_name. */
static int remote_hlr_rx(struct osmo_gsup_client *gsupc, struct msgb *msg)
{
struct osmo_gsup_message gsup;
struct osmo_gsup_conn *msc_conn;
struct osmo_gsup_conn *vlr_conn;
struct proxy *proxy;
const struct proxy_subscr *proxy_subscr;
struct msgb *gsup_copy;
int rc;
rc = osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup);
@ -68,26 +74,66 @@ static int remote_hlr_rx(struct osmo_gsup_client *gsupc, struct msgb *msg)
return -GMM_CAUSE_INV_MAND_INFO;
}
/* Since this is a proxy link to a remote osmo-msc, we are acting on behalf of a local MSC, and need to know the
* routing name of that local MSC. We have sent it to the remote HLR as source_name, and we're required to get
* it back as destination_name. */
if (!gsup.destination_name || !gsup.destination_name_len) {
LOG_GSUP_MSG(gsupc, &gsup, LOGL_ERROR, "message lacks Destination Name IE, cannot route to MSC.\n");
switch (gsup.cn_domain) {
case OSMO_GSUP_CN_DOMAIN_CS:
proxy = g_hlr->gsup_proxy.cs;
break;
case OSMO_GSUP_CN_DOMAIN_PS:
proxy = g_hlr->gsup_proxy.ps;
break;
default:
LOG_GSUP_MSG(gsupc, &gsup, LOGL_ERROR, "Unknown cn_domain: %d\n", gsup.cn_domain);
remote_hlr_err_reply(gsupc, &gsup, GMM_CAUSE_INV_MAND_INFO);
return -GMM_CAUSE_INV_MAND_INFO;
}
if (!proxy) {
LOG_GSUP_MSG(gsupc, &gsup, LOGL_ERROR, "Cannot route, there is no GSUP proxy set up\n");
remote_hlr_err_reply(gsupc, &gsup, GMM_CAUSE_NET_FAIL);
return -GMM_CAUSE_NET_FAIL;
}
proxy_subscr = proxy_subscr_get_by_imsi(proxy, gsup.imsi);
if (!proxy_subscr) {
LOG_GSUP_MSG(gsupc, &gsup, LOGL_ERROR, "Cannot route, no GSUP proxy record for this IMSI\n");
remote_hlr_err_reply(gsupc, &gsup, GMM_CAUSE_IMSI_UNKNOWN);
return -GMM_CAUSE_IMSI_UNKNOWN;
}
/* Route to MSC that we're proxying for */
msc_conn = gsup_route_find(g_hlr->gs, gsup.destination_name, gsup.destination_name_len);
if (!msc_conn) {
LOG_GSUP_MSG(gsupc, &gsup, LOGL_ERROR, "Destination MSC unreachable: %s\n",
osmo_quote_str((char*)gsup.destination_name, gsup.destination_name_len));
vlr_conn = gsup_route_find_gt(g_hlr->gs, &proxy_subscr->vlr_name);
if (!vlr_conn) {
LOG_GSUP_MSG(gsupc, &gsup, LOGL_ERROR, "Destination VLR unreachable: %s\n",
global_title_name(&proxy_subscr->vlr_name));
remote_hlr_err_reply(gsupc, &gsup, GMM_CAUSE_MSC_TEMP_NOTREACH);
return -GMM_CAUSE_MSC_TEMP_NOTREACH;
}
/* The outgoing message needs to be a separate msgb, because osmo_gsup_conn_send() takes ownership of it. */
return osmo_gsup_conn_send(msc_conn, msgb_copy(msg, "GSUP proxy to MSC"));
/* The outgoing message needs to be a separate msgb, because osmo_gsup_conn_send() takes ownership of it, an the
* gsup_client also does a msgb_free() after dispatching to this callback.
* We also need to strip the IPA header and have headroom. Just re-encode. */
gsup_copy = osmo_gsup_msgb_alloc("GSUP proxy to VLR");
if (osmo_gsup_encode(gsup_copy, &gsup)) {
LOG_GSUP_MSG(gsupc, &gsup, LOGL_ERROR, "Failed to re-encode GSUP message, cannot forward\n");
remote_hlr_err_reply(gsupc, &gsup, GMM_CAUSE_MSC_TEMP_NOTREACH);
return -GMM_CAUSE_MSC_TEMP_NOTREACH;
}
return osmo_gsup_conn_send(vlr_conn, gsup_copy);
}
static bool remote_hlr_up_down(struct osmo_gsup_client *gsupc, bool up)
{
struct remote_hlr *remote_hlr = gsupc->data;
if (!up) {
LOGP(DDGSM, LOGL_ERROR,
"link to remote HLR is down, removing GSUP client: " OSMO_SOCKADDR_STR_FMT "\n",
OSMO_SOCKADDR_STR_FMT_ARGS(&remote_hlr->addr));
remote_hlr_destroy(remote_hlr);
return false;
}
dgsm_remote_hlr_up(remote_hlr);
return true;
}
struct remote_hlr *remote_hlr_get(const struct osmo_sockaddr_str *addr, bool create)
@ -95,7 +141,7 @@ struct remote_hlr *remote_hlr_get(const struct osmo_sockaddr_str *addr, bool cre
struct remote_hlr *rh;
llist_for_each_entry(rh, &remote_hlrs, entry) {
if (!osmo_sockaddr_str_cmp(&rh->addr, addr))
if (!osmo_sockaddr_str_ip_cmp(&rh->addr, addr))
return rh;
}
@ -104,20 +150,36 @@ struct remote_hlr *remote_hlr_get(const struct osmo_sockaddr_str *addr, bool cre
/* Doesn't exist yet, create a GSUP client to remote HLR. */
rh = talloc_zero(dgsm_ctx, struct remote_hlr);
OSMO_ASSERT(rh);
*rh = (struct remote_hlr){
.addr = *addr,
.gsupc = osmo_gsup_client_create2(rh, &g_hlr->gsup_proxy.gsup_client_name,
.gsupc = osmo_gsup_client_create3(rh, &g_hlr->gsup_proxy.gsup_client_name,
addr->ip, addr->port,
NULL,
remote_hlr_rx,
NULL),
remote_hlr_up_down,
rh),
};
if (!rh->gsupc) {
LOGP(DDGSM, LOGL_ERROR,
"Failed to establish connection to remote HLR " OSMO_SOCKADDR_STR_FMT "\n",
OSMO_SOCKADDR_STR_FMT_ARGS(addr));
talloc_free(rh);
return NULL;
}
rh->gsupc->data = rh;
llist_add(&rh->entry, &remote_hlrs);
return rh;
}
void remote_hlr_destroy(struct remote_hlr *remote_hlr)
{
osmo_gsup_client_destroy(remote_hlr->gsupc);
remote_hlr->gsupc = NULL;
llist_del(&remote_hlr->entry);
talloc_free(remote_hlr);
}
/* This function takes ownership of the msg, do not free it after passing to this function. */
int remote_hlr_msgb_send(struct remote_hlr *remote_hlr, struct msgb *msg)
{
@ -131,8 +193,13 @@ int remote_hlr_msgb_send(struct remote_hlr *remote_hlr, struct msgb *msg)
int remote_hlr_gsup_send(struct remote_hlr *remote_hlr, const struct osmo_gsup_message *gsup)
{
int rc;
struct msgb *msg = osmo_gsup_msgb_alloc("GSUP proxy to remote HLR");
osmo_gsup_encode(msg, gsup);
rc = osmo_gsup_encode(msg, gsup);
if (rc) {
LOG_DGSM(gsup->imsi, LOGL_ERROR, "Failed to encode GSUP message: %s\n",
osmo_gsup_message_type_name(gsup->message_type));
return rc;
}
return remote_hlr_msgb_send(remote_hlr, msg);
}

View File

@ -8,6 +8,7 @@ struct osmo_gsup_client;
struct osmo_gsup_message;
struct msgb;
/* GSUP client link for proxying to a remote HLR. */
struct remote_hlr {
struct llist_head entry;
struct osmo_sockaddr_str addr;
@ -15,5 +16,6 @@ struct remote_hlr {
};
struct remote_hlr *remote_hlr_get(const struct osmo_sockaddr_str *addr, bool create);
void remote_hlr_destroy(struct remote_hlr *remote_hlr);
int remote_hlr_msgb_send(struct remote_hlr *remote_hlr, struct msgb *msg);
int remote_hlr_gsup_send(struct remote_hlr *remote_hlr, const struct osmo_gsup_message *gsup);

View File

@ -4,6 +4,7 @@ SUBDIRS = \
db \
gsup \
db_upgrade \
mslookup_manual_test \
$(NULL)
# The `:;' works around a Bash 3.2 bug when the output is not writeable.

View File

@ -0,0 +1,40 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/src \
$(NULL)
AM_CFLAGS = \
-Wall \
-ggdb3 \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
-no-install \
$(NULL)
EXTRA_DIST = \
run.sh \
osmo-hlr-1.cfg \
osmo-hlr-2.cfg \
$(NULL)
noinst_PROGRAMS = \
fake_msc \
$(NULL)
fake_msc_SOURCES = \
fake_msc.c \
$(NULL)
fake_msc_LDADD = \
$(top_builddir)/src/gsupclient/libosmo-gsup-client.la \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOABIS_LIBS) \
$(NULL)
run:
$(srcdir)/run.sh $(srcdir) $(builddir)

View File

@ -0,0 +1,80 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/select.h>
#include <osmocom/core/application.h>
#include <osmocom/gsupclient/gsup_client.h>
void *ctx;
int gsup_client_read_cb(struct osmo_gsup_client *gsupc, struct msgb *msg)
{
struct osmo_gsup_message gsup;
if (osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup)) {
printf("fake_msc: GSUP rx, but failed to decode\n");
return 0;
}
printf("fake_msc: GSUP rx %s %s (destination_name=%s)\n",
gsup.imsi, osmo_gsup_message_type_name(gsup.message_type),
osmo_quote_str((const char*)gsup.destination_name, gsup.destination_name_len));
return 0;
}
struct osmo_gsup_client *gsupc;
struct osmo_timer_list do_stuff_timer;
void do_stuff(void *data)
{
static int i = 0;
int seq = 0;
if (i == seq++) {
struct osmo_gsup_message gsup = {
.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST,
.imsi = "222222",
.cn_domain = OSMO_GSUP_CN_DOMAIN_CS,
};
osmo_gsup_client_enc_send(gsupc, &gsup);
}
seq += 3;
if (i == seq++) {
struct osmo_gsup_message gsup = {
.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST,
.imsi = "222222",
.cn_domain = OSMO_GSUP_CN_DOMAIN_CS,
};
osmo_gsup_client_enc_send(gsupc, &gsup);
}
seq += 10;
if (i == seq++) {
exit(0);
}
i++;
osmo_timer_schedule(&do_stuff_timer, 1, 0);
}
int main()
{
ctx = talloc_named_const(NULL, 0, "main");
osmo_init_logging2(ctx, NULL);
log_set_print_filename(osmo_stderr_target, 0);
log_set_print_level(osmo_stderr_target, 0);
log_set_print_category(osmo_stderr_target, 0);
log_set_print_category_hex(osmo_stderr_target, 0);
log_set_use_color(osmo_stderr_target, 0);
log_set_category_filter(osmo_stderr_target, DLMSLOOKUP, true, LOGL_DEBUG);
struct ipaccess_unit gsup_client_name = {
.unit_name = "fake-msc-1",
.serno = "fake-msc-1",
};
gsupc = osmo_gsup_client_create2(ctx, &gsup_client_name, "127.0.0.1", OSMO_GSUP_PORT, gsup_client_read_cb,
NULL);
osmo_timer_setup(&do_stuff_timer, do_stuff, NULL);
osmo_timer_schedule(&do_stuff_timer, 1, 0);
for (;;) {
osmo_select_main_ctx(0);
}
}

View File

@ -0,0 +1,40 @@
hlr
gsup
bind ip 127.0.0.1
ipa-name testHLR-1
ussd route prefix *0# internal own-msisdn
ussd route prefix *1# internal own-imsi
ussd route prefix *#100# internal own-msisdn
ussd route prefix *#101# internal own-imsi
store-imei
line vty
bind 127.0.0.1
ctrl
bind 127.0.0.1
mslookup
mdns
log stderr
logging filter all 1
logging color 1
logging print level 1
logging print category 1
logging print category-hex 0
logging print file basename last
logging print extended-timestamp 1
logging level set-all debug
logging level linp error
log gsmtap 127.0.0.1
logging filter all 1
logging color 1
logging print level 1
logging print category 1
logging print category-hex 0
logging print file basename last
logging print extended-timestamp 1
logging level set-all debug
logging level linp error

View File

@ -0,0 +1,40 @@
hlr
gsup
bind ip 127.0.0.2
ipa-name testHLR-2
ussd route prefix *0# internal own-msisdn
ussd route prefix *1# internal own-imsi
ussd route prefix *#100# internal own-msisdn
ussd route prefix *#101# internal own-imsi
store-imei
line vty
bind 127.0.0.2
ctrl
bind 127.0.0.2
mslookup
mdns
log stderr
logging filter all 1
logging color 1
logging print level 1
logging print category 1
logging print category-hex 0
logging print file basename last
logging timestamp 1
logging level set-all debug
logging level linp error
log gsmtap 127.0.0.1
logging filter all 1
logging color 1
logging print level 1
logging print category 1
logging print category-hex 0
logging print file basename last
logging print extended-timestamp 1
logging level set-all debug
logging level linp error

View File

@ -0,0 +1,22 @@
#!/bin/sh
srcdir="${1:-.}"
builddir="${2:-.}"
cd "$builddir"
osmo-hlr -c "$srcdir/osmo-hlr-1.cfg" -l hlr1.db &
sleep 1
osmo-hlr -c "$srcdir/osmo-hlr-2.cfg" -l hlr2.db &
sleep 1
osmo_interact_vty.py -H 127.0.0.1 -p 4258 -c 'enable; subscriber imsi 111111 create; subscriber imsi 111111 update msisdn 1'
osmo_interact_vty.py -H 127.0.0.2 -p 4258 -c 'enable; subscriber imsi 222222 create; subscriber imsi 222222 update msisdn 2'
sleep 1
./fake_msc &
echo enter to exit
read enter_to_exit
kill %1 %2 %3
killall osmo-hlr
killall fake_msc