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 #include +#include + /* 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 #include +#include #include #include #include + #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 +#include #include +#include + #include +#include -#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next) -#define llist_first(head, type, entry) llist_entry(__llist_first(head), type, entry) +/* TODO split GRX ares from sgsn into a separate struct and allow use without + * globals. */ +#include +extern struct sgsn_instance *sgsn; -int gtphub_resolve_ggsn_addr(struct gtphub *hub, - struct osmo_sockaddr *result, - struct gtp_packet_desc *p) +struct sgsn_instance sgsn_inst = { 0 }; +struct sgsn_instance *sgsn = &sgsn_inst; + +extern void *osmo_gtphub_ctx; + +int gtphub_ares_init(struct gtphub *hub) { - /* 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; + 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); + +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; + } + + 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) +{ + 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 gtphub_peer_port *__real_gtphub_resolve_ggsn_addr(struct gtphub *hub, + const char *imsi_str, + const char *apn_ni_str); -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 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) { - 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; + 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) +{ + /* 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