gtphub: fix Echo behavior: respond directly.
Up to now I used the Echo as a test for sequence nr mappings. But Echos should be handled differently: they are scoped on the link and an Echo response should be sent right back to the requester. Sponsored-by: On-Waves ehi
This commit is contained in:
parent
30f7bcbd79
commit
bb3d6785e1
|
@ -396,6 +396,8 @@ struct gtphub {
|
|||
struct osmo_timer_list gc_timer;
|
||||
struct expiry expire_seq_maps;
|
||||
struct expiry expire_tei_maps;
|
||||
|
||||
uint16_t restart_counter;
|
||||
};
|
||||
|
||||
struct gtp_packet_desc;
|
||||
|
@ -425,6 +427,7 @@ int gtphub_from_sgsns_handle_buf(struct gtphub *hub,
|
|||
uint8_t *buf,
|
||||
size_t received,
|
||||
time_t now,
|
||||
uint8_t **reply_buf,
|
||||
struct osmo_fd **to_ofd,
|
||||
struct osmo_sockaddr *to_addr);
|
||||
|
||||
|
@ -434,6 +437,7 @@ int gtphub_from_ggsns_handle_buf(struct gtphub *hub,
|
|||
uint8_t *buf,
|
||||
size_t received,
|
||||
time_t now,
|
||||
uint8_t **reply_buf,
|
||||
struct osmo_fd **to_ofd,
|
||||
struct osmo_sockaddr *to_addr);
|
||||
|
||||
|
|
|
@ -1222,6 +1222,7 @@ static int from_ggsns_read_cb(struct osmo_fd *from_ggsns_ofd, unsigned int what)
|
|||
struct osmo_sockaddr to_addr;
|
||||
struct osmo_fd *to_ofd;
|
||||
size_t len;
|
||||
uint8_t *reply_buf;
|
||||
|
||||
len = gtphub_read(from_ggsns_ofd, &from_addr, buf, sizeof(buf));
|
||||
if (len < 1)
|
||||
|
@ -1229,11 +1230,11 @@ static int from_ggsns_read_cb(struct osmo_fd *from_ggsns_ofd, unsigned int what)
|
|||
|
||||
len = gtphub_from_ggsns_handle_buf(hub, plane_idx, &from_addr, buf, len,
|
||||
gtphub_now(),
|
||||
&to_ofd, &to_addr);
|
||||
&reply_buf, &to_ofd, &to_addr);
|
||||
if (len < 1)
|
||||
return 0;
|
||||
|
||||
return gtphub_write(to_ofd, &to_addr, buf, len);
|
||||
return gtphub_write(to_ofd, &to_addr, reply_buf, len);
|
||||
}
|
||||
|
||||
static int gtphub_unmap(struct gtphub *hub,
|
||||
|
@ -1311,10 +1312,33 @@ static int gsn_addr_to_sockaddr(struct gsn_addr *src,
|
|||
return osmo_sockaddr_init_udp(dst, gsn_addr_to_str(src), port);
|
||||
}
|
||||
|
||||
static int gtphub_handle_echo(const struct gtp_packet_desc *p)
|
||||
/* If p is an Echo request, replace p's data with the matching response and
|
||||
* return 1. If p is no Echo request, return 0, or -1 if an invalid packet is
|
||||
* detected. */
|
||||
static int gtphub_handle_echo(struct gtphub *hub, struct gtp_packet_desc *p, uint8_t **reply_buf)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
if (p->type != GTP_ECHO_REQ)
|
||||
return 0;
|
||||
|
||||
static uint8_t echo_response_data[14] = {
|
||||
0x32, /* flags */
|
||||
GTP_ECHO_RSP,
|
||||
0x00, 14 - 8, /* Length in network byte order */
|
||||
0x00, 0x00, 0x00, 0x00, /* Zero TEI */
|
||||
0, 0, /* Seq, to be replaced */
|
||||
0, 0, /* no extensions */
|
||||
0x0e, /* Recovery IE */
|
||||
0 /* Recovery counter, to be replaced */
|
||||
};
|
||||
uint16_t *seq = (uint16_t*)&echo_response_data[8];
|
||||
uint8_t *recovery = &echo_response_data[13];
|
||||
|
||||
*seq = hton16(p->seq);
|
||||
*recovery = hub->restart_counter;
|
||||
|
||||
*reply_buf = echo_response_data;
|
||||
|
||||
return sizeof(echo_response_data);
|
||||
}
|
||||
|
||||
/* Parse buffer as GTP packet, replace elements in-place and return the ofd and
|
||||
|
@ -1328,29 +1352,30 @@ int gtphub_from_ggsns_handle_buf(struct gtphub *hub,
|
|||
uint8_t *buf,
|
||||
size_t received,
|
||||
time_t now,
|
||||
uint8_t **reply_buf,
|
||||
struct osmo_fd **to_ofd,
|
||||
struct osmo_sockaddr *to_addr)
|
||||
{
|
||||
LOG("<- rx from GGSN %s\n", osmo_sockaddr_to_str(from_addr));
|
||||
|
||||
*to_ofd = &hub->to_sgsns[plane_idx].ofd;
|
||||
|
||||
static struct gtp_packet_desc p;
|
||||
gtp_decode(buf, received, plane_idx, &p);
|
||||
|
||||
if (p.rc <= 0)
|
||||
return -1;
|
||||
|
||||
int rc;
|
||||
rc = gtphub_handle_echo(&p);
|
||||
if (rc == 1) {
|
||||
/* It was en echo. Nothing left to do. */
|
||||
/* (*to_ofd already set above.) */
|
||||
int reply_len;
|
||||
reply_len = gtphub_handle_echo(hub, &p, reply_buf);
|
||||
if (reply_len > 0) {
|
||||
/* It was an echo. Nothing left to do. */
|
||||
osmo_sockaddr_copy(to_addr, from_addr);
|
||||
return 0;
|
||||
*to_ofd = &hub->to_ggsns[plane_idx].ofd;
|
||||
return reply_len;
|
||||
}
|
||||
if (rc < 0)
|
||||
return -1; /* Invalid packet. */
|
||||
if (reply_len < 0)
|
||||
return -1;
|
||||
|
||||
*to_ofd = &hub->to_sgsns[plane_idx].ofd;
|
||||
|
||||
/* If a GGSN proxy is configured, check that it's indeed that proxy
|
||||
* talking to us. A proxy is a forced 1:1 connection, e.g. to another
|
||||
|
@ -1418,6 +1443,8 @@ int gtphub_from_ggsns_handle_buf(struct gtphub *hub,
|
|||
gtphub_map_seq(&p, ggsn, sgsn, now);
|
||||
|
||||
osmo_sockaddr_copy(to_addr, &sgsn->sa);
|
||||
|
||||
*reply_buf = (uint8_t*)p.data;
|
||||
return received;
|
||||
}
|
||||
|
||||
|
@ -1437,6 +1464,7 @@ static int from_sgsns_read_cb(struct osmo_fd *from_sgsns_ofd, unsigned int what)
|
|||
struct osmo_sockaddr to_addr;
|
||||
struct osmo_fd *to_ofd;
|
||||
size_t len;
|
||||
uint8_t *reply_buf;
|
||||
|
||||
len = gtphub_read(from_sgsns_ofd, &from_addr, buf, sizeof(buf));
|
||||
if (len < 1)
|
||||
|
@ -1444,11 +1472,11 @@ static int from_sgsns_read_cb(struct osmo_fd *from_sgsns_ofd, unsigned int what)
|
|||
|
||||
len = gtphub_from_sgsns_handle_buf(hub, plane_idx, &from_addr, buf, len,
|
||||
gtphub_now(),
|
||||
&to_ofd, &to_addr);
|
||||
&reply_buf, &to_ofd, &to_addr);
|
||||
if (len < 1)
|
||||
return 0;
|
||||
|
||||
return gtphub_write(to_ofd, &to_addr, buf, len);
|
||||
return gtphub_write(to_ofd, &to_addr, reply_buf, len);
|
||||
}
|
||||
|
||||
/* Analogous to gtphub_from_ggsns_handle_buf(), see the comment there. */
|
||||
|
@ -1458,29 +1486,30 @@ int gtphub_from_sgsns_handle_buf(struct gtphub *hub,
|
|||
uint8_t *buf,
|
||||
size_t received,
|
||||
time_t now,
|
||||
uint8_t **reply_buf,
|
||||
struct osmo_fd **to_ofd,
|
||||
struct osmo_sockaddr *to_addr)
|
||||
{
|
||||
LOG("-> rx from SGSN %s\n", osmo_sockaddr_to_str(from_addr));
|
||||
|
||||
*to_ofd = &hub->to_ggsns[plane_idx].ofd;
|
||||
|
||||
static struct gtp_packet_desc p;
|
||||
gtp_decode(buf, received, plane_idx, &p);
|
||||
|
||||
if (p.rc <= 0)
|
||||
return -1;
|
||||
|
||||
int rc;
|
||||
rc = gtphub_handle_echo(&p);
|
||||
if (rc == 1) {
|
||||
/* It was en echo. Nothing left to do. */
|
||||
/* (*to_ofd already set above.) */
|
||||
int reply_len;
|
||||
reply_len = gtphub_handle_echo(hub, &p, reply_buf);
|
||||
if (reply_len > 0) {
|
||||
/* It was an echo. Nothing left to do. */
|
||||
osmo_sockaddr_copy(to_addr, from_addr);
|
||||
return 0;
|
||||
*to_ofd = &hub->to_ggsns[plane_idx].ofd;
|
||||
return reply_len;
|
||||
}
|
||||
if (rc < 0)
|
||||
return -1; /* Invalid packet. */
|
||||
if (reply_len < 0)
|
||||
return -1;
|
||||
|
||||
*to_ofd = &hub->to_ggsns[plane_idx].ofd;
|
||||
|
||||
/* If an SGSN proxy is configured, check that it's indeed that proxy
|
||||
* talking to us. A proxy is a forced 1:1 connection, e.g. to another
|
||||
|
@ -1583,6 +1612,7 @@ int gtphub_from_sgsns_handle_buf(struct gtphub *hub,
|
|||
|
||||
osmo_sockaddr_copy(to_addr, &ggsn->sa);
|
||||
|
||||
*reply_buf = (uint8_t*)p.data;
|
||||
return received;
|
||||
}
|
||||
|
||||
|
@ -1764,6 +1794,8 @@ int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg)
|
|||
gtphub_init(hub);
|
||||
gtphub_ares_init(hub);
|
||||
|
||||
/* TODO set hub->restart_counter from external file. */
|
||||
|
||||
int plane_idx;
|
||||
for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) {
|
||||
rc = gtphub_bind_start(&hub->to_ggsns[plane_idx],
|
||||
|
|
|
@ -399,6 +399,7 @@ int __wrap_gtphub_ares_init(struct gtphub *hub)
|
|||
|
||||
#define buf_len 1024
|
||||
static uint8_t buf[buf_len];
|
||||
static uint8_t *reply_buf;
|
||||
|
||||
static unsigned int msg(const char *hex)
|
||||
{
|
||||
|
@ -410,16 +411,16 @@ static unsigned int msg(const char *hex)
|
|||
/* Compare static buf to given string constant. The amount of bytes is obtained
|
||||
* from parsing the GTP header in buf. hex must match an osmo_hexdump() of the
|
||||
* desired message. Return 1 if size and content match. */
|
||||
#define msg_is(MSG) _msg_is(MSG, __FILE__, __LINE__)
|
||||
static int _msg_is(const char *hex, const char *file, int line)
|
||||
#define reply_is(MSG) _reply_is(MSG, __FILE__, __LINE__)
|
||||
static int _reply_is(const char *hex, const char *file, int line)
|
||||
{
|
||||
struct gtp1_header_long *h = (void*)buf;
|
||||
struct gtp1_header_long *h = (void*)reply_buf;
|
||||
int len = ntoh16(h->length) + 8;
|
||||
const char *dump = osmo_hexdump_nospc(buf, len);
|
||||
const char *dump = osmo_hexdump_nospc(reply_buf, len);
|
||||
int cmp = strcmp(dump, hex);
|
||||
|
||||
if (cmp != 0) {
|
||||
printf("\n%s:%d: msg_is(): MISMATCH\n"
|
||||
printf("\n%s:%d: reply_is(): MISMATCH\n"
|
||||
" expecting:\n'%s'\n"
|
||||
" got:\n'%s'\n\n",
|
||||
file,
|
||||
|
@ -466,87 +467,82 @@ static void test_echo(void)
|
|||
time_t now = 123;
|
||||
|
||||
gtphub_init(hub);
|
||||
|
||||
/* TODO This test should test for gtphub echoing back to each side.
|
||||
* Echos must not be routed through. */
|
||||
hub->restart_counter = 0x23;
|
||||
|
||||
const char *gtp_ping_from_sgsn =
|
||||
"32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr. */
|
||||
"01" /* type 01: Echo request */
|
||||
"0004" /* length of 4 after header TEI */
|
||||
"00000000" /* header TEI == 0 in Echo */
|
||||
"abcd" /* some 16 octet sequence nr */
|
||||
"abcd" /* some 2 octet sequence nr */
|
||||
"0000" /* N-PDU 0, no extension header (why is this here?) */
|
||||
;
|
||||
|
||||
/* Same with mapped sequence number */
|
||||
const char *gtp_ping_to_ggsn =
|
||||
"32" "01" "0004" "00000000"
|
||||
"6d31" /* mapped seq */
|
||||
"00" "00";
|
||||
|
||||
const char *gtp_pong_from_ggsn =
|
||||
const char *gtp_pong_to_sgsn =
|
||||
"32"
|
||||
"02" /* type 02: Echo response */
|
||||
"0006" /* len */
|
||||
"00000000" /* tei */
|
||||
"6d31" /* mapped seq */
|
||||
"0000" /* ext */
|
||||
"0e01" /* 0e: Recovery, val == 1 */
|
||||
"0006" /* length of 6 after header TEI */
|
||||
"00000000" /* header TEI == 0 in Echo */
|
||||
"abcd" /* same sequence nr */
|
||||
"0000"
|
||||
"0e23" /* Recovery with restart counter */
|
||||
;
|
||||
/* Same with unmapped sequence number */
|
||||
const char *gtp_pong_to_sgsn =
|
||||
"32" "02" "0006" "00000000"
|
||||
"abcd" /* unmapped seq */
|
||||
"00" "00" "0e01";
|
||||
|
||||
/* Set the GGSN address that gtphub is forced to resolve to. */
|
||||
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);
|
||||
OSMO_ASSERT(osmo_sockaddr_init_udp(&orig_sgsn_addr,
|
||||
"192.168.42.23", 423) == 0);
|
||||
struct osmo_fd *ggsn_ofd = NULL;
|
||||
struct osmo_sockaddr ggsn_addr;
|
||||
struct osmo_sockaddr to_addr;
|
||||
int send;
|
||||
send = gtphub_from_sgsns_handle_buf(hub, GTPH_PLANE_CTRL, &orig_sgsn_addr,
|
||||
buf, msg(gtp_ping_from_sgsn), now,
|
||||
&ggsn_ofd, &ggsn_addr);
|
||||
&reply_buf, &ggsn_ofd, &to_addr);
|
||||
OSMO_ASSERT(send > 0);
|
||||
OSMO_ASSERT(ggsn_addr.l);
|
||||
OSMO_ASSERT(same_addr(&ggsn_addr, &resolved_ggsn_sa));
|
||||
OSMO_ASSERT(msg_is(gtp_ping_to_ggsn));
|
||||
OSMO_ASSERT(to_addr.l);
|
||||
OSMO_ASSERT(same_addr(&to_addr, &orig_sgsn_addr));
|
||||
OSMO_ASSERT(reply_is(gtp_pong_to_sgsn));
|
||||
|
||||
struct osmo_fd *sgsn_ofd;
|
||||
struct osmo_sockaddr sgsn_addr;
|
||||
send = gtphub_from_ggsns_handle_buf(hub, GTPH_PLANE_CTRL, &ggsn_addr,
|
||||
buf, msg(gtp_pong_from_ggsn), now,
|
||||
&sgsn_ofd, &sgsn_addr);
|
||||
struct gtphub_peer_port *sgsn_port =
|
||||
gtphub_port_find_sa(&hub->to_sgsns[GTPH_PLANE_CTRL],
|
||||
&orig_sgsn_addr);
|
||||
/* We don't record Echo peers. */
|
||||
OSMO_ASSERT(!sgsn_port);
|
||||
|
||||
const char *gtp_ping_from_ggsn =
|
||||
"32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr. */
|
||||
"01" /* type 01: Echo request */
|
||||
"0004" /* length of 4 after header TEI */
|
||||
"00000000" /* header TEI == 0 in Echo */
|
||||
"cdef" /* some 2 octet sequence nr */
|
||||
"0000" /* N-PDU 0, no extension header (why is this here?) */
|
||||
;
|
||||
|
||||
const char *gtp_pong_to_ggsn =
|
||||
"32"
|
||||
"02" /* type 02: Echo response */
|
||||
"0006" /* length of 6 after header TEI */
|
||||
"00000000" /* header TEI == 0 in Echo */
|
||||
"cdef" /* same sequence nr */
|
||||
"0000"
|
||||
"0e23" /* Recovery with restart counter */
|
||||
;
|
||||
|
||||
struct osmo_sockaddr orig_ggsn_addr;
|
||||
OSMO_ASSERT(osmo_sockaddr_init_udp(&orig_ggsn_addr,
|
||||
"192.168.24.32", 321) == 0);
|
||||
struct osmo_fd *sgsn_ofd = NULL;
|
||||
send = gtphub_from_ggsns_handle_buf(hub, GTPH_PLANE_CTRL, &orig_ggsn_addr,
|
||||
buf, msg(gtp_ping_from_ggsn), now,
|
||||
&reply_buf, &sgsn_ofd, &to_addr);
|
||||
OSMO_ASSERT(send > 0);
|
||||
OSMO_ASSERT(same_addr(&sgsn_addr, &orig_sgsn_addr));
|
||||
OSMO_ASSERT(msg_is(gtp_pong_to_sgsn));
|
||||
OSMO_ASSERT(same_addr(&to_addr, &orig_ggsn_addr));
|
||||
OSMO_ASSERT(reply_is(gtp_pong_to_ggsn));
|
||||
|
||||
struct gtphub_peer_port *ggsn_port =
|
||||
gtphub_port_find_sa(&hub->to_ggsns[GTPH_PLANE_CTRL],
|
||||
&resolved_ggsn_sa);
|
||||
OSMO_ASSERT(ggsn_port);
|
||||
struct gtphub_peer *ggsn = ggsn_port->peer_addr->peer;
|
||||
/* now == 123; now + 30 == 153. */
|
||||
OSMO_ASSERT(nr_map_is(&ggsn->seq_map, "(43981->27953@153), "));
|
||||
|
||||
OSMO_ASSERT(nr_map_is(&hub->tei_map[GTPH_PLANE_CTRL], ""));
|
||||
OSMO_ASSERT(nr_map_is(&hub->tei_map[GTPH_PLANE_USER], ""));
|
||||
&orig_sgsn_addr);
|
||||
/* We don't record Echo peers. */
|
||||
OSMO_ASSERT(!ggsn_port);
|
||||
|
||||
gtphub_gc(hub, now + EXPIRE_ALL);
|
||||
}
|
||||
|
@ -707,20 +703,20 @@ static void test_create_pdp_ctx(void)
|
|||
int send;
|
||||
send = gtphub_from_sgsns_handle_buf(hub, GTPH_PLANE_CTRL, &orig_sgsn_addr,
|
||||
buf, msg(gtp_req_from_sgsn), now,
|
||||
&ggsn_ofd, &ggsn_addr);
|
||||
&reply_buf, &ggsn_ofd, &ggsn_addr);
|
||||
OSMO_ASSERT(send > 0);
|
||||
OSMO_ASSERT(same_addr(&ggsn_addr, &resolved_ggsn_sa));
|
||||
OSMO_ASSERT(msg_is(gtp_req_to_ggsn));
|
||||
OSMO_ASSERT(reply_is(gtp_req_to_ggsn));
|
||||
OSMO_ASSERT(was_resolved_for("240010123456789", "internet"));
|
||||
|
||||
struct osmo_fd *sgsn_ofd;
|
||||
struct osmo_sockaddr sgsn_addr;
|
||||
send = gtphub_from_ggsns_handle_buf(hub, GTPH_PLANE_CTRL, &ggsn_addr,
|
||||
buf, msg(gtp_resp_from_ggsn), now,
|
||||
&sgsn_ofd, &sgsn_addr);
|
||||
&reply_buf, &sgsn_ofd, &sgsn_addr);
|
||||
OSMO_ASSERT(send > 0);
|
||||
OSMO_ASSERT(same_addr(&sgsn_addr, &orig_sgsn_addr));
|
||||
OSMO_ASSERT(msg_is(gtp_resp_to_sgsn));
|
||||
OSMO_ASSERT(reply_is(gtp_resp_to_sgsn));
|
||||
|
||||
struct gtphub_peer_port *ggsn_port =
|
||||
gtphub_port_find_sa(&hub->to_ggsns[GTPH_PLANE_CTRL],
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue