summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/gtphub.h28
-rw-r--r--openbsc/src/gprs/Makefile.am6
-rw-r--r--openbsc/src/gprs/gprs_utils.c4
-rw-r--r--openbsc/src/gprs/gtphub.c151
-rw-r--r--openbsc/src/gprs/gtphub_ext.c174
-rw-r--r--openbsc/src/gprs/sgsn_vty.c5
-rw-r--r--openbsc/tests/gtphub/Makefile.am4
-rw-r--r--openbsc/tests/gtphub/gtphub_test.c132
-rw-r--r--openbsc/tests/gtphub/gtphub_test.ok4
9 files changed, 388 insertions, 120 deletions
diff --git a/openbsc/include/openbsc/gtphub.h b/openbsc/include/openbsc/gtphub.h
index 5298505db..05eee851e 100644
--- a/openbsc/include/openbsc/gtphub.h
+++ b/openbsc/include/openbsc/gtphub.h
@@ -27,6 +27,8 @@
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
+#include <openbsc/gprs_sgsn.h>
+
/* support */
@@ -363,6 +365,18 @@ struct gtphub_bind {
struct llist_head peers;
};
+struct gtphub_resolved_ggsn {
+ struct llist_head entry;
+ struct expiring_item expiry_entry;
+
+ /* The APN OI, the Operator Identifier, is the combined address,
+ * including parts of the IMSI and APN NI, and ending with ".gprs". */
+ char apn_oi_str[GSM_APN_LENGTH];
+
+ /* Which address and port we resolved that to. */
+ struct gtphub_peer_port *peer;
+};
+
struct gtphub {
struct gtphub_bind to_sgsns[GTPH_PLANE_N];
struct gtphub_bind to_ggsns[GTPH_PLANE_N];
@@ -376,6 +390,9 @@ struct gtphub {
struct nr_map tei_map[GTPH_PLANE_N];
struct nr_pool tei_pool[GTPH_PLANE_N];
+ struct llist_head ggsn_lookups; /* opaque (gtphub_ext.c) */
+ struct llist_head resolved_ggsns; /* struct gtphub_resolved_ggsn */
+
struct osmo_timer_list gc_timer;
struct expiry expire_seq_maps;
struct expiry expire_tei_maps;
@@ -420,5 +437,16 @@ int gtphub_from_ggsns_handle_buf(struct gtphub *hub,
struct osmo_fd **to_ofd,
struct osmo_sockaddr *to_addr);
+struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
+ struct gtphub_bind *bind,
+ const struct gsn_addr *addr,
+ uint16_t port);
+
struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind,
const struct osmo_sockaddr *addr);
+
+void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str,
+ struct gsn_addr *resolved_addr,
+ time_t now);
+
+const char *gtphub_port_str(struct gtphub_peer_port *port);
diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am
index 0dd38f99c..5212c67f2 100644
--- a/openbsc/src/gprs/Makefile.am
+++ b/openbsc/src/gprs/Makefile.am
@@ -35,7 +35,9 @@ osmo_sgsn_LDADD = \
-lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \
$(LIBCRYPTO_LIBS) -lrt
-osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_ext.c gtphub_vty.c
+osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_ext.c gtphub_vty.c \
+ sgsn_ares.c gprs_utils.c
osmo_gtphub_LDADD = \
$(top_builddir)/src/libcommon/libcommon.a \
- -lgtp $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) -lrt
+ -lgtp $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \
+ $(LIBCARES_LIBS) -lrt
diff --git a/openbsc/src/gprs/gprs_utils.c b/openbsc/src/gprs/gprs_utils.c
index 2293f0254..ad479db81 100644
--- a/openbsc/src/gprs/gprs_utils.c
+++ b/openbsc/src/gprs/gprs_utils.c
@@ -114,7 +114,9 @@ int gprs_msgb_resize_area(struct msgb *msg, uint8_t *area,
}
/* TODO: Move these conversion functions to a utils file. */
-/**
+/* TODO: consolidate with gprs_apn2str(). */
+/** memmove apn_enc to out_str, replacing the length octets in apn_enc with '.'
+ * (omitting the first one) and terminating with a '\0'.
* out_str needs to have rest_chars amount of bytes or 1 whatever is bigger.
*/
char * gprs_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t rest_chars)
diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c
index 440f00fe3..eae4cf2cf 100644
--- a/openbsc/src/gprs/gtphub.c
+++ b/openbsc/src/gprs/gtphub.c
@@ -33,11 +33,13 @@
#include <openbsc/gtphub.h>
#include <openbsc/debug.h>
+#include <openbsc/gprs_utils.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/socket.h>
+
#define GTPHUB_DEBUG 1
static const int GTPH_GC_TICK_SECONDS = 1;
@@ -345,13 +347,13 @@ void validate_gtp_header(struct gtp_packet_desc *p)
* The first IEI is reached by passing i = 0.
* imsi must point at allocated space of (at least) 8 bytes.
* Return 1 on success, or 0 if not found. */
-static int get_ie_imsi(union gtpie_member *ie[], uint8_t *imsi, int i)
+static int get_ie_imsi(union gtpie_member *ie[], int i, uint8_t *imsi)
{
return gtpie_gettv0(ie, GTPIE_IMSI, i, imsi, 8) == 0;
}
/* Analogous to get_ie_imsi(). nsapi must point at a single uint8_t. */
-static int get_ie_nsapi(union gtpie_member *ie[], uint8_t *nsapi, int i)
+static int get_ie_nsapi(union gtpie_member *ie[], int i, uint8_t *nsapi)
{
return gtpie_gettv1(ie, GTPIE_NSAPI, i, nsapi) == 0;
}
@@ -379,6 +381,33 @@ static const char *imsi_to_str(uint8_t *imsi)
return str;
}
+static const char *get_ie_imsi_str(union gtpie_member *ie[], int i)
+{
+ uint8_t imsi_buf[8];
+ if (!get_ie_imsi(ie, i, imsi_buf))
+ return NULL;
+ return imsi_to_str(imsi_buf);
+}
+
+static const char *get_ie_apn_str(union gtpie_member *ie[])
+{
+ static char apn_buf[GSM_APN_LENGTH];
+ unsigned int len;
+ if (gtpie_gettlv(ie, GTPIE_APN, 0,
+ &len, apn_buf, sizeof(apn_buf)) != 0)
+ return NULL;
+
+ if (!len)
+ return NULL;
+
+ if (len > (sizeof(apn_buf) - 1))
+ len = sizeof(apn_buf) - 1;
+ apn_buf[len] = '\0';
+
+ return gprs_apn_to_str(apn_buf, (uint8_t*)apn_buf, len);
+}
+
+
/* Validate header, and index information elements. Write decoded packet
* information to *res. res->data will point at the given data buffer. On
* error, p->rc is set <= 0 (see enum gtp_rc). */
@@ -416,15 +445,15 @@ static void gtp_decode(const uint8_t *data, int data_len,
int i;
for (i = 0; i < 10; i++) {
- uint8_t imsi[8];
- if (!get_ie_imsi(res->ie, imsi, i))
+ const char *imsi = get_ie_imsi_str(res->ie, i);
+ if (!imsi)
break;
- LOG("| IMSI %s\n", imsi_to_str(imsi));
+ LOG("| IMSI %s\n", imsi);
}
for (i = 0; i < 10; i++) {
uint8_t nsapi;
- if (!get_ie_nsapi(res->ie, &nsapi, i))
+ if (!get_ie_nsapi(res->ie, i, &nsapi))
break;
LOG("| NSAPI %d\n", (int)nsapi);
}
@@ -481,7 +510,6 @@ int expiry_tick(struct expiry *exq, time_t now)
expiring_item_del(m);
expired ++;
} else {
- LOG("Not expired: %d > %d\n", (int)m->expiry, (int)now);
/* The items are added sorted by expiry. So when we hit
* an unexpired entry, only more unexpired ones will
* follow. */
@@ -654,19 +682,15 @@ static struct gtphub_peer_port *gtphub_resolve_ggsn(struct gtphub *hub,
struct gtp_packet_desc *p);
/* See gtphub_ext.c (wrapped by unit test) */
-int gtphub_resolve_ggsn_addr(struct gtphub *hub,
- struct osmo_sockaddr *result,
- struct gtp_packet_desc *p);
+struct gtphub_peer_port *gtphub_resolve_ggsn_addr(struct gtphub *hub,
+ const char *imsi_str,
+ const char *apn_ni_str);
+int gtphub_ares_init(struct gtphub *hub);
static struct gtphub_peer_port *gtphub_port_find(const struct gtphub_bind *bind,
const struct gsn_addr *addr,
uint16_t port);
-static struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
- struct gtphub_bind *bind,
- const struct gsn_addr *addr,
- uint16_t port);
-
static void gtphub_zero(struct gtphub *hub)
{
ZERO_STRUCT(hub);
@@ -833,7 +857,7 @@ const char *gtphub_peer_str2(struct gtphub_peer *peer)
return gtphub_peer_strb(peer, buf, sizeof(buf));
}
-static const char *gtphub_port_str(struct gtphub_peer_port *port)
+const char *gtphub_port_str(struct gtphub_peer_port *port)
{
static char buf[256];
return gtphub_port_strb(port, buf, sizeof(buf));
@@ -1562,6 +1586,49 @@ int gtphub_from_sgsns_handle_buf(struct gtphub *hub,
return received;
}
+static void resolved_gssn_del_cb(struct expiring_item *expi)
+{
+ struct gtphub_resolved_ggsn *ggsn;
+ ggsn = container_of(expi, struct gtphub_resolved_ggsn, expiry_entry);
+
+ gtphub_port_ref_count_dec(ggsn->peer);
+ llist_del(&ggsn->entry);
+
+ ggsn->expiry_entry.del_cb = 0;
+ expiring_item_del(&ggsn->expiry_entry);
+
+ talloc_free(ggsn);
+}
+
+void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str,
+ struct gsn_addr *resolved_addr,
+ time_t now)
+{
+ struct gtphub_peer_port *pp;
+ struct gtphub_resolved_ggsn *ggsn;
+
+ pp = gtphub_port_have(hub, &hub->to_ggsns[GTPH_PLANE_CTRL],
+ resolved_addr, 2123);
+ if (!pp) {
+ LOGERR("Internal: Cannot create/find peer '%s'\n",
+ gsn_addr_to_str(resolved_addr));
+ return;
+ }
+
+ ggsn = talloc_zero(osmo_gtphub_ctx, struct gtphub_resolved_ggsn);
+ OSMO_ASSERT(ggsn);
+
+ ggsn->peer = pp;
+ gtphub_port_ref_count_inc(pp);
+
+ strncpy(ggsn->apn_oi_str, apn_oi_str, sizeof(ggsn->apn_oi_str));
+
+ ggsn->expiry_entry.del_cb = resolved_gssn_del_cb;
+ expiry_add(&hub->expire_tei_maps, &ggsn->expiry_entry, now);
+
+ llist_add(&ggsn->entry, &hub->resolved_ggsns);
+}
+
static int gtphub_gc_peer_port(struct gtphub_peer_port *pp)
{
return pp->ref_count == 0;
@@ -1654,6 +1721,8 @@ void gtphub_init(struct gtphub *hub)
{
gtphub_zero(hub);
+ INIT_LLIST_HEAD(&hub->resolved_ggsns);
+
expiry_init(&hub->expire_seq_maps, GTPH_SEQ_MAPPING_EXPIRY_SECS);
expiry_init(&hub->expire_tei_maps, GTPH_TEI_MAPPING_EXPIRY_MINUTES * 60);
@@ -1693,6 +1762,7 @@ int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg)
int rc;
gtphub_init(hub);
+ gtphub_ares_init(hub);
int plane_idx;
for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) {
@@ -1882,10 +1952,10 @@ static struct gtphub_peer_port *gtphub_addr_add_port(struct gtphub_peer_addr *a,
return pp;
}
-static struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
- struct gtphub_bind *bind,
- const struct gsn_addr *addr,
- uint16_t port)
+struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
+ struct gtphub_bind *bind,
+ const struct gsn_addr *addr,
+ uint16_t port)
{
struct gtphub_peer_addr *a = gtphub_addr_have(hub, bind, addr);
@@ -1896,47 +1966,12 @@ static struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
return gtphub_addr_add_port(a, port);
}
-/* port_override: <=0: use port from addr; >0: use this number as port. Return
- * NULL if the address cannot be parsed. */
-static struct gtphub_peer_port *gtphub_port_have_sockaddr(struct gtphub *hub,
- struct gtphub_bind *bind,
- const struct osmo_sockaddr *addr,
- int port_override)
-{
- struct gsn_addr gsna;
- uint16_t port;
- if (gsn_addr_from_sockaddr(&gsna, &port, addr) != 0)
- return NULL;
-
- if (port_override > 0)
- port = port_override;
- return gtphub_port_have(hub, bind, &gsna, port);
-}
-
-static struct gtphub_peer_port *gtphub_have_ggsn(struct gtphub *hub,
- struct osmo_sockaddr *addr,
- unsigned int plane_idx,
- int port_override)
-{
- if (port_override == 0)
- port_override = gtphub_plane_idx_default_port[plane_idx];
-
- return gtphub_port_have_sockaddr(hub, &hub->to_ggsns[plane_idx], addr,
- port_override);
-}
-
static struct gtphub_peer_port *gtphub_resolve_ggsn(struct gtphub *hub,
struct gtp_packet_desc *p)
{
- int rc;
-
- struct osmo_sockaddr addr;
-
- rc = gtphub_resolve_ggsn_addr(hub, &addr, p);
- if (rc < 0)
- return NULL;
-
- return gtphub_have_ggsn(hub, &addr, p->plane_idx, -1);
+ return gtphub_resolve_ggsn_addr(hub,
+ get_ie_imsi_str(p->ie, 0),
+ get_ie_apn_str(p->ie));
}
diff --git a/openbsc/src/gprs/gtphub_ext.c b/openbsc/src/gprs/gtphub_ext.c
index 0a4164c73..d739614ca 100644
--- a/openbsc/src/gprs/gtphub_ext.c
+++ b/openbsc/src/gprs/gtphub_ext.c
@@ -24,35 +24,161 @@
*/
#include <string.h>
+#include <unistd.h>
#include <openbsc/gtphub.h>
+#include <openbsc/debug.h>
+
#include <osmocom/core/utils.h>
+#include <osmocom/gsm/apn.h>
+
+/* TODO split GRX ares from sgsn into a separate struct and allow use without
+ * globals. */
+#include <openbsc/sgsn.h>
+extern struct sgsn_instance *sgsn;
+
+struct sgsn_instance sgsn_inst = { 0 };
+struct sgsn_instance *sgsn = &sgsn_inst;
+
+extern void *osmo_gtphub_ctx;
+
+int gtphub_ares_init(struct gtphub *hub)
+{
+ return sgsn_ares_init(sgsn);
+}
+
+struct ggsn_lookup {
+ struct llist_head entry;
+ struct expiring_item expiry_entry;
+
+ struct gtphub *hub;
+
+ char imsi_str[GSM_IMSI_LENGTH];
+ char apn_ni_str[GSM_APN_LENGTH];
+ char apn_oi_str[GSM_APN_LENGTH];
+ int have_3dig_mnc;
+};
+
+static int start_ares_query(struct ggsn_lookup *lookup);
-#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next)
-#define llist_first(head, type, entry) llist_entry(__llist_first(head), type, entry)
+static void ggsn_lookup_cb(void *arg, int status, int timeouts, struct hostent *hostent)
+{
+ struct ggsn_lookup *lookup = arg;
+
+ if (status != ARES_SUCCESS) {
+ LOGP(DGTPHUB, LOGL_ERROR, "DNS query failed.\n");
+
+ /* Need to try with three digits now */
+ if (!lookup->have_3dig_mnc) {
+ lookup->have_3dig_mnc = 1;
+ if (start_ares_query(lookup) == 0)
+ return;
+ }
+
+ LOGP(DGTPHUB, LOGL_ERROR, "Failed to resolve GGSN.\n");
+ goto remove_from_queue;
+ }
+
+ struct gsn_addr resolved_addr;
+ if (hostent->h_length > sizeof(resolved_addr.buf)) {
+ LOGP(DGTPHUB, LOGL_ERROR, "Addr size too large: %d > %d\n",
+ (int)hostent->h_length, (int)sizeof(resolved_addr.buf));
+ goto remove_from_queue;
+ }
+
+ /* Get the first addr from the list */
+ char *addr0 = hostent->h_addr_list[0];
+ if (!addr0) {
+ LOGP(DGTPHUB, LOGL_ERROR, "No host address.\n");
+ goto remove_from_queue;
+ }
-int gtphub_resolve_ggsn_addr(struct gtphub *hub,
- struct osmo_sockaddr *result,
- struct gtp_packet_desc *p)
+ memcpy(&resolved_addr.buf, addr0, hostent->h_length);
+ resolved_addr.len = hostent->h_length;
+
+ gtphub_resolved_ggsn(lookup->hub, lookup->apn_oi_str, &resolved_addr,
+ gtphub_now());
+
+remove_from_queue:
+ expiring_item_del(&lookup->expiry_entry);
+}
+
+static void make_addr_str(struct ggsn_lookup *lookup)
{
- /* TODO This is just hardcodedly returning the first known address.
- * Should resolve from actual subscriber data. */
- struct gtphub_peer *peer = llist_first(&hub->to_ggsns[GTPH_PLANE_CTRL].peers,
- struct gtphub_peer, entry);
- if (!peer)
- return -1;
-
- struct gtphub_peer_addr *pa = llist_first(&peer->addresses,
- struct gtphub_peer_addr, entry);
- if (!pa)
- return -1;
-
- struct gtphub_peer_port *pp = llist_first(&pa->ports,
- struct gtphub_peer_port, entry);
- if (!pp)
- return -1;
-
- *result = pp->sa;
- return 0;
+ char *apn_oi_str;
+ apn_oi_str = osmo_apn_qualify_from_imsi(lookup->imsi_str,
+ lookup->apn_ni_str,
+ lookup->have_3dig_mnc);
+ strncpy(lookup->apn_oi_str, apn_oi_str, sizeof(lookup->apn_oi_str));
+ lookup->apn_oi_str[sizeof(lookup->apn_oi_str)-1] = '\0';
}
+static int start_ares_query(struct ggsn_lookup *lookup)
+{
+ LOGP(DGTPHUB, LOGL_DEBUG, "Going to query %s\n", lookup->apn_oi_str);
+
+ int rc = sgsn_ares_query(sgsn, lookup->apn_oi_str, ggsn_lookup_cb, &lookup);
+ if (rc != 0)
+ LOGP(DGTPHUB, LOGL_ERROR, "Failed to start ares query.\n");
+ return rc;
+}
+
+static void ggsn_lookup_del_cb(struct expiring_item *expi)
+{
+ struct ggsn_lookup *ggsn;
+ ggsn = container_of(expi, struct ggsn_lookup, expiry_entry);
+
+ ggsn->expiry_entry.del_cb = 0;
+ expiring_item_del(expi);
+
+ llist_del(&ggsn->entry);
+ talloc_free(ggsn);
+}
+
+struct gtphub_peer_port *gtphub_resolve_ggsn_addr(struct gtphub *hub,
+ const char *imsi_str,
+ const char *apn_ni_str)
+{
+ struct ggsn_lookup *lookup = talloc_zero(osmo_gtphub_ctx, struct ggsn_lookup);
+
+ lookup->hub = hub;
+
+ strncpy(lookup->imsi_str, imsi_str, sizeof(lookup->imsi_str));
+ lookup->imsi_str[sizeof(lookup->imsi_str)-1] = '\0';
+
+ strncpy(lookup->apn_ni_str, apn_ni_str, sizeof(lookup->apn_ni_str));
+ lookup->apn_ni_str[sizeof(lookup->apn_ni_str)-1] = '\0';
+
+ make_addr_str(lookup);
+
+ struct ggsn_lookup *active;
+ llist_for_each_entry(active, &hub->ggsn_lookups, entry) {
+ if (strncmp(active->apn_oi_str, lookup->apn_oi_str,
+ sizeof(lookup->apn_oi_str)) == 0) {
+ /* A query already pending. Just tip our hat. */
+ return NULL;
+ }
+ }
+
+ struct gtphub_resolved_ggsn *resolved;
+ llist_for_each_entry(resolved, &hub->resolved_ggsns, entry) {
+ if (strncmp(resolved->apn_oi_str, lookup->apn_oi_str,
+ sizeof(lookup->apn_oi_str)) == 0) {
+ /* Already resolved. */
+ return resolved->peer;
+ }
+ }
+
+ /* Kick off a resolution, but so far return nothing. The hope is that
+ * the peer will resend the request (a couple of times), and by then
+ * the GGSN will be resolved. */
+
+ llist_add(&lookup->entry, &hub->ggsn_lookups);
+
+ lookup->expiry_entry.del_cb = ggsn_lookup_del_cb;
+ expiry_add(&hub->expire_seq_maps, &lookup->expiry_entry, gtphub_now());
+
+ start_ares_query(lookup);
+
+ return NULL;
+}
diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c
index 3a73c9f55..3f6116393 100644
--- a/openbsc/src/gprs/sgsn_vty.c
+++ b/openbsc/src/gprs/sgsn_vty.c
@@ -110,6 +110,11 @@ DECLARE_TIMER(3397, "Wait for DEACT AA PDP CTX ACK timer (s)")
#define GSM48_MAX_APN_LEN 102 /* 10.5.6.1 */
+/* TODO: consolidate with gprs_apn_to_str(). */
+/** Copy apn to a static buffer, replacing the length octets in apn_enc with '.'
+ * and terminating with a '\0'. Return the static buffer.
+ * len: the length of the encoded APN (which has no terminating zero).
+ */
static char *gprs_apn2str(uint8_t *apn, unsigned int len)
{
static char apnbuf[GSM48_MAX_APN_LEN+1];
diff --git a/openbsc/tests/gtphub/Makefile.am b/openbsc/tests/gtphub/Makefile.am
index ecc6d62f0..d818811d9 100644
--- a/openbsc/tests/gtphub/Makefile.am
+++ b/openbsc/tests/gtphub/Makefile.am
@@ -11,10 +11,12 @@ noinst_PROGRAMS = gtphub_test
gtphub_test_SOURCES = gtphub_test.c
gtphub_test_LDFLAGS = \
- -Wl,--wrap=gtphub_resolve_ggsn_addr
+ -Wl,--wrap=gtphub_resolve_ggsn_addr \
+ -Wl,--wrap=gtphub_ares_init
gtphub_test_LDADD = \
$(top_builddir)/src/gprs/gtphub.o \
+ $(top_builddir)/src/gprs/gprs_utils.o \
$(LIBOSMOCORE_LIBS) \
-lgtp -lrt
diff --git a/openbsc/tests/gtphub/gtphub_test.c b/openbsc/tests/gtphub/gtphub_test.c
index af8f3ed75..81875f1c7 100644
--- a/openbsc/tests/gtphub/gtphub_test.c
+++ b/openbsc/tests/gtphub/gtphub_test.c
@@ -37,8 +37,6 @@
#define EXPIRE_ALL ((60 * GTPH_TEI_MAPPING_EXPIRY_MINUTES) + 1)
-/* Make non-public API accessible */
-
void gtphub_init(struct gtphub *hub);
void *osmo_gtphub_ctx;
@@ -328,19 +326,75 @@ static void test_expiry(void)
/* override, requires '-Wl,--wrap=gtphub_resolve_ggsn_addr' */
-int __real_gtphub_resolve_ggsn_addr(struct gtphub *hub,
- struct osmo_sockaddr *result,
- struct gtp_packet_desc *p);
-
-struct osmo_sockaddr resolved_ggsn_addr = {.l = 0};
-int __wrap_gtphub_resolve_ggsn_addr(struct gtphub *hub,
- struct osmo_sockaddr *result,
- struct gtp_packet_desc *p)
+struct gtphub_peer_port *__real_gtphub_resolve_ggsn_addr(struct gtphub *hub,
+ const char *imsi_str,
+ const char *apn_ni_str);
+
+struct gsn_addr resolved_ggsn_addr = { 0 };
+uint16_t resolved_ggsn_port = 2123;
+char resolve_ggsn_got_imsi[256];
+char resolve_ggsn_got_ni[256];
+struct gtphub_peer_port *__wrap_gtphub_resolve_ggsn_addr(struct gtphub *hub,
+ const char *imsi_str,
+ const char *apn_ni_str)
+{
+ struct gtphub_peer_port *pp;
+ pp = gtphub_port_have(hub, &hub->to_ggsns[GTPH_PLANE_CTRL],
+ &resolved_ggsn_addr, resolved_ggsn_port);
+ printf("Wrap: returning GGSN addr from imsi %s ni %s: %s\n",
+ imsi_str, apn_ni_str, gtphub_port_str(pp));
+
+ if (imsi_str) {
+ strncpy(resolve_ggsn_got_imsi, imsi_str, sizeof(resolve_ggsn_got_imsi));
+ resolve_ggsn_got_imsi[sizeof(resolve_ggsn_got_imsi) - 1] = '\0';
+ }
+ else
+ strcpy(resolve_ggsn_got_imsi, "(null)");
+
+ if (apn_ni_str) {
+ strncpy(resolve_ggsn_got_ni, apn_ni_str, sizeof(resolve_ggsn_got_ni));
+ resolve_ggsn_got_ni[sizeof(resolve_ggsn_got_ni) - 1] = '\0';
+ }
+ else
+ strcpy(resolve_ggsn_got_ni, "(null)");
+
+ return pp;
+}
+
+#define was_resolved_for(IMSI,NI) _was_resolved_for(IMSI, NI, __FILE__, __LINE__)
+static int _was_resolved_for(const char *imsi, const char *ni, const char *file, int line)
+{
+ int cmp0 = strncmp(imsi, resolve_ggsn_got_imsi, sizeof(resolve_ggsn_got_imsi));
+
+ if (cmp0 != 0) {
+ printf("\n%s:%d: was_resolved_for(): MISMATCH for IMSI\n"
+ " expecting: '%s'\n"
+ " got: '%s'\n\n",
+ file,
+ line,
+ imsi, resolve_ggsn_got_imsi);
+ }
+
+ int cmp1 = strncmp(ni, resolve_ggsn_got_ni, sizeof(resolve_ggsn_got_ni));
+ if (cmp1 != 0) {
+ printf("\n%s:%d: was_resolved_for(): MISMATCH for NI\n"
+ " expecting: '%s'\n"
+ " got: '%s'\n\n",
+ file,
+ line,
+ ni, resolve_ggsn_got_ni);
+ }
+
+ return (cmp0 == 0) && (cmp1 == 0);
+}
+
+/* override, requires '-Wl,--wrap=gtphub_ares_init' */
+int __real_gtphub_ares_init(struct gtphub *hub);
+
+int __wrap_gtphub_ares_init(struct gtphub *hub)
{
- osmo_sockaddr_copy(result, &resolved_ggsn_addr);
- printf("Wrap: returning GGSN addr: %s\n",
- osmo_sockaddr_to_str(result));
- return (resolved_ggsn_addr.l != 0)? 0 : -1;
+ /* Do nothing. */
+ return 0;
}
#define buf_len 1024
@@ -413,6 +467,9 @@ static void test_echo(void)
gtphub_init(hub);
+ /* TODO This test should test for gtphub echoing back to each side.
+ * Echos must not be routed through. */
+
const char *gtp_ping_from_sgsn =
"32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr. */
"01" /* type 01: Echo request */
@@ -444,16 +501,17 @@ static void test_echo(void)
"00" "00" "0e01";
/* Set the GGSN address that gtphub is forced to resolve to. */
- OSMO_ASSERT(osmo_sockaddr_init_udp(&resolved_ggsn_addr,
- "192.168.43.34", 434)
+ const char *resolved_ggsn_str = "192.168.43.34";
+ resolved_ggsn_port = 434;
+ OSMO_ASSERT(gsn_addr_from_str(&resolved_ggsn_addr, resolved_ggsn_str)
== 0);
- /* according to spec, we'd always send to port 2123 instead...
- struct osmo_sockaddr ggsn_standard_port;
- OSMO_ASSERT(osmo_sockaddr_init_udp(&ggsn_standard_port,
- "192.168.43.34", 2123)
+ /* A sockaddr for comparing later */
+ struct osmo_sockaddr resolved_ggsn_sa;
+ OSMO_ASSERT(osmo_sockaddr_init_udp(&resolved_ggsn_sa,
+ resolved_ggsn_str,
+ resolved_ggsn_port)
== 0);
- */
struct osmo_sockaddr orig_sgsn_addr;
OSMO_ASSERT(osmo_sockaddr_init(&orig_sgsn_addr,
@@ -467,7 +525,7 @@ static void test_echo(void)
&ggsn_ofd, &ggsn_addr);
OSMO_ASSERT(send > 0);
OSMO_ASSERT(ggsn_addr.l);
- OSMO_ASSERT(same_addr(&ggsn_addr, &resolved_ggsn_addr));
+ OSMO_ASSERT(same_addr(&ggsn_addr, &resolved_ggsn_sa));
OSMO_ASSERT(msg_is(gtp_ping_to_ggsn));
struct osmo_fd *sgsn_ofd;
@@ -481,7 +539,7 @@ static void test_echo(void)
struct gtphub_peer_port *ggsn_port =
gtphub_port_find_sa(&hub->to_ggsns[GTPH_PLANE_CTRL],
- &resolved_ggsn_addr);
+ &resolved_ggsn_sa);
OSMO_ASSERT(ggsn_port);
struct gtphub_peer *ggsn = ggsn_port->peer_addr->peer;
/* now == 123; now + 30 == 153. */
@@ -515,7 +573,7 @@ static void test_create_pdp_ctx(void)
const char *gtp_req_from_sgsn =
"32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr. */
"10" /* type 16: Create PDP Context Request */
- "0067" /* length = 8 + 103 */
+ "0068" /* length = 8 + 104 */
"00000000" /* No TEI yet */
"abcd" /* Sequence nr */
"00" /* N-PDU 0 */
@@ -536,8 +594,8 @@ static void test_create_pdp_ctx(void)
"0002" /* length = 2: empty PDP Address */
"f121" /* spare 0xf0, PDP organization 1, PDP type number 0x21 = 33 */
"83" /* 131: Access Point Name */
- "0008" /* length = 8 */
- "696e7465726e6574" /* "internet" */
+ "0009" /* length */
+ "08696e7465726e6574" /* "internet" */
"84" /* 132: Protocol Configuration Options */
"0015" /* length = 21 */
"80c0231101010011036d69670868656d6d656c6967"
@@ -557,13 +615,13 @@ static void test_create_pdp_ctx(void)
;
const char *gtp_req_to_ggsn =
- "32" "10" "0067" "00000000"
+ "32" "10" "0068" "00000000"
"6d31" /* mapped seq ("abcd") */
"00" "00" "02" "42000121436587f9" "0e60" "0f01"
"10" "00000001" /* mapped TEI Data I ("123") */
"11" "00000001" /* mapped TEI Control ("321") */
"1400" "1a" "0800" "80" "0002" "f121" "83"
- "0008" "696e7465726e6574" "84" "0015"
+ "0009" "08696e7465726e6574" "84" "0015"
"80c0231101010011036d69670868656d6d656c6967" "85" "0004"
"7f000201" /* replaced with gtphub's address ggsn ctrl */
"85" "0004"
@@ -627,14 +685,23 @@ static void test_create_pdp_ctx(void)
;
/* Set the GGSN address that gtphub is forced to resolve to. */
- OSMO_ASSERT(osmo_sockaddr_init_udp(&resolved_ggsn_addr,
- "192.168.43.34", 434)
+ const char *resolved_ggsn_str = "192.168.43.34";
+ resolved_ggsn_port = 434;
+ OSMO_ASSERT(gsn_addr_from_str(&resolved_ggsn_addr, resolved_ggsn_str)
+ == 0);
+
+ /* A sockaddr for comparing later */
+ struct osmo_sockaddr resolved_ggsn_sa;
+ OSMO_ASSERT(osmo_sockaddr_init_udp(&resolved_ggsn_sa,
+ resolved_ggsn_str,
+ resolved_ggsn_port)
== 0);
struct osmo_sockaddr orig_sgsn_addr;
OSMO_ASSERT(osmo_sockaddr_init(&orig_sgsn_addr,
AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
"192.168.42.23", 423) == 0);
+
struct osmo_fd *ggsn_ofd = NULL;
struct osmo_sockaddr ggsn_addr;
int send;
@@ -642,8 +709,9 @@ static void test_create_pdp_ctx(void)
buf, msg(gtp_req_from_sgsn), now,
&ggsn_ofd, &ggsn_addr);
OSMO_ASSERT(send > 0);
- OSMO_ASSERT(same_addr(&ggsn_addr, &resolved_ggsn_addr));
+ OSMO_ASSERT(same_addr(&ggsn_addr, &resolved_ggsn_sa));
OSMO_ASSERT(msg_is(gtp_req_to_ggsn));
+ OSMO_ASSERT(was_resolved_for("240010123456789", "internet"));
struct osmo_fd *sgsn_ofd;
struct osmo_sockaddr sgsn_addr;
@@ -656,7 +724,7 @@ static void test_create_pdp_ctx(void)
struct gtphub_peer_port *ggsn_port =
gtphub_port_find_sa(&hub->to_ggsns[GTPH_PLANE_CTRL],
- &resolved_ggsn_addr);
+ &resolved_ggsn_sa);
OSMO_ASSERT(ggsn_port);
struct gtphub_peer *ggsn = ggsn_port->peer_addr->peer;
/* now == 345; now + 30 == 375.
diff --git a/openbsc/tests/gtphub/gtphub_test.ok b/openbsc/tests/gtphub/gtphub_test.ok
index 7be13fe86..8d1075ab7 100644
--- a/openbsc/tests/gtphub/gtphub_test.ok
+++ b/openbsc/tests/gtphub/gtphub_test.ok
@@ -1,3 +1,3 @@
-Wrap: returning GGSN addr: 192.168.43.34 port 434
-Wrap: returning GGSN addr: 192.168.43.34 port 434
+Wrap: returning GGSN addr from imsi (null) ni (null): 192.168.43.34 port 434
+Wrap: returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 434
Done