hlr mslookup and gsup proxy works for the first time
Change-Id: I546ca786308fed557703321bed2935e0adcbe0ee
This commit is contained in:
parent
749e42902d
commit
2975bcbc2f
|
@ -188,4 +188,5 @@ AC_OUTPUT(
|
|||
tests/gsup/Makefile
|
||||
tests/db/Makefile
|
||||
tests/db_upgrade/Makefile
|
||||
tests/mslookup_manual_test/Makefile
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,"
|
||||
|
|
320
src/dgsm.c
320
src/dgsm.c
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
23
src/hlr.c
23
src/hlr.c
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
11
src/luop.c
11
src/luop.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
13
src/proxy.c
13
src/proxy.c
|
@ -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);
|
||||
|
|
10
src/proxy.h
10
src/proxy.h
|
@ -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);
|
||||
|
|
101
src/remote_hlr.c
101
src/remote_hlr.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
Loading…
Reference in New Issue