Merge branch 'ipv6' of https://github.com/acetcom/nextepc into ipv6

This commit is contained in:
Sukchan Lee 2017-12-16 23:22:56 +09:00
commit 7ea5f3d910
47 changed files with 1385 additions and 608 deletions

View File

@ -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>

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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 +

View File

@ -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;

View File

@ -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

View File

@ -245,6 +245,16 @@ status_t context_parse_config()
self.parameter.prefer_ipv4 =
yaml_iter_bool(&parameter_iter);
}
else if (!strcmp(parameter_key, "multicast"))
{
self.parameter.multicast =
yaml_iter_bool(&parameter_iter);
}
else if (!strcmp(parameter_key, "no_slaac"))
{
self.parameter.no_slaac =
yaml_iter_bool(&parameter_iter);
}
else
d_warn("unknown key `%s`", parameter_key);
}

View File

@ -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;

View File

@ -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));
}
}
}
}

View File

@ -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) );

View File

@ -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)
{

View File

@ -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)

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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);
}

View File

@ -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
}

View File

@ -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),

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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; };
##############################################################

View File

@ -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";
##############################################################

View File

@ -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; };
##############################################################

View File

@ -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";
##############################################################

35
support/network/ipv6_restart.sh Executable file
View File

@ -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

View File

@ -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

6
support/radvd/README.md Normal file
View File

@ -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

View File

@ -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;
};
};

View File

@ -33,6 +33,7 @@ AM_CPPFLAGS = \
AM_CFLAGS = \
-Wall -Werror \
-Wno-unused-function -Wno-unused-variable \
@OSCPPFLAGS@ \
$(NULL)
MAINTAINERCLEANFILES = Makefile.in

View File

@ -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\" : { "

View File

@ -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\" },"

View File

@ -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,);

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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: [{

View File

@ -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: [{

View File

@ -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": {

View File

@ -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) =>

View File

@ -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": {

View File

@ -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;