pespin has submitted this change. (
https://gerrit.osmocom.org/c/osmo-uecups/+/40763?usp=email )
Change subject: Introduce GTPv1U QFI support
......................................................................
Introduce GTPv1U QFI support
* Allow user configuring over the json interface the Tx of PDU Session
Container with UL/DL direction and a given QFI per flow.
* Support decoding incoming GTPv1U packets containing extended headers.
* Update ttcn3/UECUPTS_Types.ttcn accordingly to be able to use the new
features.
With this patch it is now possible to use osmo-uecups against a 5GC.
Related: SYS#7073
Change-Id: I6262c3dfbf774b361aadf0aa53ce09b5fdc38da4
---
M daemon/cups_client.c
M daemon/gtp.h
M daemon/gtp_endpoint.c
M daemon/gtp_tunnel.c
M daemon/internal.h
M daemon/tun_device.c
M ttcn3/UECUPS_Types.ttcn
7 files changed, 339 insertions(+), 76 deletions(-)
Approvals:
Jenkins Builder: Verified
laforge: Looks good to me, approved
diff --git a/daemon/cups_client.c b/daemon/cups_client.c
index c9d8652..b72ebd7 100644
--- a/daemon/cups_client.c
+++ b/daemon/cups_client.c
@@ -15,6 +15,7 @@
#include <osmocom/core/exec.h>
#include "internal.h"
+#include "gtp.h"
#include <netinet/sctp.h>
@@ -202,6 +203,58 @@
return 0;
}
+static int parse_ext_hdr_pdu_session_container(struct gtp1u_exthdr_pdu_sess_container
*out, json_t *jpdu_sess_cont)
+{
+ json_t *jpdu_type, *jqfi;
+ const char *str_pdu_type;
+
+ if (!json_is_object(jpdu_sess_cont))
+ return -EINVAL;
+
+ memset(out, 0, sizeof(*out));
+
+ out->enabled = true;
+
+ jpdu_type = json_object_get(jpdu_sess_cont, "pdu_type");
+ if (!json_is_string(jpdu_type))
+ return -EINVAL;
+ str_pdu_type = json_string_value(jpdu_type);
+ if (!strcmp(str_pdu_type, "ul_pdu_sess_info"))
+ out->pdu_type = GTP1_EXTHDR_PDU_TYPE_UL_PDU_SESSION_INFORMATION;
+ else if (!strcmp(str_pdu_type, "dl_pdu_sess_info"))
+ out->pdu_type = GTP1_EXTHDR_PDU_TYPE_DL_PDU_SESSION_INFORMATION;
+ else
+ return -EINVAL;
+
+ jqfi = json_object_get(jpdu_sess_cont, "qfi");
+ if (!json_is_integer(jqfi))
+ return -EINVAL;
+ out->qos_flow_identifier = json_number_value(jqfi);
+
+ return 0;
+}
+static int parse_ext_hdr(struct gtp1u_exthdrs *out, json_t *jexthdr)
+{
+ json_t *jseq_num, *jn_pdu_num, *jpdu_sess_cont;
+ int rc = 0;
+
+ if (!json_is_object(jexthdr))
+ return -EINVAL;
+
+ jseq_num = json_object_get(jexthdr, "sequence_number");
+ if (jseq_num)
+ out->seq_num_enabled = true;
+
+ jn_pdu_num = json_object_get(jexthdr, "n_pdu_number");
+ if (jn_pdu_num)
+ out->n_pdu_num_enabled = true;
+
+ jpdu_sess_cont = json_object_get(jexthdr, "pdu_session_container");
+ if (jpdu_sess_cont)
+ rc = parse_ext_hdr_pdu_session_container(&out->pdu_sess_container,
jpdu_sess_cont);
+
+ return rc;
+}
static int parse_create_tun(struct gtp_tunnel_params *out, json_t *ctun)
{
@@ -209,6 +262,7 @@
json_t *jrx_teid, *jtx_teid;
json_t *jtun_dev_name, *jtun_netns_name;
json_t *juser_addr, *juser_addr_type;
+ json_t *jgtp_ext_hdr;
int rc;
/*
'{"create_tun":{"tx_teid":1234,"rx_teid":5678,"user_addr_type":"IPV4","user_addr":"21222324","local_gtp_ep":{"addr_type":"IPV4","ip":"31323334","Port":2152},"remote_gtp_ep":{"addr_type":"IPV4","ip":"41424344","Port":2152},"tun_dev_name":"tun23","tun_netns_name":"foo"}}'
*/
@@ -257,6 +311,13 @@
out->tun_netns_name = talloc_strdup(out, json_string_value(jtun_netns_name));
}
+ jgtp_ext_hdr = json_object_get(ctun, "gtp_ext_hdr");
+ if (jgtp_ext_hdr) {
+ rc = parse_ext_hdr(&out->exthdr, jgtp_ext_hdr);
+ if (rc < 0)
+ return rc;
+ }
+
return 0;
}
diff --git a/daemon/gtp.h b/daemon/gtp.h
index f2acd36..2947d25 100644
--- a/daemon/gtp.h
+++ b/daemon/gtp.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#pragma once
#include <stdint.h>
+#include <osmocom/core/endian.h>
/* General GTP protocol related definitions. */
@@ -31,3 +32,60 @@
#define GTP1_F_SEQ 0x02
#define GTP1_F_EXTHDR 0x04
#define GTP1_F_MASK 0x07
+
+
+/*
+ * 5GC GTP Header (16byte)
+ * o Flags(1byte) : 0x34
+ * o Message Type(1byte) : T-PDU (0xff)
+ * o Length(2byte) : 36
+ * o TEID(4byte) : 0x00000001
+ * o Sequence Number(2byte) : 0x0000
+ * o N PDU Number(1byte) : 0x00
+ * o Next extension header type(4byte): PDU Session container(1byte) : (0x85)
+ * o Extension header(4byte)
+ * - Extension HEader Length(1byte) : 1
+ * - PDU Session Container(2byte)
+ * ; PDU Type : UL PDU SESSION INFORMATION (1)
+ * ; QoS Flow Identifier (QFI) : 1
+ * - Next extension header type : No more extension headers (0x00)
+ */
+
+#define GTP1_EXTHDR_UDP_PORT 0x40
+#define GTP1_EXTHDR_PDU_SESSION_CONTAINER 0x85
+#define GTP1_EXTHDR_PDCP_NUMBER 0xc0
+#define GTP1_EXTHDR_NO_MORE_EXTENSION_HEADERS 0x0
+
+#define GTP1_EXTHDR_PDU_TYPE_DL_PDU_SESSION_INFORMATION 0
+#define GTP1_EXTHDR_PDU_TYPE_UL_PDU_SESSION_INFORMATION 1
+
+struct gtp1_exthdr {
+ uint16_t sequence_number;
+ uint8_t n_pdu_number;
+ struct {
+#if OSMO_IS_LITTLE_ENDIAN
+ uint8_t type;
+ uint8_t len;
+ union {
+ struct { /* TODO: make sure order of fields is correct or swapped */
+ uint8_t spare1:4,
+ pdu_type:4;
+ uint8_t qos_flow_identifier:6,
+ reflective_qos_indicator:1,
+ paging_policy_presence:1;
+#elif OSMO_IS_BIG_ENDIAN
+/* auto-generated from the little endian part above
(libosmocore/contrib/struct_endianness.py) */
+ uint8_t type;
+ uint8_t len;
+ union {
+ struct {
+ uint8_t spare1:4,
+ pdu_type:4;
+ uint8_t paging_policy_presence:1, reflective_qos_indicator:1, qos_flow_identifier:6;
+#endif
+ };
+ uint16_t udp_port;
+ uint16_t pdcp_number;
+ };
+ } __attribute__ ((packed)) array[8];
+} __attribute__ ((packed));
diff --git a/daemon/gtp_endpoint.c b/daemon/gtp_endpoint.c
index 4221e14..bb417da 100644
--- a/daemon/gtp_endpoint.c
+++ b/daemon/gtp_endpoint.c
@@ -27,19 +27,98 @@
* GTP Endpoint (UDP socket)
***********************************************************************/
+static void handle_gtp1u(struct gtp_endpoint *ep, const uint8_t *buffer, unsigned int
nread)
+{
+ struct gtp_daemon *d = ep->d;
+ struct gtp_tunnel *t;
+ const struct gtp1_header *gtph;
+ const uint8_t *payload;
+ int rc, outfd;
+ uint32_t teid;
+ uint16_t gtp_len;
+
+ if (nread < sizeof(*gtph)) {
+ LOGEP(ep, LOGL_NOTICE, "Short read: %u < %lu\n", nread, sizeof(*gtph));
+ return;
+ }
+ gtph = (struct gtp1_header *)buffer;
+
+ /* check GTP header contents */
+ if ((gtph->flags & 0xf0) != 0x30) {
+ LOGEP(ep, LOGL_NOTICE, "Unexpected GTP Flags: 0x%02x\n", gtph->flags);
+ return;
+ }
+ if (gtph->type != GTP_TPDU) {
+ LOGEP(ep, LOGL_NOTICE, "Unexpected GTP Message Type: 0x%02x\n",
gtph->type);
+ return;
+ }
+
+ gtp_len = ntohs(gtph->length);
+ if (sizeof(*gtph)+gtp_len > nread) {
+ LOGEP(ep, LOGL_NOTICE, "Short GTP Message: %lu < len=%u\n",
+ sizeof(*gtph)+gtp_len, nread);
+ return;
+ }
+ teid = ntohl(gtph->tid);
+
+ payload = buffer + sizeof(*gtph);
+ if (gtph->flags & GTP1_F_MASK) {
+ const struct gtp1_exthdr *exthdr = (const struct gtp1_exthdr *)payload;
+ if (gtp_len < 4) {
+ LOGEP(ep, LOGL_NOTICE, "Short GTP Message according to flags 0x%02x: %lu <
len=%u\n",
+ gtph->flags, sizeof(*gtph) + gtp_len, nread);
+ return;
+ }
+ gtp_len -= 4;
+ payload += 4;
+ const uint8_t *it = &exthdr->array[0].type;
+ while (*it != 0) {
+ unsigned int ext_len;
+ if (gtp_len < 1) {
+ LOGEP(ep, LOGL_NOTICE, "Short GTP Message according to flags 0x%02x: %lu <
len=%u\n",
+ gtph->flags, sizeof(*gtph) + gtp_len, nread);
+ return;
+ }
+ ext_len = 1 + 1 + it[1] + 1;
+ if (gtp_len < ext_len) {
+ LOGEP(ep, LOGL_NOTICE, "Short GTP Message according to flags 0x%02x: %lu <
len=%u\n",
+ gtph->flags, sizeof(*gtph) + gtp_len, nread);
+ return;
+ }
+ gtp_len -= ext_len;
+ payload += ext_len;
+ it = payload - 1;
+ }
+ }
+
+ /* 2) look-up tunnel based on TEID */
+ pthread_rwlock_rdlock(&d->rwlock);
+ t = _gtp_tunnel_find_r(d, teid, ep);
+ if (!t) {
+ pthread_rwlock_unlock(&d->rwlock);
+ LOGEP(ep, LOGL_NOTICE, "Unable to find tunnel for TEID=0x%08x\n", teid);
+ return;
+ }
+ outfd = t->tun_dev->fd;
+ pthread_rwlock_unlock(&d->rwlock);
+
+ /* 3) write to TUN device */
+ rc = write(outfd, payload, gtp_len);
+ if (rc < gtp_len) {
+ LOGEP(ep, LOGL_FATAL, "Error writing to tun device %s\n", strerror(errno));
+ exit(1);
+ }
+}
+
/* one thread for reading from each GTP/UDP socket (GTP decapsulation -> tun) */
static void *gtp_endpoint_thread(void *arg)
{
struct gtp_endpoint *ep = (struct gtp_endpoint *)arg;
- struct gtp_daemon *d = ep->d;
- uint8_t buffer[MAX_UDP_PACKET+sizeof(struct gtp1_header)];
+ uint8_t buffer[sizeof(struct gtp1_header) + sizeof(struct gtp1_exthdr) +
MAX_UDP_PACKET];
while (1) {
- struct gtp_tunnel *t;
- const struct gtp1_header *gtph;
- int rc, nread, outfd;
- uint32_t teid;
+ int rc;
/* 1) read GTP packet from UDP socket */
rc = recvfrom(ep->fd, buffer, sizeof(buffer), 0, (struct sockaddr *)NULL, 0);
@@ -47,46 +126,7 @@
LOGEP(ep, LOGL_FATAL, "Error reading from UDP socket: %s\n",
strerror(errno));
exit(1);
}
- nread = rc;
- if (nread < sizeof(*gtph)) {
- LOGEP(ep, LOGL_NOTICE, "Short read: %d < %lu\n", nread, sizeof(*gtph));
- continue;
- }
- gtph = (struct gtp1_header *)buffer;
-
- /* check GTP heaader contents */
- if (gtph->flags != 0x30) {
- LOGEP(ep, LOGL_NOTICE, "Unexpected GTP Flags: 0x%02x\n", gtph->flags);
- continue;
- }
- if (gtph->type != GTP_TPDU) {
- LOGEP(ep, LOGL_NOTICE, "Unexpected GTP Message Type: 0x%02x\n",
gtph->type);
- continue;
- }
- if (sizeof(*gtph)+ntohs(gtph->length) > nread) {
- LOGEP(ep, LOGL_NOTICE, "Shotr GTP Message: %lu < len=%d\n",
- sizeof(*gtph)+ntohs(gtph->length), nread);
- continue;
- }
- teid = ntohl(gtph->tid);
-
- /* 2) look-up tunnel based on TEID */
- pthread_rwlock_rdlock(&d->rwlock);
- t = _gtp_tunnel_find_r(d, teid, ep);
- if (!t) {
- pthread_rwlock_unlock(&d->rwlock);
- LOGEP(ep, LOGL_NOTICE, "Unable to find tunnel for TEID=0x%08x\n", teid);
- continue;
- }
- outfd = t->tun_dev->fd;
- pthread_rwlock_unlock(&d->rwlock);
-
- /* 3) write to TUN device */
- rc = write(outfd, buffer+sizeof(*gtph), ntohs(gtph->length));
- if (rc < nread-sizeof(struct gtp1_header)) {
- LOGEP(ep, LOGL_FATAL, "Error writing to tun device %s\n", strerror(errno));
- exit(1);
- }
+ handle_gtp1u(ep, buffer, rc);
}
}
diff --git a/daemon/gtp_tunnel.c b/daemon/gtp_tunnel.c
index 87d1e69..6c3e81c 100644
--- a/daemon/gtp_tunnel.c
+++ b/daemon/gtp_tunnel.c
@@ -56,6 +56,7 @@
t->rx_teid = cpars->rx_teid;
t->tx_teid = cpars->tx_teid;
+ memcpy(&t->exthdr, &cpars->exthdr, sizeof(t->exthdr));
memcpy(&t->user_addr, &cpars->user_addr, sizeof(t->user_addr));
memcpy(&t->remote_udp, &cpars->remote_udp, sizeof(t->remote_udp));
diff --git a/daemon/internal.h b/daemon/internal.h
index 25a8f91..19cf16a 100644
--- a/daemon/internal.h
+++ b/daemon/internal.h
@@ -181,6 +181,18 @@
* this is what happens when IP arrives on the tun device
*/
+struct gtp1u_exthdr_pdu_sess_container {
+ bool enabled;
+ uint8_t pdu_type; /* GTP1_EXTHDR_PDU_TYPE_* */
+ uint8_t qos_flow_identifier;
+};
+
+struct gtp1u_exthdrs {
+ bool seq_num_enabled;
+ bool n_pdu_num_enabled;
+ struct gtp1u_exthdr_pdu_sess_container pdu_sess_container;
+};
+
struct gtp_tunnel {
/* entry in global list / hash table */
struct llist_head list;
@@ -205,6 +217,9 @@
/* Remote UDP IP/Port*/
struct sockaddr_storage remote_udp;
+ /* GTP Extension Header */
+ struct gtp1u_exthdrs exthdr;
+
/* TODO: Filter */
};
@@ -219,6 +234,9 @@
uint32_t rx_teid;
uint32_t tx_teid;
+ /* GTPv1U Extension Headers: */
+ struct gtp1u_exthdrs exthdr;
+
/* end user address */
struct sockaddr_storage user_addr;
diff --git a/daemon/tun_device.c b/daemon/tun_device.c
index e9c0400..6a0d8b6 100644
--- a/daemon/tun_device.c
+++ b/daemon/tun_device.c
@@ -128,23 +128,81 @@
OSMO_ASSERT(rc == 0);
}
+/* Note: This function is called with d->rwlock locked, and it's responsible of
unlocking it before returning. */
+static int tx_gtp1u_pkt(struct gtp_tunnel *t, uint8_t *base_buffer, const uint8_t
*payload, unsigned int payload_len)
+{
+ struct gtp1_header *gtph;
+ unsigned int head_len = payload - base_buffer;
+ unsigned int hdr_len_needed;
+ unsigned int opt_hdr_len_needed = 0;
+ struct sockaddr_storage daddr;
+ int outfd = t->gtp_ep->fd;
+ int rc;
+ uint8_t flags;
+
+#define GTP1_F_NPDU 0x01
+#define GTP1_F_SEQ 0x02
+#define GTP1_F_EXTHDR 0x04
+#define GTP1_F_MASK 0x07
+
+ flags = 0x30; /* Version */
+
+ if (t->exthdr.seq_num_enabled)
+ flags |= GTP1_F_SEQ;
+
+ if (t->exthdr.n_pdu_num_enabled)
+ flags |= GTP1_F_NPDU;
+
+ if (t->exthdr.pdu_sess_container.enabled) {
+ flags |= GTP1_F_EXTHDR;
+ opt_hdr_len_needed += 4; /* Extra Header struct */
+ }
+
+ /* Make sure the Next Extension Header Type is counted: */
+ if (flags & GTP1_F_MASK)
+ opt_hdr_len_needed += 4;
+
+ hdr_len_needed = sizeof(struct gtp1_header) + opt_hdr_len_needed;
+ OSMO_ASSERT(hdr_len_needed < head_len);
+ gtph = (struct gtp1_header *)(payload - hdr_len_needed);
+ /* initialize the fixed part of the GTP header */
+ gtph->flags = flags;
+ gtph->type = GTP_TPDU;
+ gtph->length = htons(opt_hdr_len_needed + payload_len);
+ gtph->tid = htonl(t->tx_teid);
+
+ if (flags & GTP1_F_MASK) {
+ struct gtp1_exthdr *exthdr = (struct gtp1_exthdr *)(((uint8_t *)gtph) +
sizeof(*gtph));
+ exthdr->sequence_number = htons(0); /* TODO: increment sequence_number in
"t". */
+ exthdr->n_pdu_number = 0; /* TODO: increment n_pdu_number in "t". */
+ if (t->exthdr.pdu_sess_container.enabled) {
+ exthdr->array[0].type = GTP1_EXTHDR_PDU_SESSION_CONTAINER;
+ exthdr->array[0].len = 1;
+ exthdr->array[0].pdu_type = t->exthdr.pdu_sess_container.pdu_type;
+ exthdr->array[0].qos_flow_identifier =
t->exthdr.pdu_sess_container.qos_flow_identifier;
+ exthdr->array[1].type = 0; /* No extension headers */
+ } else {
+ exthdr->array[0].type = 0; /* No extension headers */
+ }
+ }
+
+ memcpy(&daddr, &t->remote_udp, sizeof(daddr));
+ pthread_rwlock_unlock(&t->d->rwlock);
+
+ /* 4) write to GTP/UDP socket */
+ rc = sendto(outfd, gtph, hdr_len_needed + payload_len, 0,
+ (struct sockaddr *)&daddr, sizeof(daddr));
+ return rc;
+}
+
/* one thread for reading from each TUN device (TUN -> GTP encapsulation) */
static void *tun_device_thread(void *arg)
{
struct tun_device *tun = (struct tun_device *)arg;
struct gtp_daemon *d = tun->d;
-
- uint8_t base_buffer[MAX_UDP_PACKET+sizeof(struct gtp1_header)];
- struct gtp1_header *gtph = (struct gtp1_header *)base_buffer;
- uint8_t *buffer = base_buffer + sizeof(struct gtp1_header);
-
- struct sockaddr_storage daddr;
+ uint8_t base_buffer[sizeof(struct gtp1_header) + sizeof(struct gtp1_exthdr) +
MAX_UDP_PACKET];
int old_cancelst_unused;
- /* initialize the fixed part of the GTP header */
- gtph->flags = 0x30;
- gtph->type = GTP_TPDU;
-
pthread_cleanup_push(tun_device_pthread_cleanup_routine, tun);
/* IMPORTANT!: All logging functions in this function block must be called with
* PTHREAD_CANCEL_DISABLE set, otherwise the thread could be cancelled while
@@ -154,7 +212,8 @@
while (1) {
struct gtp_tunnel *t;
struct pkt_info pinfo;
- int rc, nread, outfd;
+ int rc, nread;
+ uint8_t *buffer = base_buffer + sizeof(base_buffer) - MAX_UDP_PACKET;
/* 1) read from tun */
rc = read(tun->fd, buffer, MAX_UDP_PACKET);
@@ -164,7 +223,6 @@
exit(1);
}
nread = rc;
- gtph->length = htons(nread);
rc = parse_pkt(&pinfo, buffer, nread);
if (rc < 0) {
@@ -194,14 +252,7 @@
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancelst_unused);
continue;
}
- outfd = t->gtp_ep->fd;
- memcpy(&daddr, &t->remote_udp, sizeof(daddr));
- gtph->tid = htonl(t->tx_teid);
- pthread_rwlock_unlock(&d->rwlock);
-
- /* 4) write to GTP/UDP socket */
- rc = sendto(outfd, base_buffer, nread+sizeof(*gtph), 0,
- (struct sockaddr *)&daddr, sizeof(daddr));
+ rc = tx_gtp1u_pkt(t, base_buffer, buffer, nread);
if (rc < 0) {
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelst_unused);
LOGTUN(tun, LOGL_FATAL, "Error Writing to UDP socket: %s\n",
strerror(errno));
diff --git a/ttcn3/UECUPS_Types.ttcn b/ttcn3/UECUPS_Types.ttcn
index 2e6686b..29fa738 100644
--- a/ttcn3/UECUPS_Types.ttcn
+++ b/ttcn3/UECUPS_Types.ttcn
@@ -22,23 +22,37 @@
uint16_t Port
};
+const charstring UECUPS_GtpExtHdr_PduSessContainer_Type_ul_pdu_sess_info :=
"ul_pdu_sess_info";
+const charstring UECUPS_GtpExtHdr_PduSessContainer_Type_dl_pdu_sess_info :=
"dl_pdu_sess_info";
+type record UECUPS_GtpExtHdr_PduSessContainer {
+ charstring pdu_type, /* ("ul_pdu_sess_info"|"dl_pdu_sess_info") */
+ uint32_t qfi
+};
+
+type record UECUPS_GtpExtHdr {
+ boolean sequence_number optional,
+ boolean n_pdu_number optional,
+ UECUPS_GtpExtHdr_PduSessContainer pdu_session_container optional
+};
+
/* Create a new GTP-U tunnel in the user plane */
type record UECUPS_CreateTun {
/* TEID in transmit + receive direction */
- uint32_t tx_teid,
- uint32_t rx_teid,
+ uint32_t tx_teid,
+ uint32_t rx_teid,
/* user address (allocated inside the tunnel) */
- UECUPS_AddrType user_addr_type,
- OCT4_16n user_addr,
+ UECUPS_AddrType user_addr_type,
+ OCT4_16n user_addr,
/* GTP endpoint (UDP IP/Port tuples) */
- UECUPS_SockAddr local_gtp_ep,
- UECUPS_SockAddr remote_gtp_ep,
+ UECUPS_SockAddr local_gtp_ep,
+ UECUPS_SockAddr remote_gtp_ep,
/* TUN device */
- charstring tun_dev_name,
- charstring tun_netns_name optional
+ charstring tun_dev_name,
+ charstring tun_netns_name optional,
+ UECUPS_GtpExtHdr gtp_ext_hdr optional
};
type record UECUPS_CreateTunRes {
@@ -128,6 +142,24 @@
Port := Port
}
+template (value) UECUPS_GtpExtHdr_PduSessContainer
+ts_UECUPS_GtpExtHdr_PduSessContainer(template (value) charstring pdu_type,
+ template (value) uint32_t qfi)
+:= {
+ pdu_type := pdu_type,
+ qfi := qfi
+};
+
+template (value) UECUPS_GtpExtHdr
+ts_UECUPS_GtpExtHdr(template (omit) boolean sequence_number := omit,
+ template (omit) boolean n_pdu_number := omit,
+ template (omit) UECUPS_GtpExtHdr_PduSessContainer pdu_session_container := omit)
+:= {
+ sequence_number := sequence_number,
+ n_pdu_number := n_pdu_number,
+ pdu_session_container := pdu_session_container
+};
+
template (value) UECUPS_CreateTun
ts_UECUPS_CreateTun(template (value) uint32_t tx_teid,
template (value) uint32_t rx_teid,
@@ -136,7 +168,8 @@
template (value) UECUPS_SockAddr local_gtp_ep,
template (value) UECUPS_SockAddr remote_gtp_ep,
template (value) charstring tun_dev_name := "tun",
- template (omit) charstring tun_netns_name := omit)
+ template (omit) charstring tun_netns_name := omit,
+ template (omit) UECUPS_GtpExtHdr gtp_ext_hdr := omit)
:= {
tx_teid := tx_teid,
rx_teid := rx_teid,
@@ -145,7 +178,8 @@
local_gtp_ep := local_gtp_ep,
remote_gtp_ep := remote_gtp_ep,
tun_dev_name := tun_dev_name,
- tun_netns_name := tun_netns_name
+ tun_netns_name := tun_netns_name,
+ gtp_ext_hdr := gtp_ext_hdr
};
template (value) UECUPS_DestroyTun
--
To view, visit
https://gerrit.osmocom.org/c/osmo-uecups/+/40763?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-uecups
Gerrit-Branch: master
Gerrit-Change-Id: I6262c3dfbf774b361aadf0aa53ce09b5fdc38da4
Gerrit-Change-Number: 40763
Gerrit-PatchSet: 5
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>