forked from acouzens/open5gs
Merge branch 'ipv6' of https://github.com/acetcom/nextepc into ipv6
This commit is contained in:
commit
7ea5f3d910
|
@ -254,7 +254,7 @@ AC_CHECK_HEADERS( \
|
|||
sys/uio.h \
|
||||
)
|
||||
|
||||
AC_CHECK_HEADERS(netinet/ip.h net/route.h,,,[[
|
||||
AC_CHECK_HEADERS(netinet/ip.h netinet/ip6.h net/route.h,,,[[
|
||||
#include <sys/types.h>
|
||||
#if HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
|
|
|
@ -121,7 +121,7 @@ typedef struct _paa_t {
|
|||
/* 8.34 PDN Type */
|
||||
#define GTP_PDN_TYPE_IPV4 1
|
||||
#define GTP_PDN_TYPE_IPV6 2
|
||||
#define GTP_PDN_TYPE_BOTH 3
|
||||
#define GTP_PDN_TYPE_IPV4V6 3
|
||||
#define GTP_PDN_TYPE_NON_IP 4
|
||||
ED2(c_uint8_t spare:5;,
|
||||
c_uint8_t pdn_type:3;)
|
||||
|
@ -137,13 +137,12 @@ ED2(c_uint8_t spare:5;,
|
|||
|
||||
/* GTP_PDN_TYPE_BOTH */
|
||||
struct {
|
||||
c_uint32_t addr;
|
||||
|
||||
struct {
|
||||
c_uint8_t len;
|
||||
c_uint8_t addr6[IPV6_LEN];
|
||||
};
|
||||
} both;
|
||||
c_uint32_t addr;
|
||||
} __attribute__ ((packed)) both;
|
||||
};
|
||||
} __attribute__ ((packed)) paa_t;
|
||||
|
||||
|
@ -217,20 +216,17 @@ typedef struct _pcc_rule_t {
|
|||
typedef struct _pdn_t {
|
||||
c_uint32_t context_identifier;
|
||||
c_int8_t apn[MAX_APN_LEN+1];
|
||||
#define S6A_PDN_TYPE_IPV4 0
|
||||
#define S6A_PDN_TYPE_IPV6 1
|
||||
#define S6A_PDN_TYPE_IPV4_AND_IPV6 2
|
||||
#define S6A_PDN_TYPE_IPV4_OR_IPV6 3
|
||||
#define HSS_PDN_TYPE_IPV4 0
|
||||
#define HSS_PDN_TYPE_IPV6 1
|
||||
#define HSS_PDN_TYPE_IPV4V6 2
|
||||
#define HSS_PDN_TYPE_IPV4_OR_IPV6 3
|
||||
c_int8_t pdn_type;
|
||||
|
||||
qos_t qos;
|
||||
bitrate_t ambr; /* APN-AMBR */
|
||||
|
||||
paa_t paa;
|
||||
struct {
|
||||
c_uint32_t ipv4_addr;
|
||||
c_uint8_t ipv6_addr[IPV6_LEN];
|
||||
} pgw;
|
||||
ip_t pgw_ip;
|
||||
} pdn_t;
|
||||
|
||||
CORE_DECLARE(c_int16_t) apn_build(c_int8_t *dst, c_int8_t *src, c_int16_t len);
|
||||
|
@ -244,10 +240,12 @@ CORE_DECLARE(c_int16_t) apn_parse(c_int8_t *dst, c_int8_t *src, c_int16_t len);
|
|||
* RFC 1661 [102] */
|
||||
#define PCO_PPP_FOR_USE_WITH_IP_PDP_TYPE_OR_IP_PDN_TYPE 0
|
||||
|
||||
#define PCO_ID_INTERNET_PROTOCOL_CONTROL_PROTOCOL 0x8021
|
||||
#define PCO_ID_CHALLENGE_HANDSHAKE_AUTHENTICATION_PROTOCOL 0xc223
|
||||
#define PCO_ID_DNS_SERVER_IPV4_ADDRESS_REQUEST 0x000d
|
||||
#define PCO_ID_IP_ADDRESS_ALLOCATION_VIA_NAS_SIGNALLING 0x000a
|
||||
#define PCO_ID_INTERNET_PROTOCOL_CONTROL_PROTOCOL 0x8021
|
||||
#define PCO_ID_CHALLENGE_HANDSHAKE_AUTHENTICATION_PROTOCOL 0xc223
|
||||
#define PCO_ID_DNS_SERVER_IPV6_ADDRESS_REQUEST 0x0003
|
||||
#define PCO_ID_DNS_SERVER_IPV4_ADDRESS_REQUEST 0x000d
|
||||
#define PCO_ID_IP_ADDRESS_ALLOCATION_VIA_NAS_SIGNALLING 0x000a
|
||||
#define PCO_ID_IPV4_LINK_MTU_REQUEST 0x0010
|
||||
typedef struct _pco_ipcp_options_t {
|
||||
c_uint8_t type;
|
||||
c_uint8_t len;
|
||||
|
|
|
@ -4,10 +4,6 @@
|
|||
#include "core_list.h"
|
||||
#include "core_network.h"
|
||||
|
||||
#if HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
|
|
@ -136,6 +136,10 @@
|
|||
#include <netinet/ip.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_NETINET_IP6_H
|
||||
#include <netinet/ip6.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_NETINET_UDP_H
|
||||
#include <netinet/udp.h>
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#include "core_time.h"
|
||||
#include "core_list.h"
|
||||
|
||||
#if HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
@ -157,6 +161,11 @@ CORE_DECLARE(status_t) core_sortaddrinfo(c_sockaddr_t **sa_list, int family);
|
|||
core_inet_ntop(__aDDR, buf, CORE_ADDRSTRLEN)
|
||||
#define CORE_PORT(__aDDR) \
|
||||
ntohs((__aDDR)->c_sa_port)
|
||||
|
||||
#define INET_NTOP(src, dst) \
|
||||
inet_ntop(AF_INET,(void *)(c_uintptr_t)(src),(dst),INET_ADDRSTRLEN)
|
||||
#define INET6_NTOP(src, dst) \
|
||||
inet_ntop(AF_INET6,(void *)(src),(dst),INET6_ADDRSTRLEN)
|
||||
CORE_DECLARE(const char *)core_inet_ntop(void *addr, char *buf, int buflen);
|
||||
CORE_DECLARE(status_t) core_inet_pton(int family, const char *src, void *addr);
|
||||
|
||||
|
|
|
@ -198,8 +198,9 @@ status_t sock_bind(sock_id id, c_sockaddr_t *addr)
|
|||
|
||||
if (bind(sock->fd, &addr->sa, addrlen) != 0)
|
||||
{
|
||||
d_error("socket bind [%s]:%d failed(%d:%s)",
|
||||
CORE_ADDR(addr, buf), CORE_PORT(addr), errno, strerror(errno));
|
||||
d_error("socket bind(%d) [%s]:%d failed(%d:%s)",
|
||||
addr->c_sa_family, CORE_ADDR(addr, buf), CORE_PORT(addr),
|
||||
errno, strerror(errno));
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ extern "C" {
|
|||
#define S6A_AVP_CODE_CONTEXT_IDENTIFIER (1423)
|
||||
#define S6A_AVP_CODE_ALL_APN_CONFIG_INC_IND (1428)
|
||||
#define S6A_AVP_CODE_APN_CONFIGURATION (1430)
|
||||
#define S6A_AVP_CODE_MIP_HOME_AGENT_ADDRESS (334)
|
||||
|
||||
#define S6A_RAT_TYPE_WLAN 0
|
||||
#define S6A_RAT_TYPE_VIRTUAL 1
|
||||
|
|
|
@ -183,7 +183,45 @@ c_int16_t gtp_build_tft(
|
|||
sizeof(target.pf[i].component[j].ipv4.mask));
|
||||
size += sizeof(target.pf[i].component[j].ipv4.mask);
|
||||
break;
|
||||
case GTP_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE:
|
||||
case GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE:
|
||||
d_assert(size +
|
||||
sizeof(target.pf[i].component[j].ipv6.addr)
|
||||
<= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size,
|
||||
&target.pf[i].component[j].ipv6.addr,
|
||||
sizeof(target.pf[i].component[j].ipv6.addr));
|
||||
size += sizeof(target.pf[i].component[j].ipv6.addr);
|
||||
|
||||
d_assert(size +
|
||||
sizeof(target.pf[i].component[j].ipv6.prefixlen)
|
||||
<= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size,
|
||||
&target.pf[i].component[j].ipv6.prefixlen,
|
||||
sizeof(target.pf[i].component[j].ipv6.prefixlen));
|
||||
size += sizeof(target.pf[i].component[j].ipv6.prefixlen);
|
||||
break;
|
||||
case GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE:
|
||||
d_assert(size +
|
||||
sizeof(target.pf[i].component[j].ipv6_mask.addr)
|
||||
<= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size,
|
||||
&target.pf[i].component[j].ipv6_mask.addr,
|
||||
sizeof(target.pf[i].component[j].ipv6_mask.addr));
|
||||
size += sizeof(target.pf[i].component[j].ipv6_mask.addr);
|
||||
|
||||
d_assert(size +
|
||||
sizeof(target.pf[i].component[j].ipv6_mask.mask)
|
||||
<= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size,
|
||||
&target.pf[i].component[j].ipv6_mask.mask,
|
||||
sizeof(target.pf[i].component[j].ipv6_mask.mask));
|
||||
size += sizeof(target.pf[i].component[j].ipv6_mask.mask);
|
||||
break;
|
||||
case GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE:
|
||||
case GTP_PACKET_FILTER_SINGLE_REMOTE_PORT_TYPE:
|
||||
d_assert(size +
|
||||
|
|
|
@ -224,6 +224,7 @@ ED3(c_uint8_t code:3;,
|
|||
#define GTP_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE 17
|
||||
#define GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE 32
|
||||
#define GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE 33
|
||||
#define GTP_PACKET_FILTER_IPV6_LOCAL_ADDRESS_TYPE 34
|
||||
#define GTP_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE 35
|
||||
#define GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE 64
|
||||
#define GTP_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE 65
|
||||
|
@ -240,6 +241,14 @@ ED3(c_uint8_t code:3;,
|
|||
c_uint32_t addr;
|
||||
c_uint32_t mask;
|
||||
} ipv4;
|
||||
struct {
|
||||
c_uint32_t addr[4];
|
||||
c_uint8_t prefixlen;
|
||||
} ipv6;
|
||||
struct {
|
||||
c_uint32_t addr[4];
|
||||
c_uint32_t mask[4];
|
||||
} ipv6_mask;
|
||||
struct {
|
||||
c_uint16_t low;
|
||||
c_uint16_t high;
|
||||
|
|
|
@ -1152,10 +1152,24 @@ ED3(c_uint8_t type:4;,
|
|||
|
||||
/* 9.9.4.9 PDN address
|
||||
* M LV 6-14 */
|
||||
#define NAS_PDN_ADDRESS_IPV4_LEN 5
|
||||
#define NAS_PDN_ADDRESS_IPV6_LEN 9
|
||||
#define NAS_PDN_ADDRESS_IPV4V6_LEN 13
|
||||
typedef struct _nas_pdn_address_t {
|
||||
c_uint8_t length;
|
||||
paa_t paa;
|
||||
} nas_pdn_address_t;
|
||||
ED2(c_uint8_t reserved:5;,
|
||||
c_uint8_t pdn_type:3;)
|
||||
union {
|
||||
c_uint32_t addr;
|
||||
struct {
|
||||
c_uint8_t addr6[IPV6_LEN>>1]; /* Interface Identifer Only */
|
||||
};
|
||||
struct {
|
||||
c_uint8_t addr6[IPV6_LEN>>1]; /* Interface Identifer Only */
|
||||
c_uint32_t addr;
|
||||
} both;
|
||||
};
|
||||
} __attribute__ ((packed)) nas_pdn_address_t;
|
||||
|
||||
/* 9.9.4.11 Protocol configuration options
|
||||
* See subclause 10.5.6.3 in 3GPP TS 24.008 [13].
|
||||
|
@ -1197,9 +1211,9 @@ ED3(c_uint8_t spare:3;, /* allowed in A/Gb mode or Iu mode */
|
|||
#define NAS_PDN_CONNECTIVITY_PDN_TYPE_NON_IP 5
|
||||
typedef struct _nas_request_type_t {
|
||||
ED4(c_uint8_t spare1:1;,
|
||||
c_uint8_t request_type:3;,
|
||||
c_uint8_t pdn_type:3;,
|
||||
c_uint8_t spare2:1;,
|
||||
c_uint8_t pdn_type:3;)
|
||||
c_uint8_t request_type:3;)
|
||||
} __attribute__ ((packed)) nas_request_type_t;
|
||||
|
||||
/* 9.9.4.15 Traffic flow aggregate description
|
||||
|
|
|
@ -245,6 +245,16 @@ status_t context_parse_config()
|
|||
self.parameter.prefer_ipv4 =
|
||||
yaml_iter_bool(¶meter_iter);
|
||||
}
|
||||
else if (!strcmp(parameter_key, "multicast"))
|
||||
{
|
||||
self.parameter.multicast =
|
||||
yaml_iter_bool(¶meter_iter);
|
||||
}
|
||||
else if (!strcmp(parameter_key, "no_slaac"))
|
||||
{
|
||||
self.parameter.no_slaac =
|
||||
yaml_iter_bool(¶meter_iter);
|
||||
}
|
||||
else
|
||||
d_warn("unknown key `%s`", parameter_key);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,8 @@ typedef struct _context_t {
|
|||
int no_ipv4;
|
||||
int no_ipv6;
|
||||
int prefer_ipv4;
|
||||
int multicast;
|
||||
int no_slaac;
|
||||
} parameter;
|
||||
|
||||
} context_t;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "core_debug.h"
|
||||
#include "core_lib.h"
|
||||
#include "core_network.h"
|
||||
|
||||
#include <mongoc.h>
|
||||
#include <yaml.h>
|
||||
|
@ -566,12 +567,32 @@ status_t hss_db_subscription_data(
|
|||
{
|
||||
const char *child3_key =
|
||||
bson_iter_key(&child3_iter);
|
||||
if (!strcmp(child3_key, "ipv4") &&
|
||||
if (!strcmp(child3_key, "addr") &&
|
||||
BSON_ITER_HOLDS_UTF8(&child3_iter))
|
||||
{
|
||||
utf8 = (char *)bson_iter_utf8(
|
||||
&child3_iter, &length);
|
||||
pdn->pgw.ipv4_addr = inet_addr(utf8);
|
||||
ipsubnet_t ipsub;
|
||||
const char *v =
|
||||
bson_iter_utf8(&child3_iter, &length);
|
||||
rv = core_ipsubnet(&ipsub, v, NULL);
|
||||
if (rv == CORE_OK)
|
||||
{
|
||||
pdn->pgw_ip.ipv4 = 1;
|
||||
pdn->pgw_ip.both.addr = ipsub.sub[0];
|
||||
}
|
||||
}
|
||||
else if (!strcmp(child3_key, "addr6") &&
|
||||
BSON_ITER_HOLDS_UTF8(&child3_iter))
|
||||
{
|
||||
ipsubnet_t ipsub;
|
||||
const char *v =
|
||||
bson_iter_utf8(&child3_iter, &length);
|
||||
rv = core_ipsubnet(&ipsub, v, NULL);
|
||||
if (rv == CORE_OK)
|
||||
{
|
||||
pdn->pgw_ip.ipv6 = 1;
|
||||
memcpy(pdn->pgw_ip.both.addr6,
|
||||
ipsub.sub, sizeof(ipsub.sub));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "core_debug.h"
|
||||
#include "core_lib.h"
|
||||
#include "core_sha2.h"
|
||||
#include "core_network.h"
|
||||
|
||||
#include "fd_lib.h"
|
||||
#include "s6a_dict.h"
|
||||
|
@ -205,6 +206,7 @@ static int hss_s6a_ulr_cb( struct msg **msg, struct avp *avp,
|
|||
c_uint32_t result_code = 0;
|
||||
s6a_subscription_data_t subscription_data;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
|
||||
d_assert(msg, return EINVAL,);
|
||||
|
||||
|
@ -412,18 +414,35 @@ static int hss_s6a_ulr_cb( struct msg **msg, struct avp *avp,
|
|||
MSG_BRW_LAST_CHILD, eps_subscribed_qos_profile) );
|
||||
|
||||
/* Set MIP6-Agent-Info */
|
||||
if (pdn->pgw.ipv4_addr)
|
||||
if (pdn->pgw_ip.ipv4 || pdn->pgw_ip.ipv6)
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new(fd_mip6_agent_info, 0,
|
||||
&mip6_agent_info) );
|
||||
CHECK_FCT( fd_msg_avp_new(fd_mip_home_agent_address, 0,
|
||||
&mip_home_agent_address) );
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = pdn->pgw.ipv4_addr;
|
||||
CHECK_FCT( fd_msg_avp_value_encode (
|
||||
&sin, mip_home_agent_address ) );
|
||||
CHECK_FCT( fd_msg_avp_add(mip6_agent_info,
|
||||
|
||||
if (pdn->pgw_ip.ipv4)
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new(fd_mip_home_agent_address, 0,
|
||||
&mip_home_agent_address) );
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = pdn->pgw_ip.both.addr;
|
||||
CHECK_FCT( fd_msg_avp_value_encode (
|
||||
&sin, mip_home_agent_address ) );
|
||||
CHECK_FCT( fd_msg_avp_add(mip6_agent_info,
|
||||
MSG_BRW_LAST_CHILD, mip_home_agent_address) );
|
||||
}
|
||||
|
||||
if (pdn->pgw_ip.ipv6)
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new(fd_mip_home_agent_address, 0,
|
||||
&mip_home_agent_address) );
|
||||
sin6.sin6_family = AF_INET6;
|
||||
memcpy(sin6.sin6_addr.s6_addr, pdn->pgw_ip.both.addr6,
|
||||
sizeof pdn->pgw_ip.both.addr6);
|
||||
CHECK_FCT( fd_msg_avp_value_encode (
|
||||
&sin6, mip_home_agent_address ) );
|
||||
CHECK_FCT( fd_msg_avp_add(mip6_agent_info,
|
||||
MSG_BRW_LAST_CHILD, mip_home_agent_address) );
|
||||
}
|
||||
|
||||
CHECK_FCT( fd_msg_avp_add(apn_configuration,
|
||||
MSG_BRW_LAST_CHILD, mip6_agent_info) );
|
||||
|
|
|
@ -132,8 +132,27 @@ status_t esm_build_activate_default_bearer_context_request(
|
|||
core_cpystrn(access_point_name->apn, pdn->apn,
|
||||
c_min(access_point_name->length, MAX_APN_LEN) + 1);
|
||||
|
||||
pdn_address->length = PAA_IPV4_LEN;
|
||||
memcpy(&pdn_address->paa, &pdn->paa, pdn_address->length);
|
||||
pdn_address->pdn_type = pdn->paa.pdn_type;
|
||||
if (pdn_address->pdn_type == GTP_PDN_TYPE_IPV4)
|
||||
{
|
||||
pdn_address->addr = pdn->paa.addr;
|
||||
pdn_address->length = NAS_PDN_ADDRESS_IPV4_LEN;
|
||||
}
|
||||
else if (pdn_address->pdn_type == GTP_PDN_TYPE_IPV6)
|
||||
{
|
||||
memcpy(pdn_address->addr6, pdn->paa.addr6+(IPV6_LEN>>1), IPV6_LEN>>1);
|
||||
pdn_address->length = NAS_PDN_ADDRESS_IPV6_LEN;
|
||||
}
|
||||
else if (pdn_address->pdn_type == GTP_PDN_TYPE_IPV4V6)
|
||||
{
|
||||
pdn_address->both.addr = pdn->paa.both.addr;
|
||||
memcpy(pdn_address->both.addr6,
|
||||
pdn->paa.both.addr6+(IPV6_LEN>>1), IPV6_LEN>>1);
|
||||
pdn_address->length = NAS_PDN_ADDRESS_IPV4V6_LEN;
|
||||
}
|
||||
else
|
||||
d_assert(0, return CORE_ERROR,
|
||||
"Invalid PDN_TYPE(%d)", pdn->paa.pdn_type);
|
||||
|
||||
if (pdn->ambr.downlink || pdn->ambr.uplink)
|
||||
{
|
||||
|
|
|
@ -18,17 +18,22 @@ status_t esm_handle_pdn_connectivity_request(mme_bearer_t *bearer,
|
|||
mme_sess_t *sess = NULL;
|
||||
c_uint8_t security_protected_required = 0;
|
||||
|
||||
d_assert(bearer, return CORE_ERROR, "Null param");
|
||||
d_assert(bearer, return CORE_ERROR,);
|
||||
sess = bearer->sess;
|
||||
d_assert(sess, return CORE_ERROR, "Null param");
|
||||
d_assert(sess, return CORE_ERROR,);
|
||||
mme_ue = sess->mme_ue;
|
||||
d_assert(mme_ue, return CORE_ERROR, "Null param");
|
||||
d_assert(mme_ue, return CORE_ERROR,);
|
||||
|
||||
d_assert(pdn_connectivity_request, return CORE_ERROR,);
|
||||
|
||||
d_assert(MME_UE_HAVE_IMSI(mme_ue), return CORE_ERROR,
|
||||
"No IMSI in PDN_CPNNECTIVITY_REQUEST");
|
||||
d_assert(SECURITY_CONTEXT_IS_VALID(mme_ue), return CORE_ERROR,
|
||||
"No Security Context in PDN_CPNNECTIVITY_REQUEST");
|
||||
|
||||
memcpy(&sess->request_type, &pdn_connectivity_request->request_type,
|
||||
sizeof(sess->request_type));
|
||||
|
||||
security_protected_required = 0;
|
||||
if (pdn_connectivity_request->presencemask &
|
||||
NAS_PDN_CONNECTIVITY_REQUEST_ESM_INFORMATION_TRANSFER_FLAG_PRESENT)
|
||||
|
|
|
@ -345,6 +345,9 @@ typedef struct _mme_sess_t {
|
|||
|
||||
c_uint8_t pti; /* Procedure Trasaction Identity */
|
||||
|
||||
/* PDN Connectivity Request */
|
||||
nas_request_type_t request_type;
|
||||
|
||||
/* mme_bearer_first(sess) : Default Bearer Context */
|
||||
list_t bearer_list;
|
||||
|
||||
|
|
|
@ -744,33 +744,45 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg)
|
|||
fd_mip6_agent_info, &avpch3), return );
|
||||
if (avpch3)
|
||||
{
|
||||
CHECK_FCT_DO( fd_avp_search_avp(avpch3,
|
||||
fd_mip_home_agent_address, &avpch4), return );
|
||||
if (avpch4)
|
||||
CHECK_FCT_DO( fd_msg_browse(avpch3,
|
||||
MSG_BRW_FIRST_CHILD, &avpch4, NULL), return );
|
||||
while(avpch4)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr_in *sin;
|
||||
CHECK_FCT_DO(
|
||||
fd_msg_avp_hdr(avpch4, &hdr), return );
|
||||
switch(hdr->avp_code)
|
||||
{
|
||||
case S6A_AVP_CODE_MIP_HOME_AGENT_ADDRESS:
|
||||
{
|
||||
c_sockaddr_t addr;
|
||||
|
||||
CHECK_FCT_DO(
|
||||
fd_msg_avp_hdr(avpch4, &hdr), return );
|
||||
CHECK_FCT_DO(
|
||||
fd_msg_avp_value_interpret(avpch4, &ss),
|
||||
return);
|
||||
sin = (struct sockaddr_in *)&ss;
|
||||
d_assert(sin, return, "Null param");
|
||||
if (sin->sin_family == AF_INET)
|
||||
{
|
||||
pdn->pgw.ipv4_addr = sin->sin_addr.s_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
d_error("Not implemented(%d)",
|
||||
sin->sin_family);
|
||||
CHECK_FCT_DO(
|
||||
fd_msg_avp_value_interpret(avpch4,
|
||||
&addr.sa), return );
|
||||
if (addr.c_sa_family == AF_INET)
|
||||
{
|
||||
pdn->pgw_ip.ipv4 = 1;
|
||||
pdn->pgw_ip.both.addr =
|
||||
addr.sin.sin_addr.s_addr;
|
||||
}
|
||||
else if (addr.c_sa_family == AF_INET6)
|
||||
{
|
||||
pdn->pgw_ip.ipv6 = 1;
|
||||
memcpy(pdn->pgw_ip.both.addr6,
|
||||
addr.sin6.sin6_addr.s6_addr,
|
||||
IPV6_LEN);
|
||||
}
|
||||
else
|
||||
error++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error++;
|
||||
break;
|
||||
}
|
||||
fd_msg_browse(avpch4, MSG_BRW_NEXT,
|
||||
&avpch4, NULL);
|
||||
}
|
||||
else
|
||||
error++;
|
||||
|
||||
}
|
||||
|
||||
CHECK_FCT_DO( fd_avp_search_avp(avpch2, s6a_ambr,
|
||||
|
|
|
@ -78,14 +78,34 @@ status_t mme_s11_build_create_session_request(
|
|||
|
||||
memset(&pgw_s5c_teid, 0, sizeof(gtp_f_teid_t));
|
||||
pgw_s5c_teid.interface_type = GTP_F_TEID_S5_S8_PGW_GTP_C;
|
||||
if (pdn->pgw.ipv4_addr)
|
||||
if (pdn->pgw_ip.ipv4 || pdn->pgw_ip.ipv6)
|
||||
{
|
||||
/* FIXME */
|
||||
pgw_s5c_teid.ipv4 = 1;
|
||||
pgw_s5c_teid.addr = pdn->pgw.ipv4_addr;
|
||||
pgw_s5c_teid.ipv4 = pdn->pgw_ip.ipv4;
|
||||
pgw_s5c_teid.ipv6 = pdn->pgw_ip.ipv6;
|
||||
if (pgw_s5c_teid.ipv4 && pgw_s5c_teid.ipv6)
|
||||
{
|
||||
pgw_s5c_teid.both.addr = pdn->pgw_ip.both.addr;
|
||||
memcpy(pgw_s5c_teid.both.addr6, pdn->pgw_ip.both.addr6,
|
||||
sizeof pdn->pgw_ip.both.addr6);
|
||||
req->pgw_s5_s8_address_for_control_plane_or_pmip.len =
|
||||
GTP_F_TEID_IPV4V6_LEN;
|
||||
}
|
||||
else if (pgw_s5c_teid.ipv4)
|
||||
{
|
||||
/* pdn->pgw_ip always uses both ip address memory */
|
||||
pgw_s5c_teid.addr = pdn->pgw_ip.both.addr;
|
||||
req->pgw_s5_s8_address_for_control_plane_or_pmip.len =
|
||||
GTP_F_TEID_IPV4_LEN;
|
||||
}
|
||||
else if (pgw_s5c_teid.ipv6)
|
||||
{
|
||||
/* pdn->pgw_ip always uses both ip address memory */
|
||||
memcpy(pgw_s5c_teid.addr6, pdn->pgw_ip.both.addr6,
|
||||
sizeof pdn->pgw_ip.both.addr6);
|
||||
req->pgw_s5_s8_address_for_control_plane_or_pmip.len =
|
||||
GTP_F_TEID_IPV6_LEN;
|
||||
}
|
||||
req->pgw_s5_s8_address_for_control_plane_or_pmip.presence = 1;
|
||||
req->pgw_s5_s8_address_for_control_plane_or_pmip.len =
|
||||
GTP_F_TEID_IPV4_LEN;
|
||||
req->pgw_s5_s8_address_for_control_plane_or_pmip.data =
|
||||
&pgw_s5c_teid;
|
||||
}
|
||||
|
@ -107,13 +127,42 @@ status_t mme_s11_build_create_session_request(
|
|||
req->selection_mode.u8 =
|
||||
GTP_SELECTION_MODE_MS_OR_NETWORK_PROVIDED_APN | 0xfc;
|
||||
|
||||
d_assert(sess->request_type.pdn_type ==
|
||||
NAS_PDN_CONNECTIVITY_PDN_TYPE_IPV4 ||
|
||||
sess->request_type.pdn_type ==
|
||||
NAS_PDN_CONNECTIVITY_PDN_TYPE_IPV6 ||
|
||||
sess->request_type.pdn_type ==
|
||||
NAS_PDN_CONNECTIVITY_PDN_TYPE_IPV4V6, return CORE_ERROR,
|
||||
"UE PDN Configuration Error(%d)", sess->request_type.pdn_type);
|
||||
if (pdn->pdn_type == HSS_PDN_TYPE_IPV4 ||
|
||||
pdn->pdn_type == HSS_PDN_TYPE_IPV6 ||
|
||||
pdn->pdn_type == HSS_PDN_TYPE_IPV4V6)
|
||||
{
|
||||
req->pdn_type.u8 = ((pdn->pdn_type + 1) & sess->request_type.pdn_type);
|
||||
d_assert(req->pdn_type.u8 != 0, return CORE_ERROR,
|
||||
"PDN Configuration Error:(%d, %d)",
|
||||
pdn->pdn_type, sess->request_type.pdn_type);
|
||||
}
|
||||
else if (pdn->pdn_type == HSS_PDN_TYPE_IPV4_OR_IPV6)
|
||||
{
|
||||
req->pdn_type.u8 = sess->request_type.pdn_type;
|
||||
}
|
||||
else
|
||||
d_assert(0, return CORE_ERROR,
|
||||
"HSS PDN Confiugration Error(%d)", pdn->pdn_type);
|
||||
req->pdn_type.presence = 1;
|
||||
req->pdn_type.u8 = GTP_PDN_TYPE_IPV4;
|
||||
|
||||
pdn->paa.pdn_type = GTP_PDN_TYPE_IPV4;
|
||||
req->pdn_address_allocation.presence = 1;
|
||||
pdn->paa.pdn_type = req->pdn_type.u8;
|
||||
req->pdn_address_allocation.data = &pdn->paa;
|
||||
req->pdn_address_allocation.len = PAA_IPV4_LEN;
|
||||
if (req->pdn_type.u8 == GTP_PDN_TYPE_IPV4)
|
||||
req->pdn_address_allocation.len = PAA_IPV4_LEN;
|
||||
else if (req->pdn_type.u8 == GTP_PDN_TYPE_IPV6)
|
||||
req->pdn_address_allocation.len = PAA_IPV6_LEN;
|
||||
else if (req->pdn_type.u8 == GTP_PDN_TYPE_IPV4V6)
|
||||
req->pdn_address_allocation.len = PAA_IPV4V6_LEN;
|
||||
else
|
||||
d_assert(0, return CORE_ERROR, "Not supported(%d)", req->pdn_type.u8);
|
||||
req->pdn_address_allocation.presence = 1;
|
||||
|
||||
req->maximum_apn_restriction.presence = 1;
|
||||
req->maximum_apn_restriction.u8 = GTP_APN_NO_RESTRICTION;
|
||||
|
|
|
@ -25,7 +25,6 @@ static pgw_context_t self;
|
|||
index_declare(pgw_sess_pool, pgw_sess_t, MAX_POOL_OF_SESS);
|
||||
index_declare(pgw_bearer_pool, pgw_bearer_t, MAX_POOL_OF_BEARER);
|
||||
|
||||
pool_declare(pgw_ip_pool_pool, pgw_ip_pool_t, MAX_POOL_OF_SESS);
|
||||
pool_declare(pgw_pf_pool, pgw_pf_t, MAX_POOL_OF_PF);
|
||||
|
||||
typedef struct _ue_pool_t {
|
||||
|
@ -36,7 +35,7 @@ typedef struct _ue_pool_t {
|
|||
} ue_pool_t;
|
||||
|
||||
#define INVALID_POOL_INDEX MAX_NUM_OF_UE_POOL
|
||||
static ue_pool_t ue_pool[MAX_NUM_OF_UE_POOL];
|
||||
static ue_pool_t ue_ip_pool[MAX_NUM_OF_UE_POOL];
|
||||
|
||||
static int context_initiaized = 0;
|
||||
|
||||
|
@ -61,11 +60,10 @@ status_t pgw_context_init()
|
|||
index_init(&pgw_sess_pool, MAX_POOL_OF_SESS);
|
||||
index_init(&pgw_bearer_pool, MAX_POOL_OF_BEARER);
|
||||
|
||||
pool_init(&pgw_ip_pool_pool, MAX_POOL_OF_SESS);
|
||||
pool_init(&pgw_pf_pool, MAX_POOL_OF_PF);
|
||||
|
||||
for (i = 0; i < MAX_NUM_OF_UE_POOL; i++)
|
||||
pool_init(&ue_pool[i], MAX_POOL_OF_UE);
|
||||
pool_init(&ue_ip_pool[i], MAX_POOL_OF_UE);
|
||||
|
||||
self.sess_hash = hash_make();
|
||||
|
||||
|
@ -86,40 +84,25 @@ status_t pgw_context_final()
|
|||
d_assert(self.sess_hash, , "Null param");
|
||||
hash_destroy(self.sess_hash);
|
||||
|
||||
if (index_size(&pgw_sess_pool) != pool_avail(&pgw_sess_pool))
|
||||
if (index_used(&pgw_sess_pool))
|
||||
d_warn("%d not freed in pgw_sess_pool[%d] in PGW-Context",
|
||||
index_size(&pgw_sess_pool) - pool_avail(&pgw_sess_pool),
|
||||
index_size(&pgw_sess_pool));
|
||||
index_used(&pgw_sess_pool), index_size(&pgw_sess_pool));
|
||||
d_trace(3, "%d not freed in pgw_sess_pool[%d] in PGW-Context\n",
|
||||
index_size(&pgw_sess_pool) - pool_avail(&pgw_sess_pool),
|
||||
index_size(&pgw_sess_pool));
|
||||
|
||||
if (index_size(&pgw_ip_pool_pool) != pool_avail(&pgw_ip_pool_pool))
|
||||
{
|
||||
d_warn("%d not freed in pgw_ip_pool[%d] in PGW-Context",
|
||||
index_size(&pgw_ip_pool_pool) - pool_avail(&pgw_ip_pool_pool),
|
||||
index_size(&pgw_ip_pool_pool));
|
||||
}
|
||||
d_trace(3, "%d not freed in pgw_ip_pool[%d] in PGW-Context\n",
|
||||
index_size(&pgw_ip_pool_pool) - pool_avail(&pgw_ip_pool_pool),
|
||||
index_size(&pgw_ip_pool_pool));
|
||||
index_used(&pgw_sess_pool), index_size(&pgw_sess_pool));
|
||||
|
||||
pool_final(&pgw_pf_pool);
|
||||
pool_final(&pgw_ip_pool_pool);
|
||||
|
||||
for (i = 0; i < MAX_NUM_OF_UE_POOL; i++)
|
||||
{
|
||||
if (index_size(&ue_pool[i]) != pool_avail(&ue_pool[i]))
|
||||
if (pool_used(&ue_ip_pool[i]))
|
||||
{
|
||||
d_warn("[%d] %d not freed in ue_pool[%d] in PGW-Context",
|
||||
i, index_size(&ue_pool[i]) - pool_avail(&ue_pool[i]),
|
||||
index_size(&ue_pool[i]));
|
||||
d_warn("[%d] %d not freed in ue_ip_pool[%d] in PGW-Context",
|
||||
i, pool_used(&ue_ip_pool[i]), index_size(&ue_ip_pool[i]));
|
||||
}
|
||||
d_trace(3, "[%d] %d not freed in ue_pool[%d] in PGW-Context\n",
|
||||
i, index_size(&ue_pool[i]) - pool_avail(&ue_pool[i]),
|
||||
index_size(&ue_pool[i]));
|
||||
d_trace(3, "[%d] %d not freed in ue_ip_pool[%d] in PGW-Context\n",
|
||||
i, pool_used(&ue_ip_pool[i]), index_size(&ue_ip_pool[i]));
|
||||
|
||||
pool_final(&ue_pool[i]);
|
||||
pool_final(&ue_ip_pool[i]);
|
||||
}
|
||||
|
||||
index_final(&pgw_bearer_pool);
|
||||
|
@ -176,7 +159,7 @@ static status_t pgw_context_validation()
|
|||
context_self()->config.path);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
if (self.dns.primary == 0)
|
||||
if (self.dns[0] == NULL && self.dns6[0] == NULL)
|
||||
{
|
||||
d_error("No pgw.dns in '%s'",
|
||||
context_self()->config.path);
|
||||
|
@ -609,16 +592,26 @@ status_t pgw_context_parse_config()
|
|||
v = yaml_iter_value(&dns_iter);
|
||||
if (v)
|
||||
{
|
||||
if (count == 0)
|
||||
ipsubnet_t ipsub;
|
||||
rv = core_ipsubnet(&ipsub, v, NULL);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
||||
if (ipsub.family == AF_INET)
|
||||
{
|
||||
self.dns.primary = inet_addr(v);
|
||||
if (self.dns[0] && self.dns[1])
|
||||
d_warn("Ignore DNS : %s", v);
|
||||
else if (self.dns[0]) self.dns[1] = v;
|
||||
else self.dns[0] = v;
|
||||
}
|
||||
else if (count == 1)
|
||||
else if (ipsub.family == AF_INET6)
|
||||
{
|
||||
self.dns.secondary = inet_addr(v);
|
||||
if (self.dns6[0] && self.dns6[1])
|
||||
d_warn("Ignore DNS : %s", v);
|
||||
else if (self.dns6[0]) self.dns6[1] = v;
|
||||
else self.dns6[0] = v;
|
||||
}
|
||||
else
|
||||
d_warn("Ignored %d DNS(%s)", count, v);
|
||||
d_warn("Ignore DNS : %s", v);
|
||||
}
|
||||
|
||||
count++;
|
||||
|
@ -626,43 +619,6 @@ status_t pgw_context_parse_config()
|
|||
yaml_iter_type(&dns_iter) ==
|
||||
YAML_SEQUENCE_NODE);
|
||||
}
|
||||
else if (!strcmp(pgw_key, "dns6"))
|
||||
{
|
||||
int count = 0;
|
||||
yaml_iter_t dns6_iter;
|
||||
yaml_iter_recurse(&pgw_iter, &dns6_iter);
|
||||
d_assert(yaml_iter_type(&dns6_iter) !=
|
||||
YAML_MAPPING_NODE, return CORE_ERROR,);
|
||||
|
||||
do
|
||||
{
|
||||
const char *v = NULL;
|
||||
|
||||
if (yaml_iter_type(&dns6_iter) ==
|
||||
YAML_SEQUENCE_NODE)
|
||||
{
|
||||
if (!yaml_iter_next(&dns6_iter))
|
||||
break;
|
||||
}
|
||||
|
||||
v = yaml_iter_value(&dns6_iter);
|
||||
if (v)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
}
|
||||
else if (count == 1)
|
||||
{
|
||||
}
|
||||
else
|
||||
d_warn("Ignored %d DNS(%s)", count, v);
|
||||
}
|
||||
|
||||
count++;
|
||||
} while(
|
||||
yaml_iter_type(&dns6_iter) ==
|
||||
YAML_SEQUENCE_NODE);
|
||||
}
|
||||
else
|
||||
d_warn("unknown key `%s`", pgw_key);
|
||||
|
||||
|
@ -715,6 +671,8 @@ status_t pgw_context_setup_trace_module()
|
|||
d_trace_level(&_tlv_msg, gtp);
|
||||
extern int _gtp_xact;
|
||||
d_trace_level(&_gtp_xact, gtp);
|
||||
extern int _pgw_ipfw;
|
||||
d_trace_level(&_pgw_ipfw, others);
|
||||
}
|
||||
|
||||
if (others)
|
||||
|
@ -744,7 +702,8 @@ static void *sess_hash_keygen(c_uint8_t *out, int *out_len,
|
|||
}
|
||||
|
||||
pgw_sess_t *pgw_sess_add(
|
||||
c_uint8_t *imsi, int imsi_len, c_int8_t *apn, c_uint8_t ebi)
|
||||
c_uint8_t *imsi, int imsi_len, c_int8_t *apn,
|
||||
c_uint8_t pdn_type, c_uint8_t ebi)
|
||||
{
|
||||
pgw_sess_t *sess = NULL;
|
||||
pgw_bearer_t *bearer = NULL;
|
||||
|
@ -771,9 +730,38 @@ pgw_sess_t *pgw_sess_add(
|
|||
"Can't add default bearer context");
|
||||
bearer->ebi = ebi;
|
||||
|
||||
sess->ue_ip = pgw_ue_ip_alloc(AF_INET, apn);
|
||||
d_assert(sess->ue_ip, pgw_sess_remove(sess); return NULL,
|
||||
"Can't add default bearer context");
|
||||
sess->pdn.paa.pdn_type = pdn_type;
|
||||
if (pdn_type == GTP_PDN_TYPE_IPV4)
|
||||
{
|
||||
sess->ipv4 = pgw_ue_ip_alloc(AF_INET, apn);
|
||||
d_assert(sess->ipv4, pgw_sess_remove(sess); return NULL,
|
||||
"Can't allocate IPv4 Pool");
|
||||
sess->pdn.paa.addr = sess->ipv4->addr[0];
|
||||
}
|
||||
else if (pdn_type == GTP_PDN_TYPE_IPV6)
|
||||
{
|
||||
sess->ipv6 = pgw_ue_ip_alloc(AF_INET6, apn);
|
||||
d_assert(sess->ipv6, pgw_sess_remove(sess); return NULL,
|
||||
"Can't allocate IPv6 Pool");
|
||||
|
||||
sess->pdn.paa.len = pgw_ue_ip_prefixlen(sess->ipv6);
|
||||
memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, IPV6_LEN);
|
||||
}
|
||||
else if (pdn_type == GTP_PDN_TYPE_IPV4V6)
|
||||
{
|
||||
sess->ipv4 = pgw_ue_ip_alloc(AF_INET, apn);
|
||||
d_assert(sess->ipv4, pgw_sess_remove(sess); return NULL,
|
||||
"Can't allocate IPv4 Pool");
|
||||
sess->ipv6 = pgw_ue_ip_alloc(AF_INET6, apn);
|
||||
d_assert(sess->ipv6, pgw_sess_remove(sess); return NULL,
|
||||
"Can't allocate IPv6 Pool");
|
||||
|
||||
sess->pdn.paa.both.addr = sess->ipv4->addr[0];
|
||||
sess->pdn.paa.both.len = pgw_ue_ip_prefixlen(sess->ipv6);
|
||||
memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, IPV6_LEN);
|
||||
}
|
||||
else
|
||||
d_assert(0, return NULL, "Unsupported PDN Type(%d)", pdn_type);
|
||||
|
||||
/* Generate Hash Key : IMSI + APN */
|
||||
sess_hash_keygen(sess->hash_keybuf, &sess->hash_keylen,
|
||||
|
@ -790,7 +778,10 @@ status_t pgw_sess_remove(pgw_sess_t *sess)
|
|||
|
||||
hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, NULL);
|
||||
|
||||
pgw_ue_ip_free(sess->ue_ip);
|
||||
if (sess->ipv4)
|
||||
pgw_ue_ip_free(sess->ipv4);
|
||||
if (sess->ipv6)
|
||||
pgw_ue_ip_free(sess->ipv6);
|
||||
|
||||
pgw_bearer_remove_all(sess);
|
||||
|
||||
|
@ -891,12 +882,18 @@ pgw_sess_t *pgw_sess_add_by_message(gtp_message_t *message)
|
|||
d_error("No EPS Bearer ID");
|
||||
return NULL;
|
||||
}
|
||||
if (req->pdn_type.presence == 0)
|
||||
{
|
||||
d_error("No PDN Type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
apn_parse(apn, req->access_point_name.data, req->access_point_name.len);
|
||||
sess = pgw_sess_find_by_imsi_apn(req->imsi.data, req->imsi.len, apn);
|
||||
if (!sess)
|
||||
{
|
||||
sess = pgw_sess_add(req->imsi.data, req->imsi.len, apn,
|
||||
req->pdn_type.u8,
|
||||
req->bearer_contexts_to_be_created.eps_bearer_id.u8);
|
||||
d_assert(sess, return NULL, "No Session Context");
|
||||
}
|
||||
|
@ -1059,202 +1056,6 @@ pgw_bearer_t* pgw_bearer_next(pgw_bearer_t *bearer)
|
|||
return list_next(bearer);
|
||||
}
|
||||
|
||||
pgw_bearer_t* pgw_bearer_find_by_packet(pkbuf_t *pkt)
|
||||
{
|
||||
pgw_bearer_t *default_bearer = NULL;
|
||||
pgw_bearer_t *bearer = NULL;
|
||||
hash_index_t *hi = NULL;
|
||||
pgw_sess_t *sess = NULL;
|
||||
struct ip *iph = NULL;
|
||||
#if 0 /* ADDR */
|
||||
char buf1[INET_ADDRSTRLEN];
|
||||
char buf2[INET_ADDRSTRLEN];
|
||||
#endif
|
||||
|
||||
d_assert(pkt, return NULL, "pkt is NULL");
|
||||
|
||||
iph = (struct ip *)pkt->payload;
|
||||
|
||||
/* FIXME : Only support IPV4 */
|
||||
if (iph->ip_v != 4) /* IPv4 */
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0 /* ADDR */
|
||||
d_trace(50, "Src(%s)-> Dst(%s), Protocol: %d\n",
|
||||
INET_NTOP(&iph->ip_src.s_addr,buf1),
|
||||
INET_NTOP(&iph->ip_dst.s_addr,buf2),
|
||||
iph->ip_p);
|
||||
#endif
|
||||
|
||||
/* TODO: Need to use the method of FAST matching algorithm and
|
||||
* implementation .
|
||||
* Until be ready, linear searching will be use to find the bearer.
|
||||
*/
|
||||
|
||||
for (hi = pgw_sess_first(); hi; hi = pgw_sess_next(hi))
|
||||
{
|
||||
sess = pgw_sess_this(hi);
|
||||
#if 0 /* ADDR */
|
||||
d_trace(50, "Dst(%s) in Pkt : PAA(%s) in PDN\n",
|
||||
INET_NTOP(&iph->ip_dst.s_addr,buf1),
|
||||
INET_NTOP(&sess->pdn.paa.ipv4_addr, buf2));
|
||||
#endif
|
||||
|
||||
if (iph->ip_dst.s_addr == sess->pdn.paa.addr)
|
||||
{
|
||||
/* Found */
|
||||
|
||||
/* Save the default bearer */
|
||||
default_bearer = pgw_default_bearer_in_sess(sess);
|
||||
d_assert(default_bearer, return NULL, "No default Bearer");
|
||||
|
||||
bearer = pgw_bearer_next(default_bearer);
|
||||
/* Find the bearer with matched */
|
||||
for (; bearer; bearer = pgw_bearer_next(bearer))
|
||||
{
|
||||
pgw_pf_t *pf = NULL;
|
||||
|
||||
for (pf = pgw_pf_first(bearer); pf; pf = pgw_pf_next(pf))
|
||||
{
|
||||
d_trace(50,"Dir:%d Proto:%d Src = 0x%x/0x%x (low:%d high:%d)"
|
||||
"Dst = 0x%x/0x%x (low:%d high:%d)\n",
|
||||
pf->direction,
|
||||
pf->rule.proto,
|
||||
ntohl(pf->rule.ipv4.local.addr),
|
||||
ntohl(pf->rule.ipv4.local.mask),
|
||||
pf->rule.port.local.low,
|
||||
pf->rule.port.local.high,
|
||||
ntohl(pf->rule.ipv4.remote.addr),
|
||||
ntohl(pf->rule.ipv4.remote.mask),
|
||||
pf->rule.port.remote.low,
|
||||
pf->rule.port.remote.high);
|
||||
|
||||
if (pf->direction != 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (((iph->ip_src.s_addr & pf->rule.ipv4.local.mask) ==
|
||||
pf->rule.ipv4.local.addr) &&
|
||||
((iph->ip_dst.s_addr & pf->rule.ipv4.remote.mask) ==
|
||||
pf->rule.ipv4.remote.addr))
|
||||
{
|
||||
/* Protocol match */
|
||||
if (pf->rule.proto == 0) /* IP */
|
||||
{
|
||||
/* No need to match port */
|
||||
break;
|
||||
}
|
||||
|
||||
if (pf->rule.proto == iph->ip_p)
|
||||
{
|
||||
if (pf->rule.proto == IPPROTO_TCP)
|
||||
{
|
||||
struct tcphdr *tcph =
|
||||
(struct tcphdr *)
|
||||
((char *)iph + (iph->ip_hl)*4);
|
||||
|
||||
/* Source port */
|
||||
if (pf->rule.port.local.low &&
|
||||
ntohs(tcph->th_sport) <
|
||||
pf->rule.port.local.low)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pf->rule.port.local.high &&
|
||||
ntohs(tcph->th_sport) >
|
||||
pf->rule.port.local.high)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Dst Port*/
|
||||
if (pf->rule.port.remote.low &&
|
||||
ntohs(tcph->th_dport) <
|
||||
pf->rule.port.remote.low)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pf->rule.port.remote.high &&
|
||||
ntohs(tcph->th_dport) >
|
||||
pf->rule.port.remote.high)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Matched */
|
||||
break;
|
||||
}
|
||||
else if (pf->rule.proto == IPPROTO_UDP)
|
||||
{
|
||||
struct udphdr *udph =
|
||||
(struct udphdr *)
|
||||
((char *)iph + (iph->ip_hl)*4);
|
||||
|
||||
/* Source port */
|
||||
if (pf->rule.port.local.low &&
|
||||
ntohs(udph->uh_sport) <
|
||||
pf->rule.port.local.low)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pf->rule.port.local.high &&
|
||||
ntohs(udph->uh_sport) >
|
||||
pf->rule.port.local.high)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Dst Port*/
|
||||
if (pf->rule.port.remote.low &&
|
||||
ntohs(udph->uh_dport) <
|
||||
pf->rule.port.remote.low)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pf->rule.port.remote.high &&
|
||||
ntohs(udph->uh_dport) >
|
||||
pf->rule.port.remote.high)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Matched */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No need to match port */
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (pf)
|
||||
{
|
||||
bearer = pf->bearer;
|
||||
d_trace(50,"Found bearer ebi = %d\n",bearer->ebi);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (bearer ? bearer : default_bearer);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pgw_pf_t *pgw_pf_add(pgw_bearer_t *bearer, c_uint32_t precedence)
|
||||
{
|
||||
pgw_pf_t *pf = NULL;
|
||||
|
@ -1335,9 +1136,9 @@ status_t pgw_ue_pool_generate()
|
|||
|
||||
for (i = 0; i < self.num_of_ue_pool; i++)
|
||||
{
|
||||
int pool_index = 0;
|
||||
int index = 0;
|
||||
ipsubnet_t ipaddr, ipsub;
|
||||
c_uint32_t bits;
|
||||
c_uint32_t prefixlen;
|
||||
c_uint32_t mask_count;
|
||||
c_uint32_t broadcast[4];
|
||||
|
||||
|
@ -1349,23 +1150,23 @@ status_t pgw_ue_pool_generate()
|
|||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
||||
d_assert(self.ue_pool[i].mask_or_numbits, return CORE_ERROR,);
|
||||
bits = atoi(self.ue_pool[i].mask_or_numbits);
|
||||
prefixlen = atoi(self.ue_pool[i].mask_or_numbits);
|
||||
if (ipsub.family == AF_INET)
|
||||
{
|
||||
if (bits == 32)
|
||||
if (prefixlen == 32)
|
||||
mask_count = 1;
|
||||
else if (bits < 32)
|
||||
mask_count = (0xffffffff >> bits) + 1;
|
||||
else if (prefixlen < 32)
|
||||
mask_count = (0xffffffff >> prefixlen) + 1;
|
||||
else
|
||||
d_assert(0, return CORE_ERROR,);
|
||||
}
|
||||
else if (ipsub.family == AF_INET6)
|
||||
{
|
||||
if (bits == 128)
|
||||
if (prefixlen == 128)
|
||||
mask_count = 1;
|
||||
else if (bits > 96 && bits < 128)
|
||||
mask_count = (0xffffffff >> (bits - 96)) + 1;
|
||||
else if (bits <= 96)
|
||||
else if (prefixlen > 96 && prefixlen < 128)
|
||||
mask_count = (0xffffffff >> (prefixlen - 96)) + 1;
|
||||
else if (prefixlen <= 96)
|
||||
mask_count = 0xffffffff;
|
||||
else
|
||||
d_assert(0, return CORE_ERROR,);
|
||||
|
@ -1380,13 +1181,13 @@ status_t pgw_ue_pool_generate()
|
|||
broadcast[j] = ipsub.sub[j] + ~ipsub.mask[j];
|
||||
}
|
||||
|
||||
for (j = 0; j < mask_count && pool_index < MAX_POOL_OF_SESS; j++)
|
||||
for (j = 0; j < mask_count && index < MAX_POOL_OF_SESS; j++)
|
||||
{
|
||||
pgw_ue_ip_t *ue_ip = NULL;
|
||||
int maxbytes = 0;
|
||||
int lastindex = 0;
|
||||
|
||||
ue_ip = &ue_pool[i].pool[pool_index];
|
||||
ue_ip = &ue_ip_pool[i].pool[index];
|
||||
d_assert(ue_ip, return CORE_ERROR,);
|
||||
memset(ue_ip, 0, sizeof *ue_ip);
|
||||
|
||||
|
@ -1412,9 +1213,10 @@ status_t pgw_ue_pool_generate()
|
|||
|
||||
/* Exclude TUN IP Address */
|
||||
if (memcmp(ue_ip->addr, ipaddr.sub, maxbytes) == 0) continue;
|
||||
|
||||
pool_index++;
|
||||
|
||||
index++;
|
||||
}
|
||||
ue_ip_pool[i].size = ue_ip_pool[i].avail = index;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
|
@ -1434,7 +1236,8 @@ static c_uint8_t find_ue_pool_index(int family, const char *apn)
|
|||
if (self.ue_pool[i].apn)
|
||||
{
|
||||
if (self.ue_pool[i].family == family &&
|
||||
strcmp(self.ue_pool[i].apn, apn) == 0)
|
||||
strcmp(self.ue_pool[i].apn, apn) == 0 &&
|
||||
pool_avail(&ue_ip_pool[i]))
|
||||
{
|
||||
pool_index = i;
|
||||
break;
|
||||
|
@ -1448,7 +1251,8 @@ static c_uint8_t find_ue_pool_index(int family, const char *apn)
|
|||
{
|
||||
if (self.ue_pool[i].apn == NULL)
|
||||
{
|
||||
if (self.ue_pool[i].family == family)
|
||||
if (self.ue_pool[i].family == family &&
|
||||
pool_avail(&ue_ip_pool[i]))
|
||||
{
|
||||
pool_index = i;
|
||||
break;
|
||||
|
@ -1476,7 +1280,7 @@ pgw_ue_ip_t *pgw_ue_ip_alloc(int family, const char *apn)
|
|||
pool_index = find_ue_pool_index(family, apn);
|
||||
d_assert(pool_index < MAX_NUM_OF_UE_POOL, return NULL,);
|
||||
|
||||
pool_alloc_node(&ue_pool[pool_index], &ue_ip);
|
||||
pool_alloc_node(&ue_ip_pool[pool_index], &ue_ip);
|
||||
d_assert(ue_ip, return NULL,);
|
||||
ue_ip->index = pool_index;
|
||||
|
||||
|
@ -1491,7 +1295,18 @@ status_t pgw_ue_ip_free(pgw_ue_ip_t *ue_ip)
|
|||
pool_index = ue_ip->index;
|
||||
|
||||
d_assert(pool_index < MAX_NUM_OF_UE_POOL, return CORE_ERROR,);
|
||||
pool_free_node(&ue_pool[pool_index], ue_ip);
|
||||
pool_free_node(&ue_ip_pool[pool_index], ue_ip);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
c_uint8_t pgw_ue_ip_prefixlen(pgw_ue_ip_t *ue_ip)
|
||||
{
|
||||
d_assert(ue_ip, return CORE_ERROR,);
|
||||
|
||||
c_uint8_t index = ue_ip->index;
|
||||
d_assert(index < MAX_NUM_OF_UE_POOL, return CORE_ERROR,);
|
||||
d_assert(pgw_self()->ue_pool[index].mask_or_numbits,
|
||||
return CORE_ERROR,);
|
||||
return atoi(pgw_self()->ue_pool[index].mask_or_numbits);
|
||||
}
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#include "gtp_types.h"
|
||||
#include "gtp_message.h"
|
||||
|
||||
#define MAX_NUM_OF_UE_POOL 16
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
@ -41,6 +39,7 @@ typedef struct _pgw_context_t {
|
|||
|
||||
sock_id tun_sock; /* PGW Tun Interace for UE */
|
||||
const char *tun_ifname; /* default : pgwtun */
|
||||
#define MAX_NUM_OF_UE_POOL 16
|
||||
struct {
|
||||
const char *ipstr; /* IP : "172.16.0.1", "cafe::1", ... */
|
||||
const char *mask_or_numbits; /* MASK : "16, 64, ... */
|
||||
|
@ -52,7 +51,11 @@ typedef struct _pgw_context_t {
|
|||
struct {
|
||||
c_uint32_t primary;
|
||||
c_uint32_t secondary;
|
||||
} dns;
|
||||
} old_dns;
|
||||
|
||||
#define MAX_NUM_OF_DNS 2
|
||||
const char *dns[2]; /* Primary/Secondanry */
|
||||
const char *dns6[2]; /* Primary/Secondanry */
|
||||
|
||||
list_t sgw_s5c_list; /* SGW GTPC Node List */
|
||||
list_t sgw_s5u_list; /* SGW GTPU Node List */
|
||||
|
@ -86,7 +89,8 @@ typedef struct _pgw_sess_t {
|
|||
|
||||
/* APN Configuration */
|
||||
pdn_t pdn;
|
||||
pgw_ue_ip_t* ue_ip;
|
||||
pgw_ue_ip_t* ipv4;
|
||||
pgw_ue_ip_t* ipv6;
|
||||
|
||||
/* User-Lication-Info */
|
||||
tai_t tai;
|
||||
|
@ -125,16 +129,21 @@ typedef struct _pgw_bearer_t {
|
|||
|
||||
typedef struct _pgw_rule_t {
|
||||
c_uint8_t proto;
|
||||
ED5(c_uint8_t ipv4_local:1;,
|
||||
c_uint8_t ipv4_remote:1;,
|
||||
c_uint8_t ipv6_local:1;,
|
||||
c_uint8_t ipv6_remote:1;,
|
||||
c_uint8_t reserved:4;)
|
||||
struct {
|
||||
struct {
|
||||
c_uint32_t addr;
|
||||
c_uint32_t mask;
|
||||
c_uint32_t addr[4];
|
||||
c_uint32_t mask[4];
|
||||
} local;
|
||||
struct {
|
||||
c_uint32_t addr;
|
||||
c_uint32_t mask;
|
||||
c_uint32_t addr[4];
|
||||
c_uint32_t mask[4];
|
||||
} remote;
|
||||
} ipv4;
|
||||
} ip;
|
||||
struct {
|
||||
struct {
|
||||
c_uint16_t low;
|
||||
|
@ -169,7 +178,8 @@ CORE_DECLARE(gtp_node_t *) pgw_sgw_add_by_message(gtp_message_t *message);
|
|||
CORE_DECLARE(pgw_sess_t *) pgw_sess_add_by_message(gtp_message_t *message);
|
||||
|
||||
CORE_DECLARE(pgw_sess_t*) pgw_sess_add(
|
||||
c_uint8_t *imsi, int imsi_len, c_int8_t *apn, c_uint8_t ebi);
|
||||
c_uint8_t *imsi, int imsi_len, c_int8_t *apn,
|
||||
c_uint8_t pdn_type, c_uint8_t ebi);
|
||||
CORE_DECLARE(status_t ) pgw_sess_remove(pgw_sess_t *sess);
|
||||
CORE_DECLARE(status_t ) pgw_sess_remove_all();
|
||||
CORE_DECLARE(pgw_sess_t*) pgw_sess_find(index_t index);
|
||||
|
@ -211,6 +221,7 @@ CORE_DECLARE(pgw_pf_t*) pgw_pf_next(pgw_pf_t *pf);
|
|||
CORE_DECLARE(status_t ) pgw_ue_pool_generate();
|
||||
CORE_DECLARE(pgw_ue_ip_t *) pgw_ue_ip_alloc(int family, const char *apn);
|
||||
CORE_DECLARE(status_t) pgw_ue_ip_free(pgw_ue_ip_t *ip);
|
||||
CORE_DECLARE(c_uint8_t) pgw_ue_ip_prefixlen(pgw_ue_ip_t *ue_ip);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ void pgw_gx_send_ccr(gtp_xact_t *xact, pgw_sess_t *sess,
|
|||
struct session *session = NULL;
|
||||
|
||||
d_assert(sess, return, "Null param");
|
||||
d_assert(sess->ue_ip, return, "Null param");
|
||||
d_assert(sess->ipv4 || sess->ipv6, return, "Null param");
|
||||
|
||||
/* Create the random value to store with the session */
|
||||
pool_alloc_node(&pgw_gx_sess_pool, &mi);
|
||||
|
@ -136,12 +136,28 @@ void pgw_gx_send_ccr(gtp_xact_t *xact, pgw_sess_t *sess,
|
|||
CHECK_FCT_DO( fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp), goto out );
|
||||
|
||||
/* Set Framed-IP-Address */
|
||||
CHECK_FCT_DO( fd_msg_avp_new(gx_framed_ip_address, 0, &avp),
|
||||
goto out );
|
||||
val.os.data = (c_uint8_t*)&sess->ue_ip->addr[0];
|
||||
val.os.len = sizeof(sess->ue_ip->addr[0]);
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue(avp, &val), goto out );
|
||||
CHECK_FCT_DO( fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp), goto out );
|
||||
if (sess->ipv4)
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new(gx_framed_ip_address, 0, &avp),
|
||||
goto out );
|
||||
val.os.data = (c_uint8_t*)&sess->ipv4->addr;
|
||||
val.os.len = 4;
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue(avp, &val), goto out );
|
||||
CHECK_FCT_DO( fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp),
|
||||
goto out );
|
||||
}
|
||||
|
||||
/* Set Framed-IP-Address-Prefix */
|
||||
if (sess->ipv6)
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new(gx_framed_ipv6_prefix, 0, &avp),
|
||||
goto out );
|
||||
val.os.data = (c_uint8_t*)&sess->pdn.paa;
|
||||
val.os.len = PAA_IPV6_LEN;
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue(avp, &val), goto out );
|
||||
CHECK_FCT_DO( fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp),
|
||||
goto out );
|
||||
}
|
||||
|
||||
/* Set IP-Can-Type */
|
||||
CHECK_FCT_DO( fd_msg_avp_new(gx_ip_can_type, 0, &avp),
|
||||
|
|
|
@ -6,10 +6,45 @@
|
|||
#include "gtp_node.h"
|
||||
#include "gtp_path.h"
|
||||
|
||||
#include "context.h"
|
||||
#include "pgw_context.h"
|
||||
#include "pgw_event.h"
|
||||
#include "pgw_gtp_path.h"
|
||||
|
||||
static status_t pgw_gtp_send_to_bearer(pgw_bearer_t *bearer, pkbuf_t *sendbuf)
|
||||
{
|
||||
status_t rv;
|
||||
gtp_header_t *gtp_h = NULL;
|
||||
|
||||
/* Add GTP-U header */
|
||||
rv = pkbuf_header(sendbuf, GTPV1U_HEADER_LEN);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("pkbuf_header error");
|
||||
pkbuf_free(sendbuf);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
gtp_h = (gtp_header_t *)sendbuf->payload;
|
||||
/* Bits 8 7 6 5 4 3 2 1
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* |version |PT| 1| E| S|PN|
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* 0 0 1 1 0 0 0 0
|
||||
*/
|
||||
gtp_h->flags = 0x30;
|
||||
gtp_h->type = GTPU_MSGTYPE_GPDU;
|
||||
gtp_h->length = htons(sendbuf->len);
|
||||
gtp_h->teid = htonl(bearer->sgw_s5u_teid);
|
||||
|
||||
/* Send to SGW */
|
||||
d_trace(50, "Send S5U PDU (teid = 0x%x) to SGW\n",
|
||||
bearer->sgw_s5u_teid);
|
||||
rv = gtp_send(bearer->gnode, sendbuf);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int _gtpv1_tun_recv_cb(sock_id sock, void *data)
|
||||
{
|
||||
pkbuf_t *recvbuf = NULL;
|
||||
|
@ -36,37 +71,44 @@ static int _gtpv1_tun_recv_cb(sock_id sock, void *data)
|
|||
bearer = pgw_bearer_find_by_packet(recvbuf);
|
||||
if (bearer)
|
||||
{
|
||||
gtp_header_t *gtp_h = NULL;
|
||||
|
||||
/* Add GTP-U header */
|
||||
rv = pkbuf_header(recvbuf, GTPV1U_HEADER_LEN);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("pkbuf_header error");
|
||||
pkbuf_free(recvbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gtp_h = (gtp_header_t *)recvbuf->payload;
|
||||
/* Bits 8 7 6 5 4 3 2 1
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* |version |PT| 1| E| S|PN|
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* 0 0 1 1 0 0 0 0
|
||||
*/
|
||||
gtp_h->flags = 0x30;
|
||||
gtp_h->type = GTPU_MSGTYPE_GPDU;
|
||||
gtp_h->length = htons(n);
|
||||
gtp_h->teid = htonl(bearer->sgw_s5u_teid);
|
||||
|
||||
/* Send to SGW */
|
||||
d_trace(50, "Send S5U PDU (teid = 0x%x) to SGW\n",
|
||||
bearer->sgw_s5u_teid);
|
||||
rv = gtp_send(bearer->gnode, recvbuf);
|
||||
/* Unicast */
|
||||
rv = pgw_gtp_send_to_bearer(bearer, recvbuf);
|
||||
d_assert(rv == CORE_OK,, "pgw_gtp_send_to_bearer failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
d_trace(3, "Can not find bearer\n");
|
||||
if (context_self()->parameter.multicast)
|
||||
{
|
||||
struct ip *ip_h = NULL;
|
||||
struct ip6_hdr *ip6_h = NULL;
|
||||
|
||||
ip_h = (struct ip *)recvbuf->payload;
|
||||
if (ip_h->ip_v == 6)
|
||||
{
|
||||
ip6_h = (struct ip6_hdr *)recvbuf->payload;
|
||||
if (IN6_IS_ADDR_MULTICAST(&ip6_h->ip6_dst))
|
||||
{
|
||||
hash_index_t *hi = NULL;
|
||||
|
||||
/* IPv6 Multicast */
|
||||
for (hi = pgw_sess_first(); hi; hi = pgw_sess_next(hi))
|
||||
{
|
||||
pgw_sess_t *sess = pgw_sess_this(hi);
|
||||
d_assert(sess, return 0,);
|
||||
if (sess->ipv6)
|
||||
{
|
||||
/* PDN IPv6 is avaiable */
|
||||
pgw_bearer_t *bearer = pgw_default_bearer_in_sess(sess);
|
||||
d_assert(bearer, return 0,);
|
||||
|
||||
rv = pgw_gtp_send_to_bearer(bearer, recvbuf);
|
||||
d_assert(rv == CORE_OK,,
|
||||
"pgw_gtp_send_to_bearer failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pkbuf_free(recvbuf);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#define TRACE_MODULE _pgw_ipfw
|
||||
|
||||
#include "core_network.h"
|
||||
#include "pgw_ipfw.h"
|
||||
|
||||
#include "ipfw2.h"
|
||||
|
@ -78,23 +79,48 @@ status_t pgw_compile_packet_filter(pgw_rule_t *pgw_rule, c_int8_t *description)
|
|||
case O_IP_SRC_MASK:
|
||||
{
|
||||
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
|
||||
pgw_rule->ipv4.local.addr = a[0];
|
||||
pgw_rule->ipv4_local = 1;
|
||||
pgw_rule->ip.local.addr[0] = a[0];
|
||||
if (cmd->opcode == O_IP_SRC_MASK)
|
||||
pgw_rule->ipv4.local.mask = a[1];
|
||||
pgw_rule->ip.local.mask[0] = a[1];
|
||||
else
|
||||
pgw_rule->ipv4.local.mask = 0xffffffff;
|
||||
|
||||
pgw_rule->ip.local.mask[0] = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
case O_IP_DST:
|
||||
case O_IP_DST_MASK:
|
||||
{
|
||||
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
|
||||
pgw_rule->ipv4.remote.addr = a[0];
|
||||
pgw_rule->ipv4_remote = 1;
|
||||
pgw_rule->ip.remote.addr[0] = a[0];
|
||||
if (cmd->opcode == O_IP_DST_MASK)
|
||||
pgw_rule->ipv4.remote.mask = a[1];
|
||||
pgw_rule->ip.remote.mask[0] = a[1];
|
||||
else
|
||||
pgw_rule->ipv4.remote.mask = 0xffffffff;
|
||||
pgw_rule->ip.remote.mask[0] = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
case O_IP6_SRC:
|
||||
case O_IP6_SRC_MASK:
|
||||
{
|
||||
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
|
||||
pgw_rule->ipv6_local = 1;
|
||||
memcpy(pgw_rule->ip.local.addr, a, IPV6_LEN);
|
||||
if (cmd->opcode == O_IP6_SRC_MASK)
|
||||
memcpy(pgw_rule->ip.local.mask, a+4, IPV6_LEN);
|
||||
else
|
||||
n2mask((struct in6_addr *)pgw_rule->ip.local.mask, 128);
|
||||
break;
|
||||
}
|
||||
case O_IP6_DST:
|
||||
case O_IP6_DST_MASK:
|
||||
{
|
||||
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
|
||||
pgw_rule->ipv6_remote = 1;
|
||||
memcpy(pgw_rule->ip.remote.addr, a, IPV6_LEN);
|
||||
if (cmd->opcode == O_IP6_DST_MASK)
|
||||
memcpy(pgw_rule->ip.remote.mask, a+4, IPV6_LEN);
|
||||
else
|
||||
n2mask((struct in6_addr *)pgw_rule->ip.remote.mask, 128);
|
||||
break;
|
||||
}
|
||||
case O_IP_SRCPORT:
|
||||
|
@ -123,3 +149,331 @@ status_t pgw_compile_packet_filter(pgw_rule_t *pgw_rule, c_int8_t *description)
|
|||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
static status_t decode_ipv6_header(
|
||||
struct ip6_hdr *ip6_h, c_uint8_t *proto, c_uint16_t *hlen)
|
||||
{
|
||||
int done = 0;
|
||||
c_uint8_t *p, *jp, *endp;
|
||||
c_uint8_t nxt; /* Next Header */
|
||||
|
||||
d_assert(ip6_h, return CORE_ERROR,);
|
||||
d_assert(proto, return CORE_ERROR,);
|
||||
d_assert(hlen, return CORE_ERROR,);
|
||||
|
||||
nxt = ip6_h->ip6_nxt;
|
||||
p = (c_uint8_t *)ip6_h + sizeof(*ip6_h);
|
||||
endp = p + ntohs(ip6_h->ip6_plen);
|
||||
|
||||
jp = p + sizeof(struct ip6_hbh);
|
||||
while(p == endp) /* Jumbo Frame */
|
||||
{
|
||||
c_uint32_t jp_len = 0;
|
||||
struct ip6_opt_jumbo *jumbo = NULL;
|
||||
|
||||
d_assert(nxt == 0, return CORE_ERROR,);
|
||||
|
||||
jumbo = (struct ip6_opt_jumbo *)jp;
|
||||
memcpy(&jp_len, jumbo->ip6oj_jumbo_len, sizeof(jp_len));
|
||||
jp_len = ntohl(jp_len);
|
||||
switch(jumbo->ip6oj_type)
|
||||
{
|
||||
case IP6OPT_JUMBO:
|
||||
endp = p + jp_len;
|
||||
break;
|
||||
case 0:
|
||||
jp++;
|
||||
break;
|
||||
default:
|
||||
jp += (sizeof(struct ip6_opt) + jp_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while(p < endp)
|
||||
{
|
||||
struct ip6_ext *ext = (struct ip6_ext *)p;
|
||||
switch(nxt)
|
||||
{
|
||||
case IPPROTO_HOPOPTS:
|
||||
case IPPROTO_ROUTING:
|
||||
case IPPROTO_DSTOPTS:
|
||||
case 135: /* mobility */
|
||||
case 139: /* host identity, experimental */
|
||||
case 140: /* shim6 */
|
||||
case 253: /* testing, experimental */
|
||||
case 254: /* testing, experimental */
|
||||
p += ((ext->ip6e_len << 3) + 8);
|
||||
break;
|
||||
case IPPROTO_FRAGMENT:
|
||||
p += sizeof(struct ip6_frag);
|
||||
break;
|
||||
case IPPROTO_AH:
|
||||
p += ((ext->ip6e_len + 2) << 2);
|
||||
break;
|
||||
default: /* Upper Layer */
|
||||
done = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
if (done)
|
||||
break;
|
||||
|
||||
nxt = ext->ip6e_nxt;
|
||||
}
|
||||
|
||||
*proto = nxt;
|
||||
*hlen = p - (c_uint8_t *)ip6_h;
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
pgw_bearer_t*pgw_bearer_find_by_packet(pkbuf_t *pkt)
|
||||
{
|
||||
hash_index_t *hi = NULL;
|
||||
struct ip *ip_h = NULL;
|
||||
struct ip6_hdr *ip6_h = NULL;
|
||||
c_uint32_t *src_addr = NULL;
|
||||
c_uint32_t *dst_addr = NULL;
|
||||
int addr_len = 0;
|
||||
c_uint8_t proto = 0;
|
||||
c_uint16_t ip_hlen = 0;
|
||||
char buf[CORE_ADDRSTRLEN];
|
||||
|
||||
d_assert(pkt, return NULL, "pkt is NULL");
|
||||
|
||||
ip_h = (struct ip *)pkt->payload;
|
||||
if (ip_h->ip_v == 4)
|
||||
{
|
||||
ip_h = (struct ip *)pkt->payload;
|
||||
ip6_h = NULL;
|
||||
|
||||
proto = ip_h->ip_p;
|
||||
ip_hlen = (ip_h->ip_hl)*4;
|
||||
|
||||
src_addr = &ip_h->ip_src.s_addr;
|
||||
dst_addr = &ip_h->ip_dst.s_addr;
|
||||
addr_len = 4;
|
||||
}
|
||||
else if (ip_h->ip_v == 6)
|
||||
{
|
||||
ip_h = NULL;
|
||||
ip6_h = (struct ip6_hdr *)pkt->payload;
|
||||
|
||||
decode_ipv6_header(ip6_h, &proto, &ip_hlen);
|
||||
|
||||
src_addr = (c_uint32_t *)ip6_h->ip6_src.s6_addr;
|
||||
dst_addr = (c_uint32_t *)ip6_h->ip6_dst.s6_addr;
|
||||
addr_len = 16;
|
||||
|
||||
}
|
||||
else
|
||||
d_error("Invalid IP version = %d\n", ip_h->ip_v);
|
||||
|
||||
d_trace(50, "PROTO:%d SRC:%08x %08x %08x %08x\n",
|
||||
proto, ntohl(src_addr[0]), ntohl(src_addr[1]),
|
||||
ntohl(src_addr[2]), ntohl(src_addr[3]));
|
||||
d_trace(50, "HLEN:%d DST:%08x %08x %08x %08x\n",
|
||||
ip_hlen, ntohl(dst_addr[0]), ntohl(dst_addr[1]),
|
||||
ntohl(dst_addr[2]), ntohl(dst_addr[3]));
|
||||
|
||||
|
||||
/* TODO: Need to use the method of FAST matching algorithm and
|
||||
* implementation .
|
||||
* Until be ready, linear searching will be use to find the bearer.
|
||||
*/
|
||||
|
||||
for (hi = pgw_sess_first(); hi; hi = pgw_sess_next(hi))
|
||||
{
|
||||
pgw_sess_t *sess = pgw_sess_this(hi);
|
||||
d_assert(sess, return NULL,);
|
||||
|
||||
if (sess->ipv4)
|
||||
d_trace(50, "PAA IPv4:%s\n", INET_NTOP(&sess->ipv4->addr, buf));
|
||||
if (sess->ipv6)
|
||||
d_trace(50, "PAA IPv6:%s\n", INET6_NTOP(&sess->ipv6->addr, buf));
|
||||
|
||||
if ((sess->ipv4 && memcmp(dst_addr, sess->ipv4->addr, addr_len) == 0) ||
|
||||
(sess->ipv6 && memcmp(dst_addr, sess->ipv6->addr, addr_len) == 0))
|
||||
{
|
||||
pgw_bearer_t *default_bearer = NULL;
|
||||
pgw_bearer_t *bearer = NULL;
|
||||
/* Found */
|
||||
|
||||
/* Save the default bearer */
|
||||
default_bearer = pgw_default_bearer_in_sess(sess);
|
||||
d_assert(default_bearer, return NULL, "No default Bearer");
|
||||
|
||||
bearer = pgw_bearer_next(default_bearer);
|
||||
/* Find the bearer with matched */
|
||||
for (; bearer; bearer = pgw_bearer_next(bearer))
|
||||
{
|
||||
pgw_pf_t *pf = NULL;
|
||||
|
||||
if (bearer->ebi == 0)
|
||||
{
|
||||
/* Create Bearer Response is not received */
|
||||
continue;
|
||||
}
|
||||
|
||||
for (pf = pgw_pf_first(bearer); pf; pf = pgw_pf_next(pf))
|
||||
{
|
||||
int k;
|
||||
c_uint32_t src_mask[4];
|
||||
c_uint32_t dst_mask[4];
|
||||
|
||||
d_trace(50, "DIR:%d PROTO:%d SRC:%d-%d DST:%d-%d\n",
|
||||
pf->direction, pf->rule.proto,
|
||||
pf->rule.port.local.low,
|
||||
pf->rule.port.local.high,
|
||||
pf->rule.port.remote.low,
|
||||
pf->rule.port.remote.high);
|
||||
d_trace(50, "SRC:%08x %08x %08x %08x/%08x %08x %08x %08x\n",
|
||||
ntohl(pf->rule.ip.local.addr[0]),
|
||||
ntohl(pf->rule.ip.local.addr[1]),
|
||||
ntohl(pf->rule.ip.local.addr[2]),
|
||||
ntohl(pf->rule.ip.local.addr[3]),
|
||||
ntohl(pf->rule.ip.local.mask[0]),
|
||||
ntohl(pf->rule.ip.local.mask[1]),
|
||||
ntohl(pf->rule.ip.local.mask[2]),
|
||||
ntohl(pf->rule.ip.local.mask[3]));
|
||||
d_trace(50, "DST:%08x %08x %08x %08x/%08x %08x %08x %08x\n",
|
||||
ntohl(pf->rule.ip.remote.addr[0]),
|
||||
ntohl(pf->rule.ip.remote.addr[1]),
|
||||
ntohl(pf->rule.ip.remote.addr[2]),
|
||||
ntohl(pf->rule.ip.remote.addr[3]),
|
||||
ntohl(pf->rule.ip.remote.mask[0]),
|
||||
ntohl(pf->rule.ip.remote.mask[1]),
|
||||
ntohl(pf->rule.ip.remote.mask[2]),
|
||||
ntohl(pf->rule.ip.remote.mask[3]));
|
||||
|
||||
if (pf->direction != 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
src_mask[k] = src_addr[k] & pf->rule.ip.local.mask[k];
|
||||
dst_mask[k] = dst_addr[k] & pf->rule.ip.remote.mask[k];
|
||||
}
|
||||
|
||||
if (memcmp(src_mask, pf->rule.ip.local.addr,
|
||||
addr_len) == 0 &&
|
||||
memcmp(dst_mask, pf->rule.ip.remote.addr,
|
||||
addr_len) == 0)
|
||||
{
|
||||
/* Protocol match */
|
||||
if (pf->rule.proto == 0) /* IP */
|
||||
{
|
||||
/* No need to match port */
|
||||
break;
|
||||
}
|
||||
|
||||
if (pf->rule.proto == proto)
|
||||
{
|
||||
if (pf->rule.proto == IPPROTO_TCP)
|
||||
{
|
||||
struct tcphdr *tcph =
|
||||
(struct tcphdr *)
|
||||
((char *)pkt->payload + ip_hlen);
|
||||
|
||||
/* Source port */
|
||||
if (pf->rule.port.local.low &&
|
||||
ntohs(tcph->th_sport) <
|
||||
pf->rule.port.local.low)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pf->rule.port.local.high &&
|
||||
ntohs(tcph->th_sport) >
|
||||
pf->rule.port.local.high)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Dst Port*/
|
||||
if (pf->rule.port.remote.low &&
|
||||
ntohs(tcph->th_dport) <
|
||||
pf->rule.port.remote.low)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pf->rule.port.remote.high &&
|
||||
ntohs(tcph->th_dport) >
|
||||
pf->rule.port.remote.high)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Matched */
|
||||
break;
|
||||
}
|
||||
else if (pf->rule.proto == IPPROTO_UDP)
|
||||
{
|
||||
struct udphdr *udph =
|
||||
(struct udphdr *)
|
||||
((char *)pkt->payload + ip_hlen);
|
||||
|
||||
/* Source port */
|
||||
if (pf->rule.port.local.low &&
|
||||
ntohs(udph->uh_sport) <
|
||||
pf->rule.port.local.low)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pf->rule.port.local.high &&
|
||||
ntohs(udph->uh_sport) >
|
||||
pf->rule.port.local.high)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Dst Port*/
|
||||
if (pf->rule.port.remote.low &&
|
||||
ntohs(udph->uh_dport) <
|
||||
pf->rule.port.remote.low)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pf->rule.port.remote.high &&
|
||||
ntohs(udph->uh_dport) >
|
||||
pf->rule.port.remote.high)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Matched */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No need to match port */
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (pf)
|
||||
{
|
||||
bearer = pf->bearer;
|
||||
d_trace(50,"FOUND Bearer EBI = %d\n", bearer->ebi);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (bearer ? bearer : default_bearer);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "gtp_message.h"
|
||||
#include "gx_message.h"
|
||||
|
||||
#include "ipfw2.h"
|
||||
|
||||
#include "pgw_context.h"
|
||||
|
||||
static c_int16_t pgw_pco_build(c_uint8_t *pco_buf, tlv_pco_t *tlv_pco);
|
||||
|
@ -59,13 +61,16 @@ status_t pgw_s5c_build_create_session_response(
|
|||
len = len;
|
||||
|
||||
/* PDN Address Allocation */
|
||||
d_assert(sess->ue_ip, return CORE_ERROR, "No IP Pool");
|
||||
sess->pdn.paa.pdn_type = GTP_PDN_TYPE_IPV4;
|
||||
sess->pdn.paa.addr = sess->ue_ip->addr[0];
|
||||
|
||||
rsp->pdn_address_allocation.presence = 1;
|
||||
rsp->pdn_address_allocation.data = &sess->pdn.paa;
|
||||
rsp->pdn_address_allocation.len = PAA_IPV4_LEN;
|
||||
if (sess->ipv4 && sess->ipv6)
|
||||
rsp->pdn_address_allocation.len = PAA_IPV4V6_LEN;
|
||||
else if (sess->ipv4)
|
||||
rsp->pdn_address_allocation.len = PAA_IPV4_LEN;
|
||||
else if (sess->ipv6)
|
||||
rsp->pdn_address_allocation.len = PAA_IPV6_LEN;
|
||||
else
|
||||
d_assert(0, return CORE_ERROR, "No IP Pool");
|
||||
rsp->pdn_address_allocation.presence = 1;
|
||||
|
||||
/* APN Restriction */
|
||||
rsp->apn_restriction.presence = 1;
|
||||
|
@ -245,24 +250,46 @@ status_t pgw_s5c_build_create_bearer_request(
|
|||
j++; len += 2;
|
||||
}
|
||||
|
||||
if (pf->rule.ipv4.local.addr)
|
||||
if (pf->rule.ipv4_local)
|
||||
{
|
||||
tft.pf[i].component[j].type =
|
||||
GTP_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE;
|
||||
tft.pf[i].component[j].ipv4.addr = pf->rule.ipv4.local.addr;
|
||||
tft.pf[i].component[j].ipv4.mask = pf->rule.ipv4.local.mask;
|
||||
tft.pf[i].component[j].ipv4.addr = pf->rule.ip.local.addr[0];
|
||||
tft.pf[i].component[j].ipv4.mask = pf->rule.ip.local.mask[0];
|
||||
j++; len += 9;
|
||||
}
|
||||
|
||||
if (pf->rule.ipv4.remote.addr)
|
||||
if (pf->rule.ipv4_remote)
|
||||
{
|
||||
tft.pf[i].component[j].type =
|
||||
GTP_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE;
|
||||
tft.pf[i].component[j].ipv4.addr = pf->rule.ipv4.remote.addr;
|
||||
tft.pf[i].component[j].ipv4.mask = pf->rule.ipv4.remote.mask;
|
||||
tft.pf[i].component[j].ipv4.addr = pf->rule.ip.remote.addr[0];
|
||||
tft.pf[i].component[j].ipv4.mask = pf->rule.ip.remote.mask[0];
|
||||
j++; len += 9;
|
||||
}
|
||||
|
||||
if (pf->rule.ipv6_local)
|
||||
{
|
||||
tft.pf[i].component[j].type =
|
||||
GTP_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE;
|
||||
memcpy(tft.pf[i].component[j].ipv6.addr, pf->rule.ip.local.addr,
|
||||
sizeof pf->rule.ip.local.addr);
|
||||
tft.pf[i].component[j].ipv6.prefixlen =
|
||||
contigmask((c_uint8_t *)pf->rule.ip.local.mask, 128);
|
||||
j++; len += 18;
|
||||
}
|
||||
|
||||
if (pf->rule.ipv6_remote)
|
||||
{
|
||||
tft.pf[i].component[j].type =
|
||||
GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE;
|
||||
memcpy(tft.pf[i].component[j].ipv6.addr, pf->rule.ip.remote.addr,
|
||||
sizeof pf->rule.ip.remote.addr);
|
||||
tft.pf[i].component[j].ipv6.prefixlen =
|
||||
contigmask((c_uint8_t *)pf->rule.ip.remote.mask, 128);
|
||||
j++; len += 18;
|
||||
}
|
||||
|
||||
if (pf->rule.port.local.low)
|
||||
{
|
||||
if (pf->rule.port.local.low == pf->rule.port.local.high)
|
||||
|
@ -322,8 +349,10 @@ status_t pgw_s5c_build_create_bearer_request(
|
|||
|
||||
static c_int16_t pgw_pco_build(c_uint8_t *pco_buf, tlv_pco_t *tlv_pco)
|
||||
{
|
||||
status_t rv;
|
||||
pco_t ue, pgw;
|
||||
pco_ipcp_t pco_ipcp;
|
||||
ipsubnet_t dns_primary, dns_secondary, dns6_primary, dns6_secondary;
|
||||
c_int8_t size = 0;
|
||||
int i = 0;
|
||||
|
||||
|
@ -365,14 +394,26 @@ static c_int16_t pgw_pco_build(c_uint8_t *pco_buf, tlv_pco_t *tlv_pco)
|
|||
pco_ipcp.len = htons(len);
|
||||
|
||||
/* Primary DNS Server IP Address */
|
||||
pco_ipcp.options[0].type = 129;
|
||||
pco_ipcp.options[0].len = 6;
|
||||
pco_ipcp.options[0].addr = pgw_self()->dns.primary;
|
||||
if (pgw_self()->dns[0])
|
||||
{
|
||||
rv = core_ipsubnet(
|
||||
&dns_primary, pgw_self()->dns[0], NULL);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
pco_ipcp.options[0].type = 129;
|
||||
pco_ipcp.options[0].len = 6;
|
||||
pco_ipcp.options[0].addr = dns_primary.sub[0];
|
||||
}
|
||||
|
||||
/* Secondary DNS Server IP Address */
|
||||
pco_ipcp.options[1].type = 131;
|
||||
pco_ipcp.options[1].len = 6;
|
||||
pco_ipcp.options[1].addr = pgw_self()->dns.secondary;
|
||||
if (pgw_self()->dns[1])
|
||||
{
|
||||
rv = core_ipsubnet(
|
||||
&dns_secondary, pgw_self()->dns[1], NULL);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
pco_ipcp.options[1].type = 131;
|
||||
pco_ipcp.options[1].len = 6;
|
||||
pco_ipcp.options[1].addr = dns_secondary.sub[0];
|
||||
}
|
||||
|
||||
pgw.ids[pgw.num_of_id].id = ue.ids[i].id;
|
||||
pgw.ids[pgw.num_of_id].len = len;
|
||||
|
@ -384,19 +425,59 @@ static c_int16_t pgw_pco_build(c_uint8_t *pco_buf, tlv_pco_t *tlv_pco)
|
|||
}
|
||||
case PCO_ID_DNS_SERVER_IPV4_ADDRESS_REQUEST:
|
||||
{
|
||||
pgw.ids[pgw.num_of_id].id = ue.ids[i].id;
|
||||
pgw.ids[pgw.num_of_id].len = 4;
|
||||
pgw.ids[pgw.num_of_id].data = &pgw_self()->dns.primary;
|
||||
pgw.num_of_id++;
|
||||
if (pgw_self()->dns[0])
|
||||
{
|
||||
rv = core_ipsubnet(
|
||||
&dns_primary, pgw_self()->dns[0], NULL);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
pgw.ids[pgw.num_of_id].id = ue.ids[i].id;
|
||||
pgw.ids[pgw.num_of_id].len = IPV4_LEN;
|
||||
pgw.ids[pgw.num_of_id].data = dns_primary.sub;
|
||||
pgw.num_of_id++;
|
||||
}
|
||||
|
||||
pgw.ids[pgw.num_of_id].id = ue.ids[i].id;
|
||||
pgw.ids[pgw.num_of_id].len = 4;
|
||||
pgw.ids[pgw.num_of_id].data = &pgw_self()->dns.secondary;
|
||||
if (pgw_self()->dns[1])
|
||||
{
|
||||
rv = core_ipsubnet(
|
||||
&dns_secondary, pgw_self()->dns[1], NULL);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
pgw.ids[pgw.num_of_id].id = ue.ids[i].id;
|
||||
pgw.ids[pgw.num_of_id].len = IPV4_LEN;
|
||||
pgw.ids[pgw.num_of_id].data = dns_secondary.sub;
|
||||
pgw.num_of_id++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PCO_ID_DNS_SERVER_IPV6_ADDRESS_REQUEST:
|
||||
{
|
||||
if (pgw_self()->dns6[0])
|
||||
{
|
||||
rv = core_ipsubnet(
|
||||
&dns6_primary, pgw_self()->dns6[0], NULL);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
pgw.ids[pgw.num_of_id].id = ue.ids[i].id;
|
||||
pgw.ids[pgw.num_of_id].len = IPV6_LEN;
|
||||
pgw.ids[pgw.num_of_id].data = dns6_primary.sub;
|
||||
pgw.num_of_id++;
|
||||
}
|
||||
|
||||
pgw.num_of_id++;
|
||||
if (pgw_self()->dns6[1])
|
||||
{
|
||||
rv = core_ipsubnet(
|
||||
&dns6_secondary, pgw_self()->dns6[1], NULL);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
pgw.ids[pgw.num_of_id].id = ue.ids[i].id;
|
||||
pgw.ids[pgw.num_of_id].len = IPV6_LEN;
|
||||
pgw.ids[pgw.num_of_id].data = dns6_secondary.sub;
|
||||
pgw.num_of_id++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PCO_ID_IP_ADDRESS_ALLOCATION_VIA_NAS_SIGNALLING:
|
||||
/* TODO */
|
||||
break;
|
||||
case PCO_ID_IPV4_LINK_MTU_REQUEST:
|
||||
/* TODO */
|
||||
break;
|
||||
default:
|
||||
d_warn("Unknown PCO ID:(0x%x)", ue.ids[i].id);
|
||||
|
|
|
@ -10,61 +10,30 @@ logger:
|
|||
others: 1
|
||||
|
||||
#
|
||||
# <IPv4>
|
||||
# parameter:
|
||||
#
|
||||
# o Disable use of IPv4 addresses (only IPv6)
|
||||
# Type : BOOLEAN
|
||||
#
|
||||
# o IPv4 enabled
|
||||
# parameter:
|
||||
#
|
||||
# o IPv4 disabled
|
||||
# parameter:
|
||||
# no_ipv4: true
|
||||
#
|
||||
#
|
||||
# <IPv6>
|
||||
#
|
||||
# o Disable use of IPv6 addresses (only IPv4)
|
||||
# Type : BOOLEAN
|
||||
#
|
||||
# o IPv6 enabled
|
||||
# parameter:
|
||||
#
|
||||
# o IPv6 disabled
|
||||
# parameter:
|
||||
# no_ipv6: true
|
||||
#
|
||||
#
|
||||
# <GTP Client Preference>
|
||||
#
|
||||
# o Prefer IPv4 instead of IPv6 for estabishing new GTP connections.
|
||||
# Type : BOOLEAN
|
||||
# Default : IPv6 is attempted first.
|
||||
#
|
||||
# o IPv6 preferred
|
||||
# parameter:
|
||||
#
|
||||
# o IPv4 preferred
|
||||
# parameter:
|
||||
# prefer_ipv4: true
|
||||
#
|
||||
#
|
||||
# <EPC elements>
|
||||
#
|
||||
# o Disable EPC elements (Only applicable `nextepc-epcd`)
|
||||
# Type : BOOLEAN
|
||||
#
|
||||
# o Enable HSS/SGW/PGW/PCRF
|
||||
# parameter:
|
||||
#
|
||||
# o Disable HSS/SGW/PGW/PCRF
|
||||
# parameter:
|
||||
# no_hss: true
|
||||
# no_sgw: true
|
||||
# no_pgw: true
|
||||
# no_pcrf: true
|
||||
#
|
||||
# o Enable Multicast traffic to the UE
|
||||
# multicast: true
|
||||
#
|
||||
# o Disable Stateless Address Autoconfiguration for IPv6
|
||||
# no_slaac: true
|
||||
#
|
||||
#
|
||||
parameter:
|
||||
|
||||
mme:
|
||||
|
@ -103,8 +72,6 @@ mme:
|
|||
# - addr: ::1
|
||||
#
|
||||
gtpc:
|
||||
- addr: 127.0.0.1
|
||||
- addr: ::1
|
||||
|
||||
#
|
||||
# <GUMMEI>
|
||||
|
@ -223,7 +190,6 @@ sgw:
|
|||
gtpc:
|
||||
addr:
|
||||
- 127.0.0.2
|
||||
- fe80::2%@LO_DEV@
|
||||
|
||||
#
|
||||
# <GTP-U Server>>
|
||||
|
@ -246,44 +212,49 @@ pgw:
|
|||
# o Only first node is attempted. others are ignored.
|
||||
# o if HSS provide PGW addresss(per-UE), it overwrites configuration.
|
||||
#
|
||||
# o Two PGW are defined. 127.0.0.3:2123 is attempted. [fe80::3%@LO_DEV@]:2123 is ignored.
|
||||
# o Two PGW are defined. 127.0.0.1:2123 is attempted. [::1]:2123 is ignored.
|
||||
# gtpc:
|
||||
# - addr: 127.0.0.3
|
||||
# - addr: fe80::3%@LO_DEV@
|
||||
# - addr: 127.0.0.1
|
||||
# - addr: ::1
|
||||
#
|
||||
# o One PGW is defined. if prefer_ipv4 is not true, [fe80::2%@LO_DEV@] is selected.
|
||||
# o One PGW is defined. if prefer_ipv4 is not true, [::1] is selected.
|
||||
# gtpc:
|
||||
# - addr:
|
||||
# - 127.0.0.3
|
||||
# - fe80::3%@LO_DEV@
|
||||
# - 127.0.0.1
|
||||
# - ::1
|
||||
#
|
||||
# ------------------------ PGW --------------------------
|
||||
#
|
||||
# o Specify local addresses the GTP-C server must bind to
|
||||
#
|
||||
# o GTP-C Server(127.0.0.3:2123, [fe80::3%@LO_DEV@]:2123)
|
||||
# o GTP-C Server(127.0.0.1:2123, [::1]:2123)
|
||||
# gtpc:
|
||||
# addr:
|
||||
# - 127.0.0.3
|
||||
# - fe80::3%@LO_DEV@
|
||||
# - 127.0.0.1
|
||||
# - ::1
|
||||
#
|
||||
# o Same configuration(127.0.0.1:2123, [::1]:2123) as below.
|
||||
# gtpc:
|
||||
# - addr: 127.0.0.1
|
||||
# - addr: ::1
|
||||
#
|
||||
gtpc:
|
||||
addr:
|
||||
- 127.0.0.3
|
||||
- fe80::3%@LO_DEV@
|
||||
- 127.0.0.1
|
||||
- ::1
|
||||
|
||||
#
|
||||
# <GTP-U Server>>
|
||||
#
|
||||
# o Specify local addresses the GTP-U server must bind to
|
||||
#
|
||||
# o GTP-U Server(127.0.0.3:2152, [::3]:2152)
|
||||
# o GTP-U Server(127.0.0.1:2152, [::1]:2152)
|
||||
# gtpu:
|
||||
# - addr: 127.0.0.3
|
||||
# - addr: fe80::3%@LO_DEV@
|
||||
# - addr: 127.0.0.1
|
||||
# - addr: ::1
|
||||
gtpu:
|
||||
- addr: 127.0.0.3
|
||||
- addr: fe80::3%@LO_DEV@
|
||||
- addr: 127.0.0.1
|
||||
- addr: ::1
|
||||
|
||||
#
|
||||
# <UE Pool>
|
||||
|
@ -330,7 +301,6 @@ pgw:
|
|||
dns:
|
||||
- 8.8.8.8
|
||||
- 8.8.4.4
|
||||
dns6:
|
||||
- 2001:4860:4860::8888
|
||||
- 2001:4860:4860::8844
|
||||
|
||||
|
|
|
@ -262,6 +262,6 @@ LoadExtension = "dict_s6a.so";
|
|||
# Examples:
|
||||
#ConnectPeer = "aaa.wide.ad.jp";
|
||||
#ConnectPeer = "old.diameter.serv" { TcTimer = 60; TLS_old_method; No_SCTP; Port=3868; } ;
|
||||
ConnectPeer = "mme.localdomain" { ConnectTo = "127.0.0.1"; No_TLS; };
|
||||
ConnectPeer = "mme.localdomain" { ConnectTo = "127.0.0.3"; No_TLS; };
|
||||
|
||||
##############################################################
|
||||
|
|
|
@ -80,7 +80,7 @@ No_SCTP;
|
|||
#ListenOn = "202.249.37.5";
|
||||
#ListenOn = "2001:200:903:2::202:1";
|
||||
#ListenOn = "fe80::21c:5ff:fe98:7d62%eth0";
|
||||
ListenOn = "127.0.0.1";
|
||||
ListenOn = "127.0.0.3";
|
||||
|
||||
|
||||
##############################################################
|
||||
|
|
|
@ -261,6 +261,6 @@ LoadExtension = "dict_dcca_3gpp.so";
|
|||
# Examples:
|
||||
#ConnectPeer = "aaa.wide.ad.jp";
|
||||
#ConnectPeer = "old.diameter.serv" { TcTimer = 60; TLS_old_method; No_SCTP; Port=3868; } ;
|
||||
ConnectPeer = "pgw.localdomain" { ConnectTo = "127.0.0.3"; No_TLS; };
|
||||
ConnectPeer = "pgw.localdomain" { ConnectTo = "127.0.0.1"; No_TLS; };
|
||||
|
||||
##############################################################
|
||||
|
|
|
@ -80,7 +80,7 @@ No_SCTP;
|
|||
#ListenOn = "202.249.37.5";
|
||||
#ListenOn = "2001:200:903:2::202:1";
|
||||
#ListenOn = "fe80::21c:5ff:fe98:7d62%eth0";
|
||||
ListenOn = "127.0.0.3";
|
||||
ListenOn = "127.0.0.1";
|
||||
|
||||
|
||||
##############################################################
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#!/bin/sh
|
||||
|
||||
SYSTEM=`uname`;
|
||||
|
||||
if [ "$SYSTEM" = "Linux" ]; then
|
||||
if ! grep "pgwtun" /proc/net/dev > /dev/null; then
|
||||
ip tuntap add name pgwtun mode tun
|
||||
fi
|
||||
ip addr del 45.45.0.1/16 dev pgwtun 2> /dev/null
|
||||
ip addr add 45.45.0.1/16 dev pgwtun
|
||||
ip addr del cafe::1/64 dev pgwtun 2> /dev/null
|
||||
ip addr add cafe::1/64 dev pgwtun
|
||||
ip link set pgwtun up
|
||||
ip addr del fe80::2 dev lo 2> /dev/null
|
||||
ip addr del fe80::3 dev lo 2> /dev/null
|
||||
ip addr del fe80::4 dev lo 2> /dev/null
|
||||
ip addr del fe80::5 dev lo 2> /dev/null
|
||||
ip addr add fe80::2 dev lo
|
||||
ip addr add fe80::3 dev lo
|
||||
ip addr add fe80::4 dev lo
|
||||
ip addr add fe80::5 dev lo
|
||||
else
|
||||
ifconfig lo0 alias 127.0.0.2 netmask 255.255.255.255
|
||||
ifconfig lo0 alias 127.0.0.3 netmask 255.255.255.255
|
||||
ifconfig lo0 alias 127.0.0.4 netmask 255.255.255.255
|
||||
ifconfig lo0 alias 127.0.0.5 netmask 255.255.255.255
|
||||
ifconfig lo0 inet6 delete fe80::2 prefixlen 128 2> /dev/null
|
||||
ifconfig lo0 inet6 delete fe80::3 prefixlen 128 2> /dev/null
|
||||
ifconfig lo0 inet6 delete fe80::4 prefixlen 128 2> /dev/null
|
||||
ifconfig lo0 inet6 delete fe80::5 prefixlen 128 2> /dev/null
|
||||
ifconfig lo0 inet6 add fe80::2 prefixlen 128
|
||||
ifconfig lo0 inet6 add fe80::3 prefixlen 128
|
||||
ifconfig lo0 inet6 add fe80::4 prefixlen 128
|
||||
ifconfig lo0 inet6 add fe80::5 prefixlen 128
|
||||
fi
|
|
@ -6,23 +6,14 @@ if [ "$SYSTEM" = "Linux" ]; then
|
|||
if ! grep "pgwtun" /proc/net/dev > /dev/null; then
|
||||
ip tuntap add name pgwtun mode tun
|
||||
fi
|
||||
ip addr add 45.45.0.1/16 dev pgwtun 2>/dev/null
|
||||
ip addr del 45.45.0.1/16 dev pgwtun 2> /dev/null
|
||||
ip addr add 45.45.0.1/16 dev pgwtun
|
||||
ip addr del cafe::1/64 dev pgwtun 2> /dev/null
|
||||
ip addr add cafe::1/64 dev pgwtun
|
||||
ip link set pgwtun up
|
||||
ip addr add fe80::2 dev lo 2> /dev/null
|
||||
ip addr add fe80::3 dev lo 2> /dev/null
|
||||
ip addr add fe80::4 dev lo 2> /dev/null
|
||||
ip addr add fe80::5 dev lo 2> /dev/null
|
||||
else
|
||||
ifconfig lo0 alias 127.0.0.2 netmask 255.255.255.255
|
||||
ifconfig lo0 alias 127.0.0.3 netmask 255.255.255.255
|
||||
ifconfig lo0 alias 127.0.0.4 netmask 255.255.255.255
|
||||
ifconfig lo0 alias 127.0.0.5 netmask 255.255.255.255
|
||||
ifconfig lo0 inet6 delete fe80::2 prefixlen 128 2> /dev/null
|
||||
ifconfig lo0 inet6 delete fe80::3 prefixlen 128 2> /dev/null
|
||||
ifconfig lo0 inet6 delete fe80::4 prefixlen 128 2> /dev/null
|
||||
ifconfig lo0 inet6 delete fe80::5 prefixlen 128 2> /dev/null
|
||||
ifconfig lo0 inet6 add fe80::2 prefixlen 128
|
||||
ifconfig lo0 inet6 add fe80::3 prefixlen 128
|
||||
ifconfig lo0 inet6 add fe80::4 prefixlen 128
|
||||
ifconfig lo0 inet6 add fe80::5 prefixlen 128
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
IPv6 Routing Daemon(radvd)
|
||||
===========================================
|
||||
- sudo apt-get install radvd
|
||||
- sudo cp support/radvd/radvd.conf.example /etc/radvd.conf
|
||||
- sudo systemctl start radvd
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#
|
||||
# NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
|
||||
# NOTE NOTE
|
||||
# NOTE This is an EXAMPLE, which serves only to demonstrate the NOTE
|
||||
# NOTE syntax of radvd.conf, and is not meant to be used for a NOTE
|
||||
# NOTE real radvd configuration. NOTE
|
||||
# NOTE NOTE
|
||||
# NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
|
||||
#
|
||||
|
||||
interface pgwtun
|
||||
{
|
||||
AdvSendAdvert on;
|
||||
|
||||
# This may be needed on some interfaces which are not active when
|
||||
# radvd starts, but become available later on; see man page for details.
|
||||
|
||||
# IgnoreIfMissing on;
|
||||
|
||||
#
|
||||
# These settings cause advertisements to be sent every 3-10 seconds. This
|
||||
# range is good for 6to4 with a dynamic IPv4 address, but can be greatly
|
||||
# increased when not using 6to4 prefixes.
|
||||
#
|
||||
|
||||
MinRtrAdvInterval 3;
|
||||
MaxRtrAdvInterval 10;
|
||||
|
||||
#
|
||||
# You can use AdvDefaultPreference setting to advertise the preference of
|
||||
# the router for the purposes of default router determination.
|
||||
# NOTE: This feature is still being specified and is not widely supported!
|
||||
#
|
||||
AdvDefaultPreference low;
|
||||
|
||||
#
|
||||
# Disable Mobile IPv6 support
|
||||
#
|
||||
AdvHomeAgentFlag off;
|
||||
|
||||
#
|
||||
# NextEPC pgwtun prefix
|
||||
#
|
||||
prefix cafe::/64
|
||||
{
|
||||
AdvOnLink on;
|
||||
AdvAutonomous on;
|
||||
AdvRouterAddr off;
|
||||
};
|
||||
};
|
||||
|
|
@ -33,6 +33,7 @@ AM_CPPFLAGS = \
|
|||
AM_CFLAGS = \
|
||||
-Wall -Werror \
|
||||
-Wno-unused-function -Wno-unused-variable \
|
||||
@OSCPPFLAGS@ \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
|
@ -72,7 +72,7 @@ static void attach_test1(abts_case *tc, void *data)
|
|||
"\"pre_emption_capability\" : 1"
|
||||
"} "
|
||||
"}, "
|
||||
"\"type\" : 0"
|
||||
"\"type\" : 2"
|
||||
"}"
|
||||
"],"
|
||||
"\"ambr\" : { "
|
||||
|
@ -112,7 +112,7 @@ static void attach_test1(abts_case *tc, void *data)
|
|||
"\"pre_emption_capability\" : 1"
|
||||
"} "
|
||||
"}, "
|
||||
"\"type\" : 0"
|
||||
"\"type\" : 2"
|
||||
"}"
|
||||
"],"
|
||||
"\"ambr\" : { "
|
||||
|
@ -302,7 +302,16 @@ static void attach_test1(abts_case *tc, void *data)
|
|||
core_sleep(time_from_msec(300));
|
||||
|
||||
/* Send GTP-U ICMP Packet */
|
||||
rv = testgtpu_enb_send(inet_addr("45.45.0.2"), inet_addr("45.45.0.1"));
|
||||
rv = testgtpu_enb_send("45.45.0.2", "45.45.0.1");
|
||||
|
||||
/* Receive GTP-U ICMP Packet */
|
||||
recvbuf = pkbuf_alloc(0, MAX_SDU_LEN);
|
||||
rv = testgtpu_enb_read(gtpu, recvbuf);
|
||||
ABTS_INT_EQUAL(tc, CORE_OK, rv);
|
||||
pkbuf_free(recvbuf);
|
||||
|
||||
#if LINUX == 1
|
||||
rv = testgtpu_enb_send("cafe::2", "cafe::1");
|
||||
ABTS_INT_EQUAL(tc, CORE_OK, rv);
|
||||
|
||||
/* Receive GTP-U ICMP Packet */
|
||||
|
@ -310,6 +319,7 @@ static void attach_test1(abts_case *tc, void *data)
|
|||
rv = testgtpu_enb_read(gtpu, recvbuf);
|
||||
ABTS_INT_EQUAL(tc, CORE_OK, rv);
|
||||
pkbuf_free(recvbuf);
|
||||
#endif
|
||||
|
||||
/*****************************************************************
|
||||
* Attach Request : Known GUTI, Integrity Protected, MAC Matched
|
||||
|
@ -476,7 +486,7 @@ static void attach_test2(abts_case *tc, void *data)
|
|||
"\"pre_emption_capability\" : 1"
|
||||
"} "
|
||||
"}, "
|
||||
"\"type\" : 0"
|
||||
"\"type\" : 2"
|
||||
"}"
|
||||
"],"
|
||||
"\"ambr\" : { "
|
||||
|
@ -759,7 +769,7 @@ static void attach_test3(abts_case *tc, void *data)
|
|||
"\"pre_emption_capability\" : 1"
|
||||
"} "
|
||||
"}, "
|
||||
"\"type\" : 0"
|
||||
"\"type\" : 2"
|
||||
"}"
|
||||
"],"
|
||||
"\"ambr\" : { "
|
||||
|
|
|
@ -45,7 +45,7 @@ static void handover_test1(abts_case *tc, void *data)
|
|||
"\"priority_level\" : 8,"
|
||||
"\"pre_emption_vulnerability\" : 1,"
|
||||
"\"pre_emption_capability\" : 1 } },"
|
||||
"\"type\" : 0 },"
|
||||
"\"type\" : 2 },"
|
||||
"{ \"apn\" : \"internet\","
|
||||
"\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2c\" },"
|
||||
"\"pcc_rule\" : ["
|
||||
|
@ -85,7 +85,7 @@ static void handover_test1(abts_case *tc, void *data)
|
|||
"\"priority_level\" : 1,"
|
||||
"\"pre_emption_vulnerability\" : 0,"
|
||||
"\"pre_emption_capability\" : 1 } },"
|
||||
"\"type\" : 0 }"
|
||||
"\"type\" : 2 }"
|
||||
"],"
|
||||
"\"ambr\" : {"
|
||||
"\"downlink\" : { \"$numberLong\" : \"1024000\" },"
|
||||
|
@ -366,7 +366,7 @@ static void handover_test2(abts_case *tc, void *data)
|
|||
"\"priority_level\" : 8,"
|
||||
"\"pre_emption_vulnerability\" : 1,"
|
||||
"\"pre_emption_capability\" : 1 } },"
|
||||
"\"type\" : 0 },"
|
||||
"\"type\" : 2 },"
|
||||
"{ \"apn\" : \"internet\","
|
||||
"\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2c\" },"
|
||||
"\"pcc_rule\" : ["
|
||||
|
@ -406,7 +406,7 @@ static void handover_test2(abts_case *tc, void *data)
|
|||
"\"priority_level\" : 1,"
|
||||
"\"pre_emption_vulnerability\" : 1,"
|
||||
"\"pre_emption_capability\" : 0 } },"
|
||||
"\"type\" : 0 }"
|
||||
"\"type\" : 2 }"
|
||||
"],"
|
||||
"\"ambr\" : {"
|
||||
"\"downlink\" : { \"$numberLong\" : \"202400\" },"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#define TRACE_MODULE _testpacket
|
||||
|
||||
#include "core_debug.h"
|
||||
#include "core_pkbuf.h"
|
||||
#include "core_lib.h"
|
||||
|
||||
#include "s1ap_build.h"
|
||||
|
@ -18,6 +17,50 @@
|
|||
|
||||
extern int test_only_control_plane;
|
||||
|
||||
#define TEST_ENB_ADDR "127.0.0.5"
|
||||
#if LINUX == 1
|
||||
#define TEST_ENB_ADDR6 "fe80::1%lo"
|
||||
#else
|
||||
#define TEST_ENB_ADDR6 "fe80::1%lo0"
|
||||
#endif
|
||||
static c_sockaddr_t *test_enb_addr = NULL;
|
||||
static c_sockaddr_t *test_enb_addr6 = NULL;
|
||||
|
||||
status_t testpacket_init()
|
||||
{
|
||||
status_t rv;
|
||||
|
||||
rv = core_getaddrinfo(&test_enb_addr,
|
||||
AF_INET, TEST_ENB_ADDR, GTPV1_U_UDP_PORT, 0);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
||||
/* There is no default link-local address,
|
||||
* If you want to test it, you need set the IPv6 address in some interface */
|
||||
#if LINUX != 1
|
||||
rv = core_getaddrinfo(&test_enb_addr6,
|
||||
AF_INET6, TEST_ENB_ADDR6, GTPV1_U_UDP_PORT, 0);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
#endif
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t testpacket_final()
|
||||
{
|
||||
if (test_enb_addr)
|
||||
{
|
||||
core_freeaddrinfo(test_enb_addr);
|
||||
test_enb_addr = NULL;
|
||||
}
|
||||
if (test_enb_addr6)
|
||||
{
|
||||
core_freeaddrinfo(test_enb_addr6);
|
||||
test_enb_addr6 = NULL;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t tests1ap_enb_connect(sock_id *new)
|
||||
{
|
||||
status_t rv;
|
||||
|
@ -52,34 +95,26 @@ status_t testgtpu_enb_connect(sock_id *new)
|
|||
{
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
status_t rv;
|
||||
mme_context_t *mme = mme_self();
|
||||
c_sockaddr_t addr;
|
||||
c_sockaddr_t *addr = NULL;
|
||||
int family = AF_UNSPEC;
|
||||
|
||||
if (test_only_control_plane) return CORE_OK;
|
||||
|
||||
d_assert(mme, return CORE_ERROR,);
|
||||
|
||||
family = AF_INET6;
|
||||
if (context_self()->parameter.no_ipv6) family = AF_INET;
|
||||
else if (context_self()->parameter.prefer_ipv4) family = AF_INET;
|
||||
else if (test_enb_addr6 == NULL) family = AF_INET;
|
||||
|
||||
rv = udp_socket(new, family);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
d_assert(mme->gtpc_addr, return CORE_ERROR,);
|
||||
memcpy(&addr, mme->gtpc_addr, sizeof(c_sockaddr_t));
|
||||
addr.c_sa_port = htons(GTPV1_U_UDP_PORT);
|
||||
}
|
||||
if (family == AF_INET) addr = test_enb_addr;
|
||||
else if (family == AF_INET6) addr = test_enb_addr6;
|
||||
else
|
||||
{
|
||||
d_assert(mme->gtpc_addr6, return CORE_ERROR,);
|
||||
memcpy(&addr, mme->gtpc_addr6, sizeof(c_sockaddr_t));
|
||||
addr.c_sa_port = htons(GTPV1_U_UDP_PORT);
|
||||
}
|
||||
rv = sock_bind(*new, &addr);
|
||||
d_assert(0, return CORE_ERROR,);
|
||||
|
||||
d_assert(addr, return CORE_ERROR,);
|
||||
rv = sock_bind(*new, addr);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
||||
return CORE_OK;
|
||||
|
@ -119,7 +154,7 @@ static uint16_t in_cksum(uint16_t *addr, int len)
|
|||
return answer;
|
||||
}
|
||||
|
||||
status_t testgtpu_enb_send(c_uint32_t src_ip, c_uint32_t dst_ip)
|
||||
status_t testgtpu_enb_send(const char *src_ip, const char *dst_ip)
|
||||
{
|
||||
sock_id sock = 0;
|
||||
hash_index_t *hi = NULL;
|
||||
|
@ -131,6 +166,7 @@ status_t testgtpu_enb_send(c_uint32_t src_ip, c_uint32_t dst_ip)
|
|||
pkbuf_t *pkbuf = NULL;
|
||||
gtp_header_t *gtp_h = NULL;
|
||||
ssize_t sent;
|
||||
ipsubnet_t src_ipsub, dst_ipsub;
|
||||
c_sockaddr_t sgw;
|
||||
struct ip *ip_h = NULL;
|
||||
struct icmp_header_t {
|
||||
|
@ -153,49 +189,145 @@ status_t testgtpu_enb_send(c_uint32_t src_ip, c_uint32_t dst_ip)
|
|||
} un;
|
||||
} *icmp_h = NULL;
|
||||
|
||||
struct ip6_hdr *ip6_h = NULL;
|
||||
struct icmp6_hdr
|
||||
{
|
||||
uint8_t icmp6_type; /* type field */
|
||||
uint8_t icmp6_code; /* code field */
|
||||
uint16_t icmp6_cksum; /* checksum field */
|
||||
union
|
||||
{
|
||||
uint32_t icmp6_un_data32[1]; /* type-specific field */
|
||||
#define icmp6_data16 icmp6_dataun.icmp6_un_data16
|
||||
#define icmp6_id icmp6_data16[0] /* echo request/reply */
|
||||
#define icmp6_seq icmp6_data16[1] /* echo request/reply */
|
||||
uint16_t icmp6_un_data16[2]; /* type-specific field */
|
||||
uint8_t icmp6_un_data8[4]; /* type-specific field */
|
||||
} icmp6_dataun;
|
||||
} *icmp6_h = NULL;
|
||||
|
||||
if (test_only_control_plane) return 0;
|
||||
|
||||
hi = mme_ue_first();
|
||||
if (!hi) return -1;
|
||||
mme_ue = mme_ue_this(hi);
|
||||
if (!mme_ue) return -1;
|
||||
sess = mme_sess_first(mme_ue);
|
||||
if (!sess) return -1;
|
||||
bearer = mme_bearer_first(sess);
|
||||
if (!bearer) return -1;
|
||||
d_assert(src_ip, return -1,);
|
||||
d_assert(dst_ip, return -1,);
|
||||
rv = core_ipsubnet(&src_ipsub, src_ip, NULL);
|
||||
d_assert(rv == CORE_OK, return -1,);
|
||||
rv = core_ipsubnet(&dst_ipsub, dst_ip, NULL);
|
||||
d_assert(rv == CORE_OK, return -1,);
|
||||
|
||||
pkbuf = pkbuf_alloc(0, 100 /* enough for ICMP; use smaller buffer */);
|
||||
hi = mme_ue_first();
|
||||
d_assert(hi, return -1,);
|
||||
mme_ue = mme_ue_this(hi);
|
||||
d_assert(mme_ue, return -1,);
|
||||
sess = mme_sess_first(mme_ue);
|
||||
d_assert(sess, return -1,);
|
||||
bearer = mme_bearer_first(sess);
|
||||
d_assert(bearer, return -1,);
|
||||
|
||||
pkbuf = pkbuf_alloc(0, 200 /* 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 = src_ip;
|
||||
ip_h->ip_dst.s_addr = dst_ip;
|
||||
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));
|
||||
if (dst_ipsub.family == AF_INET)
|
||||
{
|
||||
gtp_h->length = htons(sizeof(struct ip) + sizeof(struct icmp_header_t));
|
||||
|
||||
ip_h = (struct ip *)(pkbuf->payload + GTPV1U_HEADER_LEN);
|
||||
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 = src_ipsub.sub[0];
|
||||
ip_h->ip_dst.s_addr = dst_ipsub.sub[0];
|
||||
ip_h->ip_sum = in_cksum(
|
||||
(unsigned short *)ip_h, sizeof(struct ip));
|
||||
|
||||
icmp_h = (struct icmp_header_t *)
|
||||
(pkbuf->payload + GTPV1U_HEADER_LEN + 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));
|
||||
}
|
||||
else if (dst_ipsub.family == AF_INET6)
|
||||
{
|
||||
char cksumbuf[200];
|
||||
char *ptr = NULL;
|
||||
|
||||
int icmp6_datalen = 0;
|
||||
#if 0
|
||||
int icmp6_datalen = 56;
|
||||
char *icmp6_data = NULL;
|
||||
char hexbuf[200];
|
||||
char *hexraw =
|
||||
"9805325a 00000000 ea950900 00000000"
|
||||
"10111213 14151617 18191a1b 1c1d1e1f"
|
||||
"20212223 24252627 28292a2b 2c2d2e2f"
|
||||
"30313233 34353637";
|
||||
#endif
|
||||
|
||||
gtp_h->length = htons(sizeof(struct ip6_hdr) +
|
||||
sizeof(struct icmp6_hdr) + icmp6_datalen);
|
||||
|
||||
ip6_h = (struct ip6_hdr *)(pkbuf->payload + GTPV1U_HEADER_LEN);
|
||||
ip6_h->ip6_flow = htonl(0x600d5a92);
|
||||
ip6_h->ip6_plen = htons(sizeof(struct icmp6_hdr) + icmp6_datalen);
|
||||
ip6_h->ip6_nxt = 58; /* ICMPv6 */
|
||||
ip6_h->ip6_hlim = 64;
|
||||
memcpy(ip6_h->ip6_src.s6_addr, src_ipsub.sub, sizeof src_ipsub.sub);
|
||||
memcpy(ip6_h->ip6_dst.s6_addr, dst_ipsub.sub, sizeof dst_ipsub.sub);
|
||||
|
||||
icmp6_h =
|
||||
(struct icmp6_hdr *)((c_uint8_t*)ip6_h + sizeof(struct ip6_hdr));
|
||||
icmp6_h->icmp6_type = 128;
|
||||
icmp6_h->icmp6_code = 0;
|
||||
icmp6_h->icmp6_seq = rand();
|
||||
icmp6_h->icmp6_id = rand();
|
||||
|
||||
#if 0
|
||||
icmp6_data = (char *)((c_uint8_t*)icmp6_h + sizeof(struct icmp6_hdr));
|
||||
memcpy(icmp6_data,
|
||||
CORE_HEX(hexraw, strlen(hexraw), hexbuf), icmp6_datalen);
|
||||
#endif
|
||||
|
||||
/* create pseudo-header */
|
||||
memset(cksumbuf, 0, sizeof cksumbuf);
|
||||
ptr = cksumbuf;
|
||||
memcpy(ptr, src_ipsub.sub, sizeof src_ipsub.sub);
|
||||
ptr += sizeof src_ipsub.sub;
|
||||
memcpy(ptr, dst_ipsub.sub, sizeof dst_ipsub.sub);
|
||||
ptr += sizeof dst_ipsub.sub;
|
||||
|
||||
ptr += 2;
|
||||
memcpy(ptr, &ip6_h->ip6_plen, 2);
|
||||
ptr += 2;
|
||||
|
||||
ptr += 3;
|
||||
*ptr = ip6_h->ip6_nxt;
|
||||
ptr += 1;
|
||||
|
||||
memcpy(ptr, icmp6_h, sizeof(struct icmp6_hdr));
|
||||
#if 0
|
||||
ptr += sizeof(struct icmp6_hdr);
|
||||
memcpy(ptr, icmp6_data, icmp6_datalen);
|
||||
#endif
|
||||
|
||||
#define IPV6_PSEUDO_HDR 48
|
||||
icmp6_h->icmp6_cksum = in_cksum((unsigned short *)cksumbuf,
|
||||
IPV6_PSEUDO_HDR + sizeof(struct icmp6_hdr) + icmp6_datalen);
|
||||
}
|
||||
else
|
||||
d_assert(0, return -1,);
|
||||
|
||||
memset(&sgw, 0, sizeof(c_sockaddr_t));
|
||||
sgw.c_sa_port = htons(GTPV1_U_UDP_PORT);
|
||||
|
@ -318,7 +450,7 @@ status_t tests1ap_build_initial_ue_msg(pkbuf_t **pkbuf, int i)
|
|||
{
|
||||
char *payload[TESTS1AP_MAX_MESSAGE] = {
|
||||
"000c405800000500 0800020001001a00 302f177ca0b38802 0741020809101010"
|
||||
"3254869104e060c0 4000050221d011d1 5c0a003103e5e034 9011035758a65d01"
|
||||
"3254869104e060c0 4000050221d031d1 5c0a003103e5e034 9011035758a65d01"
|
||||
"00004300060000f1 1030390064400800 00f1101079baf000 86400130",
|
||||
|
||||
"000c40809c00"
|
||||
|
@ -732,8 +864,7 @@ status_t tests1ap_build_initial_context_setup_response(
|
|||
core_calloc(1, sizeof(S1ap_E_RABSetupItemCtxtSURes_t));
|
||||
e_rab->e_RAB_ID = ebi;
|
||||
|
||||
rv = gtp_sockaddr_to_f_teid(
|
||||
mme_self()->gtpc_addr, mme_self()->gtpc_addr6, &f_teid, &len);
|
||||
rv = gtp_sockaddr_to_f_teid(test_enb_addr, test_enb_addr6, &f_teid, &len);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
rv = gtp_f_teid_to_ip(&f_teid, &ip);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
@ -1174,9 +1305,8 @@ status_t tests1ap_build_e_rab_setup_response(
|
|||
e_rab = (S1ap_E_RABSetupItemBearerSURes_t *)
|
||||
core_calloc(1, sizeof(S1ap_E_RABSetupItemBearerSURes_t));
|
||||
e_rab->e_RAB_ID = ebi;
|
||||
|
||||
rv = gtp_sockaddr_to_f_teid(
|
||||
mme_self()->gtpc_addr, mme_self()->gtpc_addr6, &f_teid, &len);
|
||||
|
||||
rv = gtp_sockaddr_to_f_teid(test_enb_addr, test_enb_addr6, &f_teid, &len);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
rv = gtp_f_teid_to_ip(&f_teid, &ip);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
@ -1426,7 +1556,7 @@ status_t tests1ap_build_path_switch_request(
|
|||
e_rab->e_RAB_ID = ebi+i;
|
||||
|
||||
rv = gtp_sockaddr_to_f_teid(
|
||||
mme_self()->gtpc_addr, mme_self()->gtpc_addr6, &f_teid, &len);
|
||||
test_enb_addr, test_enb_addr6, &f_teid, &len);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
rv = gtp_f_teid_to_ip(&f_teid, &ip);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
@ -1597,7 +1727,7 @@ CORE_DECLARE(status_t) tests1ap_build_handover_request_ack(
|
|||
e_rab->e_RAB_ID = ebi+i;
|
||||
|
||||
rv = gtp_sockaddr_to_f_teid(
|
||||
mme_self()->gtpc_addr, mme_self()->gtpc_addr6, &f_teid, &len);
|
||||
test_enb_addr, test_enb_addr6, &f_teid, &len);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
rv = gtp_f_teid_to_ip(&f_teid, &ip);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
||||
|
|
|
@ -2,11 +2,17 @@
|
|||
#define __TESTS1AP_H__
|
||||
|
||||
#include "core_network.h"
|
||||
#include "core_pkbuf.h"
|
||||
|
||||
#include "s1ap_message.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
CORE_DECLARE(status_t) testpacket_init();
|
||||
CORE_DECLARE(status_t) testpacket_final();
|
||||
|
||||
CORE_DECLARE(status_t) tests1ap_enb_connect(sock_id *new);
|
||||
CORE_DECLARE(status_t) tests1ap_enb_close(sock_id id);
|
||||
CORE_DECLARE(status_t) tests1ap_enb_send(sock_id id, pkbuf_t *sendbuf);
|
||||
|
@ -15,7 +21,8 @@ CORE_DECLARE(status_t) tests1ap_enb_read(sock_id id, pkbuf_t *recvbuf);
|
|||
CORE_DECLARE(status_t) testgtpu_enb_connect(sock_id *new);
|
||||
CORE_DECLARE(status_t) testgtpu_enb_close(sock_id sock);
|
||||
CORE_DECLARE(status_t) testgtpu_enb_read(sock_id sock, pkbuf_t *recvbuf);
|
||||
CORE_DECLARE(status_t) testgtpu_enb_send(c_uint32_t src_ip, c_uint32_t dst_ip);
|
||||
CORE_DECLARE(status_t) testgtpu_enb_send(
|
||||
const char *src_ip, const char *dst_ip);
|
||||
|
||||
CORE_DECLARE(status_t) tests1ap_build_setup_req(
|
||||
pkbuf_t **pkbuf, S1ap_ENB_ID_PR present, c_uint32_t enb_id);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "app.h"
|
||||
#include "context.h"
|
||||
#include "mme_context.h"
|
||||
#include "testpacket.h"
|
||||
#include "abts.h"
|
||||
#include "testutil.h"
|
||||
|
||||
|
@ -40,6 +40,7 @@ void test_terminate(void)
|
|||
{
|
||||
d_trace_global_on();
|
||||
|
||||
testpacket_final();
|
||||
app_terminate();
|
||||
core_terminate();
|
||||
}
|
||||
|
@ -54,6 +55,7 @@ status_t test_initialize(char *config_path)
|
|||
|
||||
core_initialize();
|
||||
rv = app_initialize(config_path, NULL);
|
||||
testpacket_init();
|
||||
if (rv == CORE_OK)
|
||||
{
|
||||
while(1)
|
||||
|
|
|
@ -38,7 +38,7 @@ static void volte_test1(abts_case *tc, void *data)
|
|||
"\"priority_level\" : 8,"
|
||||
"\"pre_emption_vulnerability\" : 1,"
|
||||
"\"pre_emption_capability\" : 1 } },"
|
||||
"\"type\" : 0 },"
|
||||
"\"type\" : 2 },"
|
||||
"{ \"apn\" : \"internet.ng2.mnet\","
|
||||
"\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2c\" },"
|
||||
"\"pcc_rule\" : ["
|
||||
|
@ -78,7 +78,7 @@ static void volte_test1(abts_case *tc, void *data)
|
|||
"\"priority_level\" : 6,"
|
||||
"\"pre_emption_vulnerability\" : 1,"
|
||||
"\"pre_emption_capability\" : 1 } },"
|
||||
"\"type\" : 0 }"
|
||||
"\"type\" : 2 }"
|
||||
"],"
|
||||
"\"ambr\" : {"
|
||||
"\"downlink\" : { \"$numberLong\" : \"1024000\" },"
|
||||
|
@ -349,7 +349,7 @@ static void volte_test2(abts_case *tc, void *data)
|
|||
"\"priority_level\" : 8,"
|
||||
"\"pre_emption_vulnerability\" : 1,"
|
||||
"\"pre_emption_capability\" : 1 } },"
|
||||
"\"type\" : 0 },"
|
||||
"\"type\" : 2 },"
|
||||
"{ \"apn\" : \"internet\","
|
||||
"\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2c\" },"
|
||||
"\"pcc_rule\" : ["
|
||||
|
@ -371,13 +371,13 @@ static void volte_test2(abts_case *tc, void *data)
|
|||
"\"description\" : \"permit out udp from any 1-65535 to 10.200.136.98/32 23454\","
|
||||
"\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } },"
|
||||
"{ \"direction\" : 1,"
|
||||
"\"description\" : \"permit out udp from any 50020 to 10.200.136.98/32 1-65535\","
|
||||
"\"description\" : \"permit out ip from 45.45.0.1 to any\","
|
||||
"\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } },"
|
||||
"{ \"direction\" : 2,"
|
||||
"\"description\" : \"permit out udp from any 1-65535 to 10.200.136.98/32 23455\","
|
||||
"\"description\" : \"permit out udp from any 1-65535 to 10.200.136.98/24 23455\","
|
||||
"\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } },"
|
||||
"{ \"direction\" : 1,"
|
||||
"\"description\" : \"permit out udp from any 50021 to 10.200.136.98/32 1-65535\","
|
||||
"\"description\" : \"permit out ip from cafe::1 to any\","
|
||||
"\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } } ]"
|
||||
"} ],"
|
||||
"\"ambr\" : {"
|
||||
|
@ -389,7 +389,7 @@ static void volte_test2(abts_case *tc, void *data)
|
|||
"\"priority_level\" : 6,"
|
||||
"\"pre_emption_vulnerability\" : 1,"
|
||||
"\"pre_emption_capability\" : 1 } },"
|
||||
"\"type\" : 0 }"
|
||||
"\"type\" : 2 }"
|
||||
"],"
|
||||
"\"ambr\" : {"
|
||||
"\"downlink\" : { \"$numberLong\" : \"1024000\" },"
|
||||
|
@ -547,6 +547,19 @@ static void volte_test2(abts_case *tc, void *data)
|
|||
rv = tests1ap_enb_send(sock, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, CORE_OK, rv);
|
||||
|
||||
#if 0 /* TFT Rule Tester */
|
||||
core_sleep(time_from_msec(300));
|
||||
|
||||
/* Send GTP-U ICMP Packet */
|
||||
#if 1
|
||||
rv = testgtpu_enb_send("45.45.0.2", "45.45.0.1");
|
||||
#else
|
||||
rv = testgtpu_enb_send("cafe::2", "cafe::1");
|
||||
#endif
|
||||
|
||||
core_sleep(time_from_msec(300));
|
||||
#endif
|
||||
|
||||
/********** Remove Subscriber in Database */
|
||||
doc = BCON_NEW("imsi", BCON_UTF8("001010123456819"));
|
||||
ABTS_PTR_NOTNULL(tc, doc);
|
||||
|
@ -567,7 +580,9 @@ abts_suite *test_volte(abts_suite *suite)
|
|||
{
|
||||
suite = ADD_SUITE(suite)
|
||||
|
||||
#if 0
|
||||
abts_run_test(suite, volte_test1, NULL);
|
||||
#endif
|
||||
abts_run_test(suite, volte_test2, NULL);
|
||||
|
||||
return suite;
|
||||
|
|
|
@ -20,7 +20,7 @@ const Profile = new Schema({
|
|||
pdn: [{
|
||||
apn: { $type: String, required: true },
|
||||
type: {
|
||||
$type: Number, default: 0 // IPv4
|
||||
$type: Number, default: 2 // IPv4, IPv6 and dualstack IPv4v6
|
||||
},
|
||||
qos: {
|
||||
qci: Number,
|
||||
|
@ -39,7 +39,8 @@ const Profile = new Schema({
|
|||
uplink: Schema.Types.Long
|
||||
},
|
||||
pgw: {
|
||||
ipv4: String
|
||||
addr: String,
|
||||
addr6: String
|
||||
},
|
||||
pcc_rule: [{
|
||||
flow: [{
|
||||
|
|
|
@ -40,7 +40,7 @@ const Subscriber = new Schema({
|
|||
pdn: [{
|
||||
apn: { $type: String, required: true },
|
||||
type: {
|
||||
$type: Number, default: 0 // IPv4
|
||||
$type: Number, default: 2 // IPv4, IPv6 and dualstack IPv4v6
|
||||
},
|
||||
qos: {
|
||||
qci: Number,
|
||||
|
@ -59,7 +59,8 @@ const Subscriber = new Schema({
|
|||
uplink: Schema.Types.Long
|
||||
},
|
||||
pgw: {
|
||||
ipv4: String
|
||||
addr: String,
|
||||
addr6: String
|
||||
},
|
||||
pcc_rule: [{
|
||||
flow: [{
|
||||
|
|
|
@ -145,11 +145,16 @@ const schema = {
|
|||
"type": "object",
|
||||
"title": "",
|
||||
"properties": {
|
||||
"ipv4": {
|
||||
"addr": {
|
||||
"type": "string",
|
||||
"title": "PGW IPv4 Address",
|
||||
"format" : "ipv4"
|
||||
},
|
||||
"addr6": {
|
||||
"type": "string",
|
||||
"title": "PGW IPv6 Address",
|
||||
"format" : "ipv6"
|
||||
},
|
||||
}
|
||||
},
|
||||
"pcc_rule": {
|
||||
|
@ -329,6 +334,14 @@ const uiSchema = {
|
|||
classNames: "col-xs-6"
|
||||
},
|
||||
},
|
||||
"pgw" : {
|
||||
"addr" : {
|
||||
classNames: "col-xs-6"
|
||||
},
|
||||
"addr6" : {
|
||||
classNames: "col-xs-6"
|
||||
},
|
||||
},
|
||||
"pcc_rule": {
|
||||
"items": {
|
||||
"flow": {
|
||||
|
|
|
@ -142,7 +142,7 @@ const Pdn = styled.div`
|
|||
margin: 0px 32px;
|
||||
|
||||
.small_data {
|
||||
width: 60px;
|
||||
width: 50px;
|
||||
font-size: 12px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
@ -279,7 +279,8 @@ const View = ({ visible, disableOnClickOutside, profile, onEdit, onDelete, onHid
|
|||
</div>
|
||||
}
|
||||
<div className="large_data"></div>
|
||||
<div className="small_data">{(pdn.pgw || {}).ipv4}</div>
|
||||
<div className="small_data">{(pdn.pgw || {}).addr}</div>
|
||||
<div className="small_data">{(pdn.pgw || {}).addr6}</div>
|
||||
</div>
|
||||
{pdn['pcc_rule'] !== undefined &&
|
||||
pdn.pcc_rule.map((pcc_rule, index) =>
|
||||
|
|
|
@ -151,11 +151,16 @@ const schema = {
|
|||
"type": "object",
|
||||
"title": "",
|
||||
"properties": {
|
||||
"ipv4": {
|
||||
"addr": {
|
||||
"type": "string",
|
||||
"title": "PGW IPv4 Address",
|
||||
"format" : "ipv4"
|
||||
},
|
||||
"addr6": {
|
||||
"type": "string",
|
||||
"title": "PGW IPv6 Address",
|
||||
"format" : "ipv6"
|
||||
},
|
||||
}
|
||||
},
|
||||
"pcc_rule": {
|
||||
|
@ -335,6 +340,14 @@ const uiSchema = {
|
|||
classNames: "col-xs-6"
|
||||
},
|
||||
},
|
||||
"pgw" : {
|
||||
"addr" : {
|
||||
classNames: "col-xs-6"
|
||||
},
|
||||
"addr6" : {
|
||||
classNames: "col-xs-6"
|
||||
},
|
||||
},
|
||||
"pcc_rule": {
|
||||
"items": {
|
||||
"flow": {
|
||||
|
|
|
@ -142,7 +142,7 @@ const Pdn = styled.div`
|
|||
margin: 0px 32px;
|
||||
|
||||
.small_data {
|
||||
width: 60px;
|
||||
width: 50px;
|
||||
font-size: 12px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
@ -278,7 +278,8 @@ const View = ({ visible, disableOnClickOutside, subscriber, onEdit, onDelete, on
|
|||
</div>
|
||||
}
|
||||
<div className="large_data"></div>
|
||||
<div className="small_data">{(pdn.pgw || {}).ipv4}</div>
|
||||
<div className="small_data">{(pdn.pgw || {}).addr}</div>
|
||||
<div className="small_data">{(pdn.pgw || {}).addr6}</div>
|
||||
</div>
|
||||
{pdn['pcc_rule'] !== undefined &&
|
||||
pdn.pcc_rule.map((pcc_rule, index) =>
|
||||
|
@ -336,4 +337,4 @@ const View = ({ visible, disableOnClickOutside, subscriber, onEdit, onDelete, on
|
|||
)
|
||||
}
|
||||
|
||||
export default View;
|
||||
export default View;
|
||||
|
|
Loading…
Reference in New Issue