This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.
Neels Hofmeyr nhofmeyr at sysmocom.deSponsored-by: On-Waves ehi --- openbsc/src/gprs/gtphub.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c index 419b21f..c6ce4f6 100644 --- a/openbsc/src/gprs/gtphub.c +++ b/openbsc/src/gprs/gtphub.c @@ -24,6 +24,8 @@ #include <inttypes.h> #include <netinet/in.h> +#include <gtp.h> + #include <openbsc/gtphub.h> #include <openbsc/debug.h> @@ -46,6 +48,116 @@ typedef int (*osmo_fd_cb_t)(struct osmo_fd *fd, unsigned int what); #define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next) #define llist_first(head, type, entry) llist_entry(__llist_first(head), type, entry) +/* TODO duplicated from openggsn/gtp/gtpie.h */ +#define ntoh16(x) ntohs(x) +#define ntoh32(x) ntohl(x) + +/* TODO move GTP header stuff to openggsn/gtp/ ? See gtp_decaps*() */ + +enum gtp_header_type { + GTPH_V0 = 0, + GTPH_V1 = 1, + + GTPH_TOOSHORT = -1, + GTPH_UNSUPPORTED_VERSION = -2, + GTPH_LOWER_VERSION = -3, // when gtp0 is received by gtp1 socket +}; + +int validate_gtp0_header(const uint8_t *data, int data_len) +{ + struct gtp0_header *pheader; + pheader = (struct gtp0_header *)(data); + + OSMO_ASSERT(data_len >= 1); + + int version = (*data) >> 5; + + /* Version should be gtp0 (or earlier) */ + /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */ + /* GTP 0 messages. If other version message is received we reply that we */ + /* only support version 0, implying that this is the only version */ + /* supported on this port */ + if (version != 0) { + LOGERR("Expecting GTP version 0, got: %d\n", version); + return GTPH_UNSUPPORTED_VERSION; + } + + /* Check length of gtp0 packet */ + if (data_len < GTP0_HEADER_SIZE) { + LOGERR("GTP0 packet too short: %d\n", data_len); + return GTPH_TOOSHORT; + } + + /* Check packet length field versus length of packet */ + if (data_len != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) { + LOGERR("GTP packet length field (%d + %d) does not match" + " actual length (%d)\n", + GTP0_HEADER_SIZE, (int)ntoh16(pheader->length), + data_len); + return GTPH_TOOSHORT; + } + + return GTPH_V0; +} + +int validate_gtp1_header(const uint8_t *data, int data_len) +{ + struct gtp1_header_short *pheader; + pheader = (struct gtp1_header_short *)data; + + OSMO_ASSERT(data_len >= 1); + + int version = (*data) >> 5; + + if (version != 1) { + LOGERR("Expecting GTP version 1, got: %d\n", version); + return (version < 1? GTPH_LOWER_VERSION : GTPH_UNSUPPORTED_VERSION); + } + + /* Check length of packet */ + if (data_len < GTP1_HEADER_SIZE_LONG) { + LOGERR("GTP packet too short: %d\n", data_len); + return GTPH_TOOSHORT; + } + + /* Check packet length field versus length of packet */ + if (data_len != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) { + LOGERR("GTP packet length field (%d + %d) does not match" + " actual length (%d)\n", + GTP1_HEADER_SIZE_SHORT, (int)ntoh16(pheader->length), + data_len); + return GTPH_TOOSHORT; + } + + return GTPH_V1; +} + +/* Examine whether given data of size data_len has a valid GTP header. + * Return the GTP version, or < 0 on error (see enum gtp_header_type). + */ +int validate_gtp_header(const uint8_t *data, int data_len) +{ + /* Need at least 1 byte in order to check version */ + if (data_len < (1)) { + LOGERR("Discarding packet - too small\n"); + return GTPH_TOOSHORT; + } + + int version = (*data) >> 5; + + switch (version) { + case 0: + return validate_gtp0_header(data, data_len); + case 1: + return validate_gtp1_header(data, data_len); + default: + break; + } + + LOGERR("Unsupported GTP version: %d\n", version); + return GTPH_UNSUPPORTED_VERSION; +} + /* general */ @@ -55,6 +167,8 @@ const char* const gtphub_port_idx_names[GTPH_PORT_N] = { }; +/* tei_map, tei_pool */ + void tei_pool_init(struct tei_pool *pool) { *pool = (struct tei_pool){}; @@ -215,6 +329,16 @@ static int gtp_relay(struct osmo_fd *from, /* insert magic here */ + int gtph = validate_gtp_header(buf, received); + + if (gtph >= 0) + LOG("Valid GTP header (v%d)\n", gtph); +#if 0 + else + // error has been logged + return 0; +#endif + errno = 0; ssize_t sent = sendto(to->fd, buf, received, 0, (struct sockaddr*)to_addr, to_addr_len); -- 2.1.4