forked from acouzens/open5gs
Fix the bug (#194)
This commit is contained in:
parent
3c61858f21
commit
c530e1cbcf
|
@ -1,3 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Open5GS.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "base/base.h"
|
#include "base/base.h"
|
||||||
|
|
||||||
#if HAVE_NETINET_IP_H
|
#if HAVE_NETINET_IP_H
|
||||||
|
@ -46,8 +65,7 @@ static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||||
ogs_pkbuf_put(recvbuf, MAX_SDU_LEN-GTPV1U_HEADER_LEN);
|
ogs_pkbuf_put(recvbuf, MAX_SDU_LEN-GTPV1U_HEADER_LEN);
|
||||||
|
|
||||||
n = ogs_read(fd, recvbuf->data, recvbuf->len);
|
n = ogs_read(fd, recvbuf->data, recvbuf->len);
|
||||||
if (n <= 0)
|
if (n <= 0) {
|
||||||
{
|
|
||||||
ogs_log_message(OGS_LOG_WARN, ogs_socket_errno, "ogs_read() failed");
|
ogs_log_message(OGS_LOG_WARN, ogs_socket_errno, "ogs_read() failed");
|
||||||
ogs_pkbuf_free(recvbuf);
|
ogs_pkbuf_free(recvbuf);
|
||||||
return;
|
return;
|
||||||
|
@ -57,16 +75,12 @@ static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||||
|
|
||||||
/* Find the bearer by packet filter */
|
/* Find the bearer by packet filter */
|
||||||
bearer = pgw_bearer_find_by_packet(recvbuf);
|
bearer = pgw_bearer_find_by_packet(recvbuf);
|
||||||
if (bearer)
|
if (bearer) {
|
||||||
{
|
|
||||||
/* Unicast */
|
/* Unicast */
|
||||||
rv = pgw_gtp_send_to_bearer(bearer, recvbuf);
|
rv = pgw_gtp_send_to_bearer(bearer, recvbuf);
|
||||||
ogs_assert(rv == OGS_OK);
|
ogs_assert(rv == OGS_OK);
|
||||||
}
|
} else {
|
||||||
else
|
if (context_self()->config.parameter.multicast) {
|
||||||
{
|
|
||||||
if (context_self()->config.parameter.multicast)
|
|
||||||
{
|
|
||||||
rv = pgw_gtp_handle_multicast(recvbuf);
|
rv = pgw_gtp_handle_multicast(recvbuf);
|
||||||
ogs_assert(rv != OGS_ERROR);
|
ogs_assert(rv != OGS_ERROR);
|
||||||
}
|
}
|
||||||
|
@ -133,8 +147,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||||
"ogs_recv() failed");
|
"ogs_recv() failed");
|
||||||
ogs_pkbuf_free(pkbuf);
|
goto cleanup;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ogs_pkbuf_trim(pkbuf, size);
|
ogs_pkbuf_trim(pkbuf, size);
|
||||||
|
@ -155,7 +168,10 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||||
ogs_assert(ip_h);
|
ogs_assert(ip_h);
|
||||||
|
|
||||||
bearer = pgw_bearer_find_by_pgw_s5u_teid(teid);
|
bearer = pgw_bearer_find_by_pgw_s5u_teid(teid);
|
||||||
ogs_assert(bearer);
|
if (!bearer) {
|
||||||
|
ogs_warn("[DROP] Cannot find PGW S5U bearer : TEID[0x%x]", teid);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
sess = bearer->sess;
|
sess = bearer->sess;
|
||||||
ogs_assert(sess);
|
ogs_assert(sess);
|
||||||
|
|
||||||
|
@ -164,8 +180,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||||
else if (ip_h->ip_v == 6 && sess->ipv6)
|
else if (ip_h->ip_v == 6 && sess->ipv6)
|
||||||
subnet = sess->ipv6->subnet;
|
subnet = sess->ipv6->subnet;
|
||||||
|
|
||||||
if (!subnet)
|
if (!subnet) {
|
||||||
{
|
|
||||||
ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data, pkbuf->len);
|
ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data, pkbuf->len);
|
||||||
ogs_trace("[DROP] Cannot find subnet V:%d, IPv4:%p, IPv6:%p",
|
ogs_trace("[DROP] Cannot find subnet V:%d, IPv4:%p, IPv6:%p",
|
||||||
ip_h->ip_v, sess->ipv4, sess->ipv6);
|
ip_h->ip_v, sess->ipv4, sess->ipv6);
|
||||||
|
@ -173,13 +188,10 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check IPv6 */
|
/* Check IPv6 */
|
||||||
if (context_self()->config.parameter.no_slaac == 0 && ip_h->ip_v == 6)
|
if (context_self()->config.parameter.no_slaac == 0 && ip_h->ip_v == 6) {
|
||||||
{
|
|
||||||
rv = pgw_gtp_handle_slaac(sess, pkbuf);
|
rv = pgw_gtp_handle_slaac(sess, pkbuf);
|
||||||
if (rv == PGW_GTP_HANDLED)
|
if (rv == PGW_GTP_HANDLED) {
|
||||||
{
|
goto cleanup;
|
||||||
ogs_pkbuf_free(pkbuf);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
ogs_assert(rv == OGS_OK);
|
ogs_assert(rv == OGS_OK);
|
||||||
}
|
}
|
||||||
|
@ -201,16 +213,14 @@ int pgw_gtp_open()
|
||||||
ogs_sock_t *sock = NULL;
|
ogs_sock_t *sock = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
ogs_list_for_each(&pgw_self()->gtpc_list, node)
|
ogs_list_for_each(&pgw_self()->gtpc_list, node) {
|
||||||
{
|
|
||||||
ogs_socknode_set_poll(node, pgw_self()->pollset,
|
ogs_socknode_set_poll(node, pgw_self()->pollset,
|
||||||
OGS_POLLIN, _gtpv2_c_recv_cb, NULL);
|
OGS_POLLIN, _gtpv2_c_recv_cb, NULL);
|
||||||
|
|
||||||
sock = gtp_server(node);
|
sock = gtp_server(node);
|
||||||
ogs_assert(sock);
|
ogs_assert(sock);
|
||||||
}
|
}
|
||||||
ogs_list_for_each(&pgw_self()->gtpc_list6, node)
|
ogs_list_for_each(&pgw_self()->gtpc_list6, node) {
|
||||||
{
|
|
||||||
ogs_socknode_set_poll(node, pgw_self()->pollset,
|
ogs_socknode_set_poll(node, pgw_self()->pollset,
|
||||||
OGS_POLLIN, _gtpv2_c_recv_cb, NULL);
|
OGS_POLLIN, _gtpv2_c_recv_cb, NULL);
|
||||||
|
|
||||||
|
@ -225,16 +235,14 @@ int pgw_gtp_open()
|
||||||
|
|
||||||
ogs_assert(pgw_self()->gtpc_addr || pgw_self()->gtpc_addr6);
|
ogs_assert(pgw_self()->gtpc_addr || pgw_self()->gtpc_addr6);
|
||||||
|
|
||||||
ogs_list_for_each(&pgw_self()->gtpu_list, node)
|
ogs_list_for_each(&pgw_self()->gtpu_list, node) {
|
||||||
{
|
|
||||||
ogs_socknode_set_poll(node, pgw_self()->pollset,
|
ogs_socknode_set_poll(node, pgw_self()->pollset,
|
||||||
OGS_POLLIN, _gtpv1_u_recv_cb, NULL);
|
OGS_POLLIN, _gtpv1_u_recv_cb, NULL);
|
||||||
|
|
||||||
sock = gtp_server(node);
|
sock = gtp_server(node);
|
||||||
ogs_assert(sock);
|
ogs_assert(sock);
|
||||||
}
|
}
|
||||||
ogs_list_for_each(&pgw_self()->gtpu_list6, node)
|
ogs_list_for_each(&pgw_self()->gtpu_list6, node) {
|
||||||
{
|
|
||||||
ogs_socknode_set_poll(node, pgw_self()->pollset,
|
ogs_socknode_set_poll(node, pgw_self()->pollset,
|
||||||
OGS_POLLIN, _gtpv1_u_recv_cb, NULL);
|
OGS_POLLIN, _gtpv1_u_recv_cb, NULL);
|
||||||
|
|
||||||
|
@ -261,11 +269,9 @@ int pgw_gtp_open()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Open Tun interface */
|
/* Open Tun interface */
|
||||||
for (dev = pgw_dev_first(); dev; dev = pgw_dev_next(dev))
|
for (dev = pgw_dev_first(); dev; dev = pgw_dev_next(dev)) {
|
||||||
{
|
|
||||||
dev->fd = ogs_tun_open(dev->ifname, IFNAMSIZ, 0);
|
dev->fd = ogs_tun_open(dev->ifname, IFNAMSIZ, 0);
|
||||||
if (dev->fd == INVALID_SOCKET)
|
if (dev->fd == INVALID_SOCKET) {
|
||||||
{
|
|
||||||
ogs_error("tun_open(dev:%s) failed", dev->ifname);
|
ogs_error("tun_open(dev:%s) failed", dev->ifname);
|
||||||
return OGS_ERROR;
|
return OGS_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -286,12 +292,11 @@ int pgw_gtp_open()
|
||||||
|
|
||||||
/* Set P-to-P IP address with Netmask
|
/* Set P-to-P IP address with Netmask
|
||||||
* Note that Linux will skip this configuration */
|
* Note that Linux will skip this configuration */
|
||||||
for (subnet = pgw_subnet_first(); subnet; subnet = pgw_subnet_next(subnet))
|
for (subnet = pgw_subnet_first();
|
||||||
{
|
subnet; subnet = pgw_subnet_next(subnet)) {
|
||||||
ogs_assert(subnet->dev);
|
ogs_assert(subnet->dev);
|
||||||
rc = ogs_tun_set_ip(subnet->dev->ifname, &subnet->gw, &subnet->sub);
|
rc = ogs_tun_set_ip(subnet->dev->ifname, &subnet->gw, &subnet->sub);
|
||||||
if (rc != OGS_OK)
|
if (rc != OGS_OK) {
|
||||||
{
|
|
||||||
ogs_error("ogs_tun_set_ip(dev:%s) failed", subnet->dev->ifname);
|
ogs_error("ogs_tun_set_ip(dev:%s) failed", subnet->dev->ifname);
|
||||||
return OGS_ERROR;
|
return OGS_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -313,8 +318,7 @@ void pgw_gtp_close()
|
||||||
ogs_socknode_remove_all(&pgw_self()->gtpu_list);
|
ogs_socknode_remove_all(&pgw_self()->gtpu_list);
|
||||||
ogs_socknode_remove_all(&pgw_self()->gtpu_list6);
|
ogs_socknode_remove_all(&pgw_self()->gtpu_list6);
|
||||||
|
|
||||||
for (dev = pgw_dev_first(); dev; dev = pgw_dev_next(dev))
|
for (dev = pgw_dev_first(); dev; dev = pgw_dev_next(dev)) {
|
||||||
{
|
|
||||||
ogs_pollset_remove(dev->poll);
|
ogs_pollset_remove(dev->poll);
|
||||||
ogs_closesocket(dev->fd);
|
ogs_closesocket(dev->fd);
|
||||||
}
|
}
|
||||||
|
@ -327,8 +331,7 @@ static int pgw_gtp_handle_multicast(ogs_pkbuf_t *recvbuf)
|
||||||
struct ip6_hdr *ip6_h = NULL;
|
struct ip6_hdr *ip6_h = NULL;
|
||||||
|
|
||||||
ip_h = (struct ip *)recvbuf->data;
|
ip_h = (struct ip *)recvbuf->data;
|
||||||
if (ip_h->ip_v == 6)
|
if (ip_h->ip_v == 6) {
|
||||||
{
|
|
||||||
#if COMPILE_ERROR_IN_MAC_OS_X /* Compiler error in Mac OS X platform */
|
#if COMPILE_ERROR_IN_MAC_OS_X /* Compiler error in Mac OS X platform */
|
||||||
ip6_h = (struct ip6_hdr *)recvbuf->data;
|
ip6_h = (struct ip6_hdr *)recvbuf->data;
|
||||||
if (IN6_IS_ADDR_MULTICAST(&ip6_h->ip6_dst))
|
if (IN6_IS_ADDR_MULTICAST(&ip6_h->ip6_dst))
|
||||||
|
@ -342,12 +345,10 @@ static int pgw_gtp_handle_multicast(ogs_pkbuf_t *recvbuf)
|
||||||
ogs_hash_index_t *hi = NULL;
|
ogs_hash_index_t *hi = NULL;
|
||||||
|
|
||||||
/* IPv6 Multicast */
|
/* IPv6 Multicast */
|
||||||
for (hi = pgw_sess_first(); hi; hi = pgw_sess_next(hi))
|
for (hi = pgw_sess_first(); hi; hi = pgw_sess_next(hi)) {
|
||||||
{
|
|
||||||
pgw_sess_t *sess = pgw_sess_this(hi);
|
pgw_sess_t *sess = pgw_sess_this(hi);
|
||||||
ogs_assert(sess);
|
ogs_assert(sess);
|
||||||
if (sess->ipv6)
|
if (sess->ipv6) {
|
||||||
{
|
|
||||||
/* PDN IPv6 is avaiable */
|
/* PDN IPv6 is avaiable */
|
||||||
pgw_bearer_t *bearer = pgw_default_bearer_in_sess(sess);
|
pgw_bearer_t *bearer = pgw_default_bearer_in_sess(sess);
|
||||||
ogs_assert(bearer);
|
ogs_assert(bearer);
|
||||||
|
@ -373,18 +374,14 @@ static int pgw_gtp_handle_slaac(pgw_sess_t *sess, ogs_pkbuf_t *recvbuf)
|
||||||
ogs_assert(recvbuf);
|
ogs_assert(recvbuf);
|
||||||
ogs_assert(recvbuf->len);
|
ogs_assert(recvbuf->len);
|
||||||
ip_h = (struct ip *)recvbuf->data;
|
ip_h = (struct ip *)recvbuf->data;
|
||||||
if (ip_h->ip_v == 6)
|
if (ip_h->ip_v == 6) {
|
||||||
{
|
|
||||||
struct ip6_hdr *ip6_h = (struct ip6_hdr *)recvbuf->data;
|
struct ip6_hdr *ip6_h = (struct ip6_hdr *)recvbuf->data;
|
||||||
if (ip6_h->ip6_nxt == IPPROTO_ICMPV6)
|
if (ip6_h->ip6_nxt == IPPROTO_ICMPV6) {
|
||||||
{
|
|
||||||
struct icmp6_hdr *icmp_h =
|
struct icmp6_hdr *icmp_h =
|
||||||
(struct icmp6_hdr *)(recvbuf->data + sizeof(struct ip6_hdr));
|
(struct icmp6_hdr *)(recvbuf->data + sizeof(struct ip6_hdr));
|
||||||
if (icmp_h->icmp6_type == ND_ROUTER_SOLICIT)
|
if (icmp_h->icmp6_type == ND_ROUTER_SOLICIT) {
|
||||||
{
|
|
||||||
ogs_debug("[PGW] Router Solict");
|
ogs_debug("[PGW] Router Solict");
|
||||||
if (sess->ipv6)
|
if (sess->ipv6) {
|
||||||
{
|
|
||||||
rv = pgw_gtp_send_router_advertisement(
|
rv = pgw_gtp_send_router_advertisement(
|
||||||
sess, ip6_h->ip6_src.s6_addr);
|
sess, ip6_h->ip6_src.s6_addr);
|
||||||
ogs_assert(rv == OGS_OK);
|
ogs_assert(rv == OGS_OK);
|
||||||
|
@ -531,16 +528,14 @@ uint16_t in_cksum(uint16_t *addr, int len)
|
||||||
uint16_t answer = 0;
|
uint16_t answer = 0;
|
||||||
|
|
||||||
// Adding 16 bits sequentially in sum
|
// Adding 16 bits sequentially in sum
|
||||||
while (nleft > 1)
|
while (nleft > 1) {
|
||||||
{
|
|
||||||
sum += *w;
|
sum += *w;
|
||||||
nleft -= 2;
|
nleft -= 2;
|
||||||
w++;
|
w++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If an odd byte is left
|
// If an odd byte is left
|
||||||
if (nleft == 1)
|
if (nleft == 1) {
|
||||||
{
|
|
||||||
*(uint8_t *) (&answer) = *(uint8_t *) w;
|
*(uint8_t *) (&answer) = *(uint8_t *) w;
|
||||||
sum += answer;
|
sum += answer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,24 @@
|
||||||
#ifndef __PGW_PATH_H__
|
/*
|
||||||
#define __PGW_PATH_H__
|
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Open5GS.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PGW_PATH_H
|
||||||
|
#define PGW_PATH_H
|
||||||
|
|
||||||
#include "ogs-tun.h"
|
#include "ogs-tun.h"
|
||||||
#include "gtp/gtp-xact.h"
|
#include "gtp/gtp-xact.h"
|
||||||
|
@ -13,6 +32,6 @@ void pgw_gtp_close();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif
|
||||||
|
|
||||||
#endif /* __PGW_PATH_H__ */
|
#endif /* PGW_PATH_H */
|
||||||
|
|
Loading…
Reference in New Issue