forked from acouzens/open5gs
GTP Loopback Test Module is Added.
1. ping(src:45.45.0.1, dst:45.45.0.1) 2. MME emulates GTP-U instead of eNB, and send GTP-U to the SGW 3. SGW relay to PGW using GTP-U 4. PGW TUN reponse ping reply 5. PGW sends GTP-U to the SGW 6. SGW sends GTP-U to the MME 7. GTP-U decapsulates and sends ping packet to the kernel
This commit is contained in:
parent
1f14b132c2
commit
172266b0c5
|
@ -32,7 +32,7 @@ case $host in
|
|||
;;
|
||||
*-apple-darwin*)
|
||||
OSDIR="unix"
|
||||
OSPPCFLAGS="-DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK"
|
||||
OSCPPFLAGS="-DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK"
|
||||
;;
|
||||
*)
|
||||
OSDIR="unix"
|
||||
|
|
|
@ -266,6 +266,8 @@ CORE_DECLARE(int) net_fds_read_run(long timeout);
|
|||
CORE_DECLARE(int) net_tuntap_open(net_link_t **net_link, char *tuntap_dev_name,
|
||||
int is_tap);
|
||||
|
||||
CORE_DECLARE(int) net_tuntap_set_ipv4(c_uint32_t ip_addr, c_uint8_t bits);
|
||||
|
||||
CORE_DECLARE(int) net_tuntap_close(net_link_t *net_link);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -1225,6 +1225,66 @@ cleanup:
|
|||
#endif
|
||||
}
|
||||
|
||||
int net_tuntap_set_ipv4(c_uint32_t ip_addr, c_uint8_t bits)
|
||||
{
|
||||
#if LINUX == 1
|
||||
/* No root priviledge */
|
||||
return 0;
|
||||
#elif defined(DARWIN)
|
||||
c_uint32_t mask_addr = htonl(0xffffffff << (32 - bits));
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
char *dev = "tun0";
|
||||
struct ifaliasreq ifa;
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_in mask;
|
||||
|
||||
(void)memset(&ifa, '\0', sizeof ifa);
|
||||
(void)strlcpy(ifa.ifra_name, dev, sizeof ifa.ifra_name);
|
||||
|
||||
(void)memset(&ifr, '\0', sizeof ifr);
|
||||
(void)strlcpy(ifr.ifr_name, dev, sizeof ifr.ifr_name);
|
||||
|
||||
/* Delete previously assigned address */
|
||||
(void)ioctl(sock, SIOCDIFADDR, &ifr);
|
||||
|
||||
/*
|
||||
* Fill-in the destination address and netmask,
|
||||
* but don't care of the broadcast address
|
||||
*/
|
||||
(void)memset(&addr, '\0', sizeof addr);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = ip_addr;
|
||||
addr.sin_len = sizeof addr;
|
||||
(void)memcpy(&ifa.ifra_addr, &addr, sizeof addr);
|
||||
|
||||
(void)memset(&mask, '\0', sizeof mask);
|
||||
mask.sin_family = AF_INET;
|
||||
mask.sin_addr.s_addr = mask_addr;
|
||||
mask.sin_len = sizeof mask;
|
||||
(void)memcpy(&ifa.ifra_mask, &mask, sizeof ifa.ifra_mask);
|
||||
|
||||
/* Simpler than calling SIOCSIFADDR and/or SIOCSIFBRDADDR */
|
||||
if (ioctl(sock, SIOCSIFADDR, &ifa) == -1) {
|
||||
d_error("Can't set IP/netmask");
|
||||
return -1;
|
||||
}
|
||||
|
||||
(void)memcpy(&ifr.ifr_addr, &addr, sizeof addr);
|
||||
if (ioctl(sock, SIOCSIFDSTADDR, &ifr) == -1) {
|
||||
d_error("Can't set IP/netmask");
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(sock);
|
||||
return 0;
|
||||
#else
|
||||
/* TODO */
|
||||
return 0;
|
||||
#endif /* LINUX != 1 */
|
||||
}
|
||||
|
||||
|
||||
#if LINUX == 1
|
||||
int net_link_open(net_link_t **net_link, char *device, int proto)
|
||||
|
|
|
@ -192,6 +192,8 @@ status_t pgw_gtp_open()
|
|||
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
|
||||
/* NOTE : tun device can be created via following command.
|
||||
*
|
||||
|
@ -212,6 +214,20 @@ status_t pgw_gtp_open()
|
|||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < pgw_self()->num_of_ip_pool; i++)
|
||||
{
|
||||
rc = net_tuntap_set_ipv4(
|
||||
pgw_self()->ip_pool[i].prefix, pgw_self()->ip_pool[i].mask);
|
||||
if (rc != 0)
|
||||
{
|
||||
d_error("Can not configure tun(dev : %s for %s/%d)",
|
||||
pgw_self()->tun_dev_name,
|
||||
INET_NTOP(&pgw_self()->ip_pool[i].prefix, buf),
|
||||
pgw_self()->ip_pool[i].mask);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
rc = net_register_link(pgw_self()->tun_link, _gtpv1_tun_recv_cb, NULL);
|
||||
if (rc != 0)
|
||||
{
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
|
||||
IP_POOL :
|
||||
{
|
||||
CIDR: 45.45.45.0/24
|
||||
CIDR: 45.45.0.1/24
|
||||
}
|
||||
|
||||
DNS :
|
||||
|
|
|
@ -19,6 +19,7 @@ static void attach_test1(abts_case *tc, void *data)
|
|||
{
|
||||
status_t rv;
|
||||
net_sock_t *sock;
|
||||
net_sock_t *gtpu;
|
||||
pkbuf_t *sendbuf;
|
||||
pkbuf_t *recvbuf;
|
||||
s1ap_message_t message;
|
||||
|
@ -39,8 +40,8 @@ static void attach_test1(abts_case *tc, void *data)
|
|||
char *_initial_context_setup_request =
|
||||
"00090080d8000006 00000005c0010000 9d00080002000100 42000a183e800000"
|
||||
"603e800000001800 8086000034008080 450009200f800a01 23d8000000017127"
|
||||
"fcf13a9702074202 49064000f1105ba0 00485221c1010909 08696e7465726e65"
|
||||
"7405012d2d2d015e 06fefeeeee030327 2980c22304030000 0480211002000010"
|
||||
"a21f172602074202 49064000f1105ba0 00485221c1010909 08696e7465726e65"
|
||||
"7405012d2d00015e 06fefeeeee030327 2980c22304030000 0480211002000010"
|
||||
"8106080808088306 04040404000d0408 080808000d040404 0404500bf600f110"
|
||||
"0002010000000153 12172c5949640125 006b000518000c00 00004900203311c6"
|
||||
"03c6a6d67f695e5a c02bb75b381b693c 3893a6d932fd9182 3544e3e79b000000"
|
||||
|
@ -138,6 +139,10 @@ static void attach_test1(abts_case *tc, void *data)
|
|||
sock = tests1ap_enb_connect();
|
||||
ABTS_PTR_NOTNULL(tc, sock);
|
||||
|
||||
/* eNB connects to SGW */
|
||||
gtpu = testgtpu_enb_connect();
|
||||
ABTS_PTR_NOTNULL(tc, gtpu);
|
||||
|
||||
/* Send S1-Setup Reqeust */
|
||||
rv = tests1ap_build_setup_req(
|
||||
&sendbuf, S1ap_ENB_ID_PR_macroENB_ID, 0x54f64);
|
||||
|
@ -287,6 +292,19 @@ static void attach_test1(abts_case *tc, void *data)
|
|||
ABTS_TRUE(tc, memcmp(recvbuf->payload+43, tmp+43, 3) == 0);
|
||||
pkbuf_free(recvbuf);
|
||||
|
||||
core_sleep(time_from_msec(300));
|
||||
|
||||
/* Send GTP-U ICMP Packet */
|
||||
rv = testgtpu_enb_send(gtpu);
|
||||
ABTS_INT_EQUAL(tc, CORE_OK, rv);
|
||||
|
||||
#if 0
|
||||
/* Receive GTP-U ICMP Packet */
|
||||
recvbuf = pkbuf_alloc(0, MAX_SDU_LEN);
|
||||
rc = testgtpu_enb_read(gtpu, recvbuf);
|
||||
pkbuf_free(recvbuf);
|
||||
#endif
|
||||
|
||||
/*****************************************************************
|
||||
* Attach Request : Known GUTI, Integrity Protected, MAC Matched
|
||||
* Send Initial-UE Message + Attach Request + PDN Connectivity */
|
||||
|
@ -408,6 +426,10 @@ static void attach_test1(abts_case *tc, void *data)
|
|||
rv = tests1ap_enb_close(sock);
|
||||
ABTS_INT_EQUAL(tc, CORE_OK, rv);
|
||||
|
||||
/* eNB disonncect from SGW */
|
||||
rv = testgtpu_enb_close(gtpu);
|
||||
ABTS_INT_EQUAL(tc, CORE_OK, rv);
|
||||
|
||||
core_sleep(time_from_msec(300));
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,133 @@ int tests1ap_enb_read(net_sock_t *sock, pkbuf_t *recvbuf)
|
|||
return rc;
|
||||
}
|
||||
|
||||
net_sock_t *testgtpu_enb_connect(void)
|
||||
{
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
int rc;
|
||||
mme_context_t *mme = mme_self();
|
||||
net_sock_t *sock = NULL;
|
||||
|
||||
if (!mme) return NULL;
|
||||
|
||||
rc = net_listen_ext(&sock, SOCK_DGRAM, IPPROTO_UDP,
|
||||
0, mme->s1ap_addr, GTPV1_U_UDP_PORT);
|
||||
if (rc != 0) return NULL;
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
status_t testgtpu_enb_close(net_sock_t *sock)
|
||||
{
|
||||
return net_close(sock);
|
||||
}
|
||||
|
||||
static uint16_t in_cksum(uint16_t *addr, int len)
|
||||
{
|
||||
int nleft = len;
|
||||
uint32_t sum = 0;
|
||||
uint16_t *w = addr;
|
||||
uint16_t answer = 0;
|
||||
|
||||
// Adding 16 bits sequentially in sum
|
||||
while (nleft > 1) {
|
||||
sum += *w;
|
||||
nleft -= 2;
|
||||
w++;
|
||||
}
|
||||
|
||||
// If an odd byte is left
|
||||
if (nleft == 1) {
|
||||
*(unsigned char *) (&answer) = *(unsigned char *) w;
|
||||
sum += answer;
|
||||
}
|
||||
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
sum += (sum >> 16);
|
||||
answer = ~sum;
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
int testgtpu_enb_send(net_sock_t *sock)
|
||||
{
|
||||
mme_sgw_t *sgw = mme_sgw_first();
|
||||
if (!sgw) return -1;
|
||||
|
||||
status_t rv;
|
||||
pkbuf_t *pkbuf = NULL;
|
||||
gtp_header_t *gtp_h = NULL;
|
||||
gtp_node_t gnode;
|
||||
struct ip *ip_h = NULL;
|
||||
struct icmp_header_t {
|
||||
c_int8_t type;
|
||||
c_int8_t code;
|
||||
c_int16_t checksum;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
c_int16_t id;
|
||||
c_int16_t sequence;
|
||||
} echo; /* echo datagram */
|
||||
u_int32_t gateway; /* gateway address */
|
||||
struct
|
||||
{
|
||||
c_int16_t __glibc_reserved;
|
||||
c_int16_t mtu;
|
||||
} frag; /* path mtu discovery */
|
||||
} un;
|
||||
} *icmp_h = NULL;
|
||||
|
||||
pkbuf = pkbuf_alloc(0, 100 /* enough for ICMP; use smaller buffer */);
|
||||
d_assert(pkbuf, return CORE_ERROR,);
|
||||
memset(pkbuf->payload, 0, pkbuf->len);
|
||||
|
||||
gtp_h = (gtp_header_t *)pkbuf->payload;
|
||||
ip_h = (struct ip *)(pkbuf->payload + GTPV1U_HEADER_LEN);
|
||||
icmp_h = (struct icmp_header_t *)
|
||||
(pkbuf->payload + GTPV1U_HEADER_LEN + sizeof(struct ip));
|
||||
|
||||
gtp_h->flags = 0x30;
|
||||
gtp_h->type = GTPU_MSGTYPE_GPDU;
|
||||
gtp_h->teid = htonl(1);
|
||||
gtp_h->length = htons(sizeof(struct ip) + sizeof(struct icmp_header_t));
|
||||
|
||||
ip_h->ip_v = 4;
|
||||
ip_h->ip_hl = 5;
|
||||
ip_h->ip_tos = 0;
|
||||
ip_h->ip_id = rand();
|
||||
ip_h->ip_off = 0;
|
||||
ip_h->ip_ttl = 255;
|
||||
ip_h->ip_p = IPPROTO_ICMP;
|
||||
ip_h->ip_len = gtp_h->length;
|
||||
ip_h->ip_src.s_addr = inet_addr("45.45.0.1");
|
||||
ip_h->ip_dst.s_addr = inet_addr("45.45.0.1");
|
||||
ip_h->ip_sum = in_cksum(
|
||||
(unsigned short *)ip_h, sizeof(struct ip));
|
||||
|
||||
icmp_h->type = 8;
|
||||
icmp_h->un.echo.sequence = rand();
|
||||
icmp_h->un.echo.id = rand();
|
||||
icmp_h->checksum = in_cksum(
|
||||
(unsigned short *)icmp_h, sizeof(struct icmp_header_t));
|
||||
|
||||
gnode.addr = sgw->addr;
|
||||
gnode.port = GTPV1_U_UDP_PORT;
|
||||
gnode.sock = sock;
|
||||
|
||||
rv = gtp_send(&gnode, pkbuf);
|
||||
pkbuf_free(pkbuf);
|
||||
|
||||
if (rv != CORE_OK) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testgtpu_enb_read(net_sock_t *sock, pkbuf_t *recvbuf)
|
||||
{
|
||||
return tests1ap_enb_read(sock, recvbuf);
|
||||
}
|
||||
|
||||
status_t tests1ap_build_setup_req(
|
||||
pkbuf_t **pkbuf, S1ap_ENB_ID_PR present, c_uint32_t enb_id)
|
||||
|
@ -507,7 +634,7 @@ status_t tests1ap_build_initial_context_setup_response(pkbuf_t **pkbuf, int i)
|
|||
char *payload[TESTS1AP_MAX_MESSAGE] = {
|
||||
"2009"
|
||||
"0025000003000040 05c00100009d0008 400200010033400f 000032400a0a1f0a"
|
||||
"012d2801000008",
|
||||
"0123d700000001",
|
||||
"",
|
||||
"",
|
||||
|
||||
|
|
|
@ -12,6 +12,11 @@ CORE_DECLARE(status_t) tests1ap_enb_close(net_sock_t *sock);
|
|||
CORE_DECLARE(int) tests1ap_enb_send(net_sock_t *sock, pkbuf_t *sendbuf);
|
||||
CORE_DECLARE(int) tests1ap_enb_read(net_sock_t *sock, pkbuf_t *recvbuf);
|
||||
|
||||
CORE_DECLARE(net_sock_t) *testgtpu_enb_connect(void);
|
||||
CORE_DECLARE(status_t) testgtpu_enb_close(net_sock_t *sock);
|
||||
CORE_DECLARE(int) testgtpu_enb_send(net_sock_t *sock);
|
||||
CORE_DECLARE(int) testgtpu_enb_read(net_sock_t *sock, pkbuf_t *recvbuf);
|
||||
|
||||
CORE_DECLARE(status_t) tests1ap_build_setup_req(
|
||||
pkbuf_t **pkbuf, S1ap_ENB_ID_PR present, c_uint32_t enb_id);
|
||||
CORE_DECLARE(status_t) tests1ap_build_initial_ue_msg(pkbuf_t **pkbuf, int i);
|
||||
|
|
Loading…
Reference in New Issue