mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Refactor gtpv1u_bearer_t and use internally
Reuse the gtpv1u_bearer_t for internal functions. Hopefully this will also simplify implementation of IPv6, as it encapsulates IP address handling within gtpv1u_bearer_t.
This commit is contained in:
@@ -96,13 +96,12 @@ typedef struct Gtpv1uExtHeader {
|
||||
#define GTP_END_MARKER (254)
|
||||
#define GTP_GPDU (255)
|
||||
|
||||
// GTP bearer context: for sending data
|
||||
typedef struct gtpv1u_bearer_s {
|
||||
/* TEID used in dl and ul */
|
||||
teid_t teid_incoming; ///< eNB TEID
|
||||
teid_t teid_outgoing; ///< Remote TEID
|
||||
in_addr_t outgoing_ip_addr;
|
||||
struct in6_addr outgoing_ip6_addr;
|
||||
tcp_udp_port_t outgoing_port;
|
||||
int sock_fd;
|
||||
struct sockaddr_storage ip;
|
||||
teid_t teid_incoming;
|
||||
teid_t teid_outgoing;
|
||||
uint16_t seqNum;
|
||||
uint8_t npduNum;
|
||||
int outgoing_qfi;
|
||||
@@ -217,22 +216,16 @@ instance_t legacyInstanceMapping = 0;
|
||||
}
|
||||
|
||||
#define HDR_MAX 256 // 256 is supposed to be larger than any gtp header
|
||||
static int gtpv1uCreateAndSendMsg(int h,
|
||||
uint32_t peerIp,
|
||||
uint16_t peerPort,
|
||||
static int gtpv1uCreateAndSendMsg(gtpv1u_bearer_t *bearer,
|
||||
int msgType,
|
||||
teid_t teid,
|
||||
uint8_t *Msg,
|
||||
int msgLen,
|
||||
bool seqNumFlag,
|
||||
bool npduNumFlag,
|
||||
int seqNum,
|
||||
int npduNum,
|
||||
int extHdrType,
|
||||
uint8_t *extensionHeader_buffer,
|
||||
uint8_t extensionHeader_length)
|
||||
{
|
||||
LOG_D(GTPU, "Peer IP:%u peer port:%u outgoing teid:%u \n", peerIp, peerPort, teid);
|
||||
|
||||
DevAssert(msgLen + HDR_MAX < 65536); // maximum size of UDP packet
|
||||
uint8_t buffer[msgLen + HDR_MAX];
|
||||
@@ -247,14 +240,14 @@ static int gtpv1uCreateAndSendMsg(int h,
|
||||
msgHdr->PT = 1;
|
||||
msgHdr->version = 1;
|
||||
msgHdr->msgType = msgType;
|
||||
msgHdr->teid = htonl(teid);
|
||||
msgHdr->teid = htonl(bearer->teid_outgoing);
|
||||
|
||||
curPtr += sizeof(Gtpv1uMsgHeaderT);
|
||||
|
||||
if (seqNumFlag || (extHdrType != NO_MORE_EXT_HDRS) || npduNumFlag) {
|
||||
*(uint16_t *)curPtr = seqNumFlag ? seqNum : 0x0000;
|
||||
*(uint16_t *)curPtr = seqNumFlag ? bearer->seqNum : 0x0000;
|
||||
curPtr += sizeof(uint16_t);
|
||||
*(uint8_t *)curPtr = npduNumFlag ? npduNum : 0x00;
|
||||
*(uint8_t *)curPtr = npduNumFlag ? bearer->npduNum : 0x00;
|
||||
curPtr++;
|
||||
*(uint8_t *)curPtr = extHdrType;
|
||||
curPtr++;
|
||||
@@ -283,20 +276,20 @@ static int gtpv1uCreateAndSendMsg(int h,
|
||||
|
||||
msgHdr->msgLength = htons(curPtr - (buffer + sizeof(Gtpv1uMsgHeaderT)));
|
||||
AssertFatal(curPtr - (buffer + msgLen) < HDR_MAX, "fixed max size of all headers too short");
|
||||
// Fix me: add IPv6 support, using flag ipVersion
|
||||
struct sockaddr_in to = {0};
|
||||
to.sin_family = AF_INET;
|
||||
to.sin_port = htons(peerPort);
|
||||
to.sin_addr.s_addr = peerIp;
|
||||
LOG_D(GTPU, "sending packet size: %ld to %s\n", curPtr - buffer, inet_ntoa(to.sin_addr));
|
||||
int ret;
|
||||
|
||||
if ((ret = sendto(h, (void *)buffer, curPtr - buffer, 0, (struct sockaddr *)&to, sizeof(to))) != curPtr - buffer) {
|
||||
// Fix me: add IPv6 support
|
||||
DevAssert(bearer->ip.ss_family == AF_INET);
|
||||
struct sockaddr_in *to = (struct sockaddr_in *)&bearer->ip;
|
||||
LOG_D(GTPU,
|
||||
"Peer IP:" IPV4_ADDR " port:%u outgoing teid:%x\n",
|
||||
IPV4_ADDR_FORMAT(to->sin_addr.s_addr),
|
||||
htons(to->sin_port),
|
||||
bearer->teid_outgoing);
|
||||
int ret = sendto(bearer->sock_fd, buffer, curPtr - buffer, 0, (struct sockaddr *)to, sizeof(*to));
|
||||
if (ret != curPtr - buffer) {
|
||||
LOG_E(GTPU,
|
||||
"[SD %d] Failed to send data to " IPV4_ADDR " on port %d, buffer size %lu, ret: %d, errno: %d\n",
|
||||
h,
|
||||
IPV4_ADDR_FORMAT(peerIp),
|
||||
peerPort,
|
||||
"[SD %d] Failed to send data buffer size %lu, ret: %d, errno: %d\n",
|
||||
bearer->sock_fd,
|
||||
curPtr - buffer,
|
||||
ret,
|
||||
errno);
|
||||
@@ -343,49 +336,33 @@ void gtpv1uSendDirect(instance_t instance,
|
||||
ptr2->second.npduNum++;
|
||||
|
||||
// copy to release the mutex
|
||||
gtpv1u_bearer_t tmp = ptr2->second;
|
||||
gtpv1u_bearer_t bearer = ptr2->second;
|
||||
pthread_mutex_unlock(&globGtp.gtp_lock);
|
||||
|
||||
if (tmp.outgoing_qfi != -1) {
|
||||
Gtpv1uExtHeaderT ext = {0};
|
||||
Gtpv1uExtHeaderT *opt_ext = NULL;
|
||||
Gtpv1uExtHeaderT ext = {0};
|
||||
if (bearer.outgoing_qfi != -1) {
|
||||
opt_ext = &ext;
|
||||
ext.ExtHeaderLen = 1; // in quad bytes EXT_HDR_LNTH_OCTET_UNITS
|
||||
ext.pdusession_cntr.spare = 0;
|
||||
ext.pdusession_cntr.PDU_type = UL_PDU_SESSION_INFORMATION;
|
||||
ext.pdusession_cntr.QFI = tmp.outgoing_qfi;
|
||||
ext.pdusession_cntr.QFI = bearer.outgoing_qfi;
|
||||
ext.pdusession_cntr.Reflective_QoS_activation = false;
|
||||
ext.pdusession_cntr.Paging_Policy_Indicator = false;
|
||||
ext.NextExtHeaderType = NO_MORE_EXT_HDRS;
|
||||
|
||||
gtpv1uCreateAndSendMsg(compatInst(instance),
|
||||
tmp.outgoing_ip_addr,
|
||||
tmp.outgoing_port,
|
||||
GTP_GPDU,
|
||||
tmp.teid_outgoing,
|
||||
buf,
|
||||
len,
|
||||
seqNumFlag,
|
||||
npduNumFlag,
|
||||
tmp.seqNum,
|
||||
tmp.npduNum,
|
||||
PDU_SESSION_CONTAINER,
|
||||
(uint8_t *)&ext,
|
||||
sizeof(ext));
|
||||
} else {
|
||||
gtpv1uCreateAndSendMsg(compatInst(instance),
|
||||
tmp.outgoing_ip_addr,
|
||||
tmp.outgoing_port,
|
||||
GTP_GPDU,
|
||||
tmp.teid_outgoing,
|
||||
buf,
|
||||
len,
|
||||
seqNumFlag,
|
||||
npduNumFlag,
|
||||
tmp.seqNum,
|
||||
tmp.npduNum,
|
||||
NO_MORE_EXT_HDRS,
|
||||
NULL,
|
||||
0);
|
||||
}
|
||||
|
||||
DevAssert(compatInst(instance) == bearer.sock_fd);
|
||||
gtpv1uCreateAndSendMsg(&bearer,
|
||||
GTP_GPDU,
|
||||
buf,
|
||||
len,
|
||||
seqNumFlag,
|
||||
npduNumFlag,
|
||||
opt_ext ? PDU_SESSION_CONTAINER : NO_MORE_EXT_HDRS,
|
||||
(uint8_t *)opt_ext,
|
||||
sizeof(*opt_ext));
|
||||
}
|
||||
|
||||
static void gtpv1uEndTunnel(instance_t instance, gtpv1u_enb_end_marker_req_t *req)
|
||||
@@ -424,22 +401,16 @@ static void gtpv1uEndTunnel(instance_t instance, gtpv1u_enb_end_marker_req_t *re
|
||||
msgHdr.msgType = GTP_END_MARKER;
|
||||
msgHdr.msgLength = htons(0);
|
||||
msgHdr.teid = htonl(tmp.teid_outgoing);
|
||||
// Fix me: add IPv6 support, using flag ipVersion
|
||||
static struct sockaddr_in to = {0};
|
||||
to.sin_family = AF_INET;
|
||||
to.sin_port = htons(tmp.outgoing_port);
|
||||
to.sin_addr.s_addr = tmp.outgoing_ip_addr;
|
||||
char ip4[INET_ADDRSTRLEN];
|
||||
// char ip6[INET6_ADDRSTRLEN];
|
||||
LOG_D(GTPU, "[%ld] sending end packet to %s\n", instance, inet_ntoa(to.sin_addr));
|
||||
|
||||
if (sendto(compatInst(instance), (void *)&msgHdr, sizeof(msgHdr), 0, (struct sockaddr *)&to, sizeof(to)) != sizeof(msgHdr)) {
|
||||
LOG_E(GTPU,
|
||||
"[%ld] Failed to send data to %s on port %d, buffer size %lu\n",
|
||||
compatInst(instance),
|
||||
inet_ntop(AF_INET, &tmp.outgoing_ip_addr, ip4, INET_ADDRSTRLEN),
|
||||
tmp.outgoing_port,
|
||||
sizeof(msgHdr));
|
||||
// Fix me: add IPv6 support
|
||||
DevAssert(instance == tmp.sock_fd);
|
||||
DevAssert(tmp.ip.ss_family == AF_INET);
|
||||
struct sockaddr_in *to = (struct sockaddr_in *)&tmp.ip;
|
||||
LOG_D(GTPU, "[%ld] sending end packet to " IPV4_ADDR " port %d\n", instance, IPV4_ADDR_FORMAT(to->sin_addr.s_addr), htons(to->sin_port));
|
||||
|
||||
ssize_t ret = sendto(tmp.sock_fd, &msgHdr, sizeof(msgHdr), 0, (struct sockaddr *)to, sizeof(*to));
|
||||
if (ret != sizeof(msgHdr)) {
|
||||
LOG_E(GTPU, "[%d] Failed to send data with buffer size %lu: ret %ld errno %d\n", tmp.sock_fd, sizeof(msgHdr), ret, errno);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,13 +521,17 @@ void GtpuUpdateTunnelOutgoingAddressAndTeid(instance_t instance,
|
||||
return;
|
||||
}
|
||||
|
||||
ptr2->second.outgoing_ip_addr = newOutgoingAddr;
|
||||
struct sockaddr_in *sockaddr = (struct sockaddr_in *)&ptr2->second.ip;
|
||||
sockaddr->sin_family = AF_INET;
|
||||
memcpy(&sockaddr->sin_addr, &newOutgoingAddr, sizeof(newOutgoingAddr));
|
||||
AssertFatal(ptr2->second.ip.ss_family == AF_INET, "only IPv4 is supported\n");
|
||||
ptr2->second.teid_outgoing = newOutgoingTeid;
|
||||
LOG_I(GTPU,
|
||||
"[%ld] Tunnel Outgoing TEID updated to %x and address to %x\n",
|
||||
"[%ld] Tunnel Outgoing TEID updated to %x and IPv4 address to " IPV4_ADDR "\n",
|
||||
instance,
|
||||
ptr2->second.teid_outgoing,
|
||||
ptr2->second.outgoing_ip_addr);
|
||||
IPV4_ADDR_FORMAT(sockaddr->sin_addr.s_addr));
|
||||
|
||||
pthread_mutex_unlock(&globGtp.gtp_lock);
|
||||
return;
|
||||
}
|
||||
@@ -594,42 +569,48 @@ teid_t newGtpuCreateTunnel(instance_t instance,
|
||||
globGtp.te2ue_mapping[incoming_teid].callBackSDAP = callBackSDAP;
|
||||
globGtp.te2ue_mapping[incoming_teid].pdusession_id = (uint8_t)outgoing_bearer_id;
|
||||
|
||||
gtpv1u_bearer_t *tmp = &inst->ue2te_mapping[ue_id].bearers[outgoing_bearer_id];
|
||||
gtpv1u_bearer_t bearer = {
|
||||
.sock_fd = (int) compatInst(instance), // avoid warning on narrowing conversion: instance is long, sock_fd is int
|
||||
.teid_incoming = incoming_teid,
|
||||
.teid_outgoing = outgoing_teid,
|
||||
.outgoing_qfi = outgoing_qfi,
|
||||
};
|
||||
|
||||
int addrs_length_in_bytes = remoteAddr.length / 8;
|
||||
|
||||
struct sockaddr_in *sa4 = (struct sockaddr_in *)&bearer.ip;
|
||||
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&bearer.ip;
|
||||
switch (addrs_length_in_bytes) {
|
||||
case 4:
|
||||
memcpy(&tmp->outgoing_ip_addr, remoteAddr.buffer, 4);
|
||||
memcpy(&sa4->sin_addr, remoteAddr.buffer, 4);
|
||||
sa4->sin_family = AF_INET;
|
||||
sa4->sin_port = htons(inst->get_dstport());
|
||||
break;
|
||||
|
||||
case 16:
|
||||
memcpy(tmp->outgoing_ip6_addr.s6_addr, remoteAddr.buffer, 16);
|
||||
AssertFatal(false, "IPv6 not supported\n");
|
||||
break;
|
||||
|
||||
case 20:
|
||||
memcpy(&tmp->outgoing_ip_addr, remoteAddr.buffer, 4);
|
||||
memcpy(tmp->outgoing_ip6_addr.s6_addr, remoteAddr.buffer + 4, 16);
|
||||
AssertFatal(false, "dual-IPv4/v6 not supported\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(false, "SGW Address size impossible");
|
||||
}
|
||||
|
||||
tmp->teid_incoming = incoming_teid;
|
||||
tmp->outgoing_port = inst->get_dstport();
|
||||
tmp->teid_outgoing = outgoing_teid;
|
||||
tmp->outgoing_qfi = outgoing_qfi;
|
||||
inst->ue2te_mapping[ue_id].bearers[outgoing_bearer_id] = bearer;
|
||||
pthread_mutex_unlock(&globGtp.gtp_lock);
|
||||
char ip4[INET_ADDRSTRLEN];
|
||||
char ip6[INET6_ADDRSTRLEN];
|
||||
LOG_I(GTPU,
|
||||
"[%ld] Created tunnel for UE ID %lu, teid for incoming: %x, teid for outgoing %x to remote IPv4: %s, IPv6 %s\n",
|
||||
"[%ld] Created tunnel for UE ID %lu, teid for incoming: %x, teid for outgoing %x to remote IPv4: %s, IPv6 %s, port %d\n",
|
||||
instance,
|
||||
ue_id,
|
||||
tmp->teid_incoming,
|
||||
tmp->teid_outgoing,
|
||||
inet_ntop(AF_INET, (void *)&tmp->outgoing_ip_addr, ip4, INET_ADDRSTRLEN),
|
||||
inet_ntop(AF_INET6, (void *)&tmp->outgoing_ip6_addr.s6_addr, ip6, INET6_ADDRSTRLEN));
|
||||
bearer.teid_incoming,
|
||||
bearer.teid_outgoing,
|
||||
inet_ntop(AF_INET, &sa4->sin_addr, ip4, INET_ADDRSTRLEN),
|
||||
inet_ntop(AF_INET6, &sa6->sin6_addr, ip6, INET6_ADDRSTRLEN),
|
||||
ntohs(sa4->sin_port));
|
||||
return incoming_teid;
|
||||
}
|
||||
|
||||
@@ -922,6 +903,13 @@ int gtpv1u_delete_ngu_tunnel(const instance_t instance, gtpv1u_gnb_delete_tunnel
|
||||
return newGtpuDeleteTunnels(instance, req->ue_id, req->num_pdusession, req->pdusession_id);
|
||||
}
|
||||
|
||||
static gtpv1u_bearer_t create_bearer(int socket, const struct sockaddr_in *addr, uint32_t teid, uint16_t seq)
|
||||
{
|
||||
gtpv1u_bearer_t bearer = {.sock_fd = socket, .teid_outgoing = teid, .seqNum = seq};
|
||||
memcpy(&bearer.ip, addr, sizeof(*addr));
|
||||
return bearer;
|
||||
}
|
||||
|
||||
static int Gtpv1uHandleEchoReq(int h, uint8_t *msgBuf, uint32_t msgBufLen, const struct sockaddr_in *addr)
|
||||
{
|
||||
Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *)msgBuf;
|
||||
@@ -939,17 +927,13 @@ static int Gtpv1uHandleEchoReq(int h, uint8_t *msgBuf, uint32_t msgBufLen, const
|
||||
uint16_t seq = ntohs(*(uint16_t *)(msgHdr + 1));
|
||||
LOG_D(GTPU, "[%d] Received a echo request, TEID: %d, seq: %hu\n", h, msgHdr->teid, seq);
|
||||
uint8_t recovery[2] = {14, 0};
|
||||
return gtpv1uCreateAndSendMsg(h,
|
||||
addr->sin_addr.s_addr,
|
||||
htons(addr->sin_port),
|
||||
gtpv1u_bearer_t bearer = create_bearer(h, addr, ntohl(msgHdr->teid), seq);
|
||||
return gtpv1uCreateAndSendMsg(&bearer,
|
||||
GTP_ECHO_RSP,
|
||||
ntohl(msgHdr->teid),
|
||||
recovery,
|
||||
sizeof recovery,
|
||||
true,
|
||||
false,
|
||||
seq,
|
||||
0,
|
||||
NO_MORE_EXT_HDRS,
|
||||
NULL,
|
||||
0);
|
||||
@@ -1185,17 +1169,14 @@ static int Gtpv1uHandleGpdu(int h, uint8_t *msgBuf, uint32_t msgBufLen, const st
|
||||
* 1 octet for padding + 1 octet for next extension header type,
|
||||
* according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/
|
||||
extensionHeader->length = 1 + sizeof(DlDataDeliveryStatus_flagsT) + 3 + 1 + 1;
|
||||
gtpv1uCreateAndSendMsg(h,
|
||||
addr->sin_addr.s_addr,
|
||||
htons(addr->sin_port),
|
||||
uint32_t teid = globGtp.te2ue_mapping[ntohl(msgHdr->teid)].outgoing_teid;
|
||||
gtpv1u_bearer_t bearer = create_bearer(h, addr, teid, 0);
|
||||
gtpv1uCreateAndSendMsg(&bearer,
|
||||
GTP_GPDU,
|
||||
globGtp.te2ue_mapping[ntohl(msgHdr->teid)].outgoing_teid,
|
||||
NULL,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
NR_RAN_CONTAINER,
|
||||
extensionHeader->buffer,
|
||||
extensionHeader->length);
|
||||
|
||||
Reference in New Issue
Block a user